diff -r 322f2f20c99a src/script/api/script_town.cpp --- a/src/script/api/script_town.cpp Tue Sep 01 22:52:41 2015 +0300 +++ b/src/script/api/script_town.cpp Wed Oct 14 00:31:27 2015 +0300 @@ -160,23 +160,24 @@ { EnforcePrecondition(false, IsValidTown(town_id)); + uint16 growth_rate; switch (days_between_town_growth) { - case TOWN_GROWTH_NORMAL: - days_between_town_growth = 0; - break; - - case TOWN_GROWTH_NONE: - days_between_town_growth = TOWN_GROW_RATE_CUSTOM_NONE; + case TOWN_GROW_RATE_NORMAL: + case TOWN_GROW_RATE_CUSTOM_NONE: + growth_rate = days_between_town_growth; break; default: - days_between_town_growth = days_between_town_growth * DAY_TICKS / TOWN_GROWTH_TICKS; - EnforcePrecondition(false, days_between_town_growth < TOWN_GROW_RATE_CUSTOM); - if (days_between_town_growth == 0) days_between_town_growth = 1; // as fast as possible + // We are asked for days_between_town_growth * DAY_TICKS, + // but town expands every (t->growth_rate + 1) * TOWN_GROWTH_TICKS + // Thus selecting growth_rate to make it as close as possible + growth_rate = (days_between_town_growth * DAY_TICKS + TOWN_GROWTH_TICKS / 2) / TOWN_GROWTH_TICKS; + if (growth_rate > 0) growth_rate--; + EnforcePrecondition(false, growth_rate < TOWN_GROW_RATE_UNDEFINED); break; } - return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, days_between_town_growth, CMD_TOWN_GROWTH_RATE); + return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, growth_rate, CMD_TOWN_GROWTH_RATE); } /* static */ int32 ScriptTown::GetGrowthRate(TownID town_id) @@ -187,7 +188,7 @@ if (t->growth_rate == TOWN_GROW_RATE_CUSTOM_NONE) return TOWN_GROWTH_NONE; - return ((t->growth_rate & ~TOWN_GROW_RATE_CUSTOM) * TOWN_GROWTH_TICKS + DAY_TICKS) / DAY_TICKS; + return (((t->growth_rate & ~TOWN_GROW_RATE_CUSTOM) + 1) * TOWN_GROWTH_TICKS + DAY_TICKS / 2) / DAY_TICKS; } /* static */ int32 ScriptTown::GetDistanceManhattanToTile(TownID town_id, TileIndex tile) diff -r 322f2f20c99a src/script/api/script_town.hpp --- a/src/script/api/script_town.hpp Tue Sep 01 22:52:41 2015 +0300 +++ b/src/script/api/script_town.hpp Wed Oct 14 00:31:27 2015 +0300 @@ -120,8 +120,8 @@ * Special values for SetGrowthRate. */ enum TownGrowth { + TOWN_GROWTH_NORMAL = 0xFFFE, ///< Use default town growth algorithm instead of custom growth rate. TOWN_GROWTH_NONE = 0xFFFF, ///< Town does not grow at all. - TOWN_GROWTH_NORMAL = 0x10000, ///< Use default town growth algorithm instead of custom growth rate. }; /** diff -r 322f2f20c99a src/town.h --- a/src/town.h Tue Sep 01 22:52:41 2015 +0300 +++ b/src/town.h Wed Oct 14 00:31:27 2015 +0300 @@ -35,7 +35,9 @@ static const uint TOWN_GROWTH_WINTER = 0xFFFFFFFE; ///< The town only needs this cargo in the winter (any amount) static const uint TOWN_GROWTH_DESERT = 0xFFFFFFFF; ///< The town needs the cargo for growth when on desert (any amount) +static const uint16 TOWN_GROW_RATE_UNDEFINED = 0x7FFF; ///< Special value for Town::growth_rate to indicate that it is not calcuted yet static const uint16 TOWN_GROW_RATE_CUSTOM = 0x8000; ///< If this mask is applied to Town::growth_rate, the grow_counter will not be calculated by the system (but assumed to be set by scripts) +static const uint16 TOWN_GROW_RATE_NORMAL = 0xFFFE; ///< Special value for CmdTownGrowthRate to switch to normal growth rate calculation static const uint16 TOWN_GROW_RATE_CUSTOM_NONE = 0xFFFF; ///< Special value for Town::growth_rate to disable town growth. typedef Pool TownPool; diff -r 322f2f20c99a src/town_cmd.cpp --- a/src/town_cmd.cpp Tue Sep 01 22:52:41 2015 +0300 +++ b/src/town_cmd.cpp Wed Oct 14 00:31:27 2015 +0300 @@ -2596,24 +2596,36 @@ CommandCost CmdTownGrowthRate(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; - if ((p2 & TOWN_GROW_RATE_CUSTOM) != 0 && p2 != TOWN_GROW_RATE_CUSTOM_NONE) return CMD_ERROR; + if ((p2 & TOWN_GROW_RATE_CUSTOM) != 0 && p2 != TOWN_GROW_RATE_CUSTOM_NONE && + p2 != TOWN_GROW_RATE_NORMAL) return CMD_ERROR; + if (p2 == TOWN_GROW_RATE_UNDEFINED) return CMD_ERROR; if (GB(p2, 16, 16) != 0) return CMD_ERROR; Town *t = Town::GetIfValid(p1); if (t == NULL) return CMD_ERROR; if (flags & DC_EXEC) { - if (p2 == 0) { - /* Clear TOWN_GROW_RATE_CUSTOM, UpdateTownGrowRate will determine a proper value */ - t->growth_rate = 0; + if (p2 == TOWN_GROW_RATE_NORMAL) { + t->growth_rate = TOWN_GROW_RATE_UNDEFINED; + } else if (p2 == TOWN_GROW_RATE_CUSTOM_NONE) { + t->growth_rate = p2; + } else if (t->growth_rate == TOWN_GROW_RATE_CUSTOM_NONE) { + if (t->grow_counter >= p2) { + t->grow_counter = p2; + } + t->growth_rate = p2 | TOWN_GROW_RATE_CUSTOM; } else { - uint old_rate = t->growth_rate & ~TOWN_GROW_RATE_CUSTOM; - if (t->grow_counter >= old_rate) { - /* This also catches old_rate == 0 */ + if (t->growth_rate != TOWN_GROW_RATE_UNDEFINED) { + uint old_rate = t->growth_rate & ~TOWN_GROW_RATE_CUSTOM; + if (t->grow_counter >= old_rate) { + /* This also catches old_rate == 0 */ + t->grow_counter = p2; + } else { + /* Scale grow_counter, so half finished houses stay half finished */ + t->grow_counter = t->grow_counter * p2 / old_rate; + } + } else if (t->grow_counter >= p2) { t->grow_counter = p2; - } else { - /* Scale grow_counter, so half finished houses stay half finished */ - t->grow_counter = t->grow_counter * p2 / old_rate; } t->growth_rate = p2 | TOWN_GROW_RATE_CUSTOM; }