Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: setting for more flexible town spacing #7745

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/core/math_func.hpp
Expand Up @@ -365,4 +365,18 @@ static inline int DivAwayFromZero(int a, uint b)

uint32 IntSqrt(uint32 num);

/**
* Computes the smallest nonnegative number r with a = q*b + r.
* (remainder of integer division with rounding towards -infinity)
* We can't rely on % giving sane results for negative a.
* @param a Numerator
* @param b Denominator
* @return Remainder
*/
static inline uint Mod(int a, uint b)
{
if (a >= 0) return ((uint)a)%b;
return b-(((uint)(-a-1))%b)-1;
}

#endif /* MATH_FUNC_HPP */
2 changes: 1 addition & 1 deletion src/genworld.cpp
Expand Up @@ -137,7 +137,7 @@ static void _GenerateWorld()

/* only generate towns, tree and industries in newgame mode. */
if (_game_mode != GM_EDITOR) {
if (!GenerateTowns(_settings_game.economy.town_layout)) {
if (!GenerateTowns(_settings_game.economy.town_layout, TS_RANDOM)) {
_cur_company.Restore();
HandleGeneratingWorldAbortion();
return;
Expand Down
8 changes: 4 additions & 4 deletions src/lang/english.txt
Expand Up @@ -1580,11 +1580,11 @@ STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :All

STR_CONFIG_SETTING_TOWN_LAYOUT :Road layout for new towns: {STRING2}
STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :Layout for the road network of towns
STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :Original
STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :Better roads
STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 grid
STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 grid
STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :natural
STR_CONFIG_SETTING_TOWN_LAYOUT_GRID :grid
STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :Random
STR_CONFIG_SETTING_MIN_TOWN_SPACING :Smallest minimum distance beetween parallel roads: {STRING2}
STR_CONFIG_SETTING_MAX_TOWN_SPACING :Largest minimum distance beetween parallel roads: {STRING2}
STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Towns are allowed to build roads: {STRING2}
STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Allow towns to build roads for growth. Disable to prevent town authorities from building roads themselves
STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Towns are allowed to build level crossings: {STRING2}
Expand Down
28 changes: 27 additions & 1 deletion src/saveload/afterload.cpp
Expand Up @@ -2155,7 +2155,7 @@ bool AfterLoadGame()
/* allow_town_roads is added, set it if town_layout wasn't TL_NO_ROADS */
if (_settings_game.economy.town_layout == 0) { // was TL_NO_ROADS
_settings_game.economy.allow_town_roads = false;
_settings_game.economy.town_layout = TL_BETTER_ROADS;
_settings_game.economy.town_layout = TL_NATURAL;
} else {
_settings_game.economy.allow_town_roads = true;
_settings_game.economy.town_layout = static_cast<TownLayout>(_settings_game.economy.town_layout - 1);
Expand Down Expand Up @@ -3207,6 +3207,32 @@ bool AfterLoadGame()
FOR_ALL_STATIONS(st) UpdateStationAcceptance(st, false);
}

if (IsSavegameVersionBefore(SLV_TOWN_SPACING)) {
/* Town spacing parameter has been added */
Town *t;
FOR_ALL_TOWNS(t) {
switch (t->layout) {
default: NOT_REACHED();
case 0: /* TL_ORIGINAL */
t->layout = TL_NATURAL;
t->spacing = 1;
break;
case 1: /* TL_BETTER_ROADS */
t->layout = TL_NATURAL;
t->spacing = 2;
break;
case 2: /* TL_2x2_GRID */
t->layout = TL_GRID;
t->spacing = 2;
break;
case 3: /* TL_3x3_GRID */
t->layout = TL_GRID;
t->spacing = 3;
break;
}
}
}

/* Road stops is 'only' updating some caches */
AfterLoadRoadStops();
AfterLoadLabelMaps();
Expand Down
2 changes: 2 additions & 0 deletions src/saveload/saveload.h
Expand Up @@ -303,6 +303,8 @@ enum SaveLoadVersion : uint16 {
SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption.
SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station.

SLV_TOWN_SPACING,

SL_MAX_VERSION, ///< Highest possible saveload version
};

Expand Down
6 changes: 2 additions & 4 deletions src/script/api/ai/ai_town.hpp.sq
Expand Up @@ -39,10 +39,8 @@ void SQAITown_Register(Squirrel *engine)
SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_EXCELLENT, "TOWN_RATING_EXCELLENT");
SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_OUTSTANDING, "TOWN_RATING_OUTSTANDING");
SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_INVALID, "TOWN_RATING_INVALID");
SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_ORIGINAL, "ROAD_LAYOUT_ORIGINAL");
SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_BETTER_ROADS, "ROAD_LAYOUT_BETTER_ROADS");
SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_2x2, "ROAD_LAYOUT_2x2");
SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_3x3, "ROAD_LAYOUT_3x3");
SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_NATURAL, "ROAD_LAYOUT_NATURAL");
SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_GRID, "ROAD_LAYOUT_GRID");
SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_INVALID, "ROAD_LAYOUT_INVALID");
SQAITown.DefSQConst(engine, ScriptTown::TOWN_SIZE_SMALL, "TOWN_SIZE_SMALL");
SQAITown.DefSQConst(engine, ScriptTown::TOWN_SIZE_MEDIUM, "TOWN_SIZE_MEDIUM");
Expand Down
6 changes: 2 additions & 4 deletions src/script/api/game/game_town.hpp.sq
Expand Up @@ -39,10 +39,8 @@ void SQGSTown_Register(Squirrel *engine)
SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_EXCELLENT, "TOWN_RATING_EXCELLENT");
SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_OUTSTANDING, "TOWN_RATING_OUTSTANDING");
SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_INVALID, "TOWN_RATING_INVALID");
SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_ORIGINAL, "ROAD_LAYOUT_ORIGINAL");
SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_BETTER_ROADS, "ROAD_LAYOUT_BETTER_ROADS");
SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_2x2, "ROAD_LAYOUT_2x2");
SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_3x3, "ROAD_LAYOUT_3x3");
SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_NATURAL, "ROAD_LAYOUT_NATURAL");
SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_GRID, "ROAD_LAYOUT_GRID");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps needs some compat.nut stuff for Squirrel, to allow creating and querying towns with the old interface.

SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_INVALID, "ROAD_LAYOUT_INVALID");
SQGSTown.DefSQConst(engine, ScriptTown::TOWN_SIZE_SMALL, "TOWN_SIZE_SMALL");
SQGSTown.DefSQConst(engine, ScriptTown::TOWN_SIZE_MEDIUM, "TOWN_SIZE_MEDIUM");
Expand Down
2 changes: 1 addition & 1 deletion src/script/api/script_town.cpp
Expand Up @@ -287,7 +287,7 @@
EnforcePrecondition(false, size == TOWN_SIZE_SMALL || size == TOWN_SIZE_MEDIUM || size == TOWN_SIZE_LARGE)
EnforcePrecondition(false, size != TOWN_SIZE_LARGE || ScriptObject::GetCompany() == OWNER_DEITY);
if (ScriptObject::GetCompany() == OWNER_DEITY || _settings_game.economy.found_town == TF_CUSTOM_LAYOUT) {
EnforcePrecondition(false, layout == ROAD_LAYOUT_ORIGINAL || layout == ROAD_LAYOUT_BETTER_ROADS || layout == ROAD_LAYOUT_2x2 || layout == ROAD_LAYOUT_3x3);
EnforcePrecondition(false, layout == ROAD_LAYOUT_NATURAL || layout == ROAD_LAYOUT_GRID);
} else {
/* The layout parameter is ignored for AIs when custom layouts is disabled. */
layout = (RoadLayout) (byte)_settings_game.economy.town_layout;
Expand Down
6 changes: 2 additions & 4 deletions src/script/api/script_town.hpp
Expand Up @@ -96,10 +96,8 @@ class ScriptTown : public ScriptObject {
*/
enum RoadLayout {
/* Note: these values represent part of the in-game TownLayout enum */
ROAD_LAYOUT_ORIGINAL = ::TL_ORIGINAL, ///< Original algorithm (min. 1 distance between roads).
ROAD_LAYOUT_BETTER_ROADS = ::TL_BETTER_ROADS, ///< Extended original algorithm (min. 2 distance between roads).
ROAD_LAYOUT_2x2 = ::TL_2X2_GRID, ///< Geometric 2x2 grid algorithm
ROAD_LAYOUT_3x3 = ::TL_3X3_GRID, ///< Geometric 3x3 grid algorithm
ROAD_LAYOUT_NATURAL = ::TL_NATURAL, ///TODO: compatibility
ROAD_LAYOUT_GRID = ::TL_GRID,

/* Custom added value, only valid for this API */
ROAD_LAYOUT_INVALID = -1, ///< The layout for invalid towns.
Expand Down
2 changes: 2 additions & 0 deletions src/settings_gui.cpp
Expand Up @@ -1698,6 +1698,8 @@ static SettingsContainer &GetSettingsTree()
genworld->Add(new SettingEntry("economy.larger_towns"));
genworld->Add(new SettingEntry("economy.initial_city_size"));
genworld->Add(new SettingEntry("economy.town_layout"));
genworld->Add(new SettingEntry("economy.town_min_spacing"));
genworld->Add(new SettingEntry("economy.town_max_spacing"));
genworld->Add(new SettingEntry("difficulty.industry_density"));
genworld->Add(new SettingEntry("gui.pause_on_newgame"));
}
Expand Down
2 changes: 2 additions & 0 deletions src/settings_type.h
Expand Up @@ -484,6 +484,8 @@ struct EconomySettings {
uint8 larger_towns; ///< the number of cities to build. These start off larger and grow twice as fast
uint8 initial_city_size; ///< multiplier for the initial size of the cities compared to towns
TownLayout town_layout; ///< select town layout, @see TownLayout
TownSpacing town_min_spacing; ///< smallest minimal distance between parallel roads for towns
TownSpacing town_max_spacing; ///< largest minimal distance between parallel roads for towns
TownCargoGenMode town_cargogen_mode; ///< algorithm for generating cargo from houses, @see TownCargoGenMode
bool allow_town_roads; ///< towns are allowed to build roads (always allowed when generating world / in SE)
TownFounding found_town; ///< town founding.
Expand Down
27 changes: 26 additions & 1 deletion src/table/settings.ini
Expand Up @@ -574,7 +574,7 @@ var = economy.town_layout
type = SLE_UINT8
from = SLV_59
guiflags = SGF_MULTISTRING
def = TL_ORIGINAL
def = TL_NATURAL
min = TL_BEGIN
max = NUM_TLS - 1
interval = 1
Expand All @@ -583,6 +583,31 @@ strhelp = STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT
strval = STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT
proc = TownFoundingChanged

[SDT_VAR]
base = GameSettings
var = economy.town_min_spacing
type = SLE_UINT8
from = SLV_TOWN_SPACING
def = 2
min = 1
max = MAX_TOWN_SPACING
interval = 1
str = STR_CONFIG_SETTING_MIN_TOWN_SPACING
strval = STR_JUST_COMMA

[SDT_VAR]
base = GameSettings
var = economy.town_max_spacing
type = SLE_UINT8
from = SLV_TOWN_SPACING
def = 2
min = 1
max = MAX_TOWN_SPACING
interval = 1
str = STR_CONFIG_SETTING_MAX_TOWN_SPACING
strval = STR_JUST_COMMA
#proc = check max >= min

[SDT_BOOL]
base = GameSettings
var = economy.allow_town_roads
Expand Down
5 changes: 3 additions & 2 deletions src/town.h
Expand Up @@ -100,6 +100,7 @@ struct Town : TownPool::PoolItem<&_town_pool> {

bool larger_town; ///< if this is a larger town and should grow more quickly
TownLayout layout; ///< town specific road layout
TownSpacing spacing; ///< minimum distance between parallel roads

bool show_zone; ///< NOSAVE: mark town to show the local authority zone in the viewports

Expand All @@ -114,7 +115,7 @@ struct Town : TownPool::PoolItem<&_town_pool> {
/** Destroy the town. */
~Town();

void InitializeLayout(TownLayout layout);
void InitializeLayout(TownLayout layout, TownSpacing spacing);

/**
* Calculate the max town noise.
Expand Down Expand Up @@ -204,7 +205,7 @@ void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags);
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile);
void SetTownRatingTestMode(bool mode);
uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t);
bool GenerateTowns(TownLayout layout);
bool GenerateTowns(TownLayout layout, TownSpacing spacing);
const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect);

/** Town actions of a company. */
Expand Down