diff --git a/src/citymania/cm_event.hpp b/src/citymania/cm_event.hpp index 4463f492fa..bf2c95bd8b 100644 --- a/src/citymania/cm_event.hpp +++ b/src/citymania/cm_event.hpp @@ -20,10 +20,15 @@ namespace event { struct NewMonth { }; -struct TownGrowthTick { +struct TownGrowthSucceeded { Town *town; - bool growth_result; - uint16 prev_houses; + TileIndex tile; + uint32 prev_houses; +}; + +struct TownGrowthFailed { + Town *town; + TileIndex tile; }; struct HouseRebuilt { diff --git a/src/citymania/cm_game.cpp b/src/citymania/cm_game.cpp index 8f19c2da7a..187449f9d3 100644 --- a/src/citymania/cm_game.cpp +++ b/src/citymania/cm_game.cpp @@ -7,7 +7,7 @@ namespace citymania { Game::Game() { - this->events.listen([] (const event::NewMonth &) { + this->events.listen([this] (const event::NewMonth &) { for (Town *t : Town::Iterate()) { t->cm.hs_last_month = t->cm.hs_total - t->cm.hs_total_prev; t->cm.hs_total_prev = t->cm.hs_total; @@ -21,26 +21,38 @@ Game::Game() { t->cm.houses_demolished_last_month = t->cm.houses_demolished_this_month; t->cm.houses_demolished_this_month = 0; } + + this->towns_growth_tiles_last_month = this->towns_growth_tiles; + this->towns_growth_tiles.clear(); }); - this->events.listen([this] (const event::TownGrowthTick &event) { - if (event.growth_result) { - if (event.town->cache.num_houses <= event.prev_houses) { - event.town->cm.hs_total++; - } - } else { - event.town->cm.cs_total++; + + this->events.listen([this] (const event::TownGrowthSucceeded &event) { + if (event.town->cache.num_houses <= event.prev_houses) { + event.town->cm.hs_total++; + this->towns_growth_tiles[event.tile] = TownGrowthTileState::HS; } }); + + this->events.listen([this] (const event::TownGrowthFailed &event) { + event.town->cm.cs_total++; + this->towns_growth_tiles[event.tile] = TownGrowthTileState::CS; + }); + this->events.listen([this] (const event::HouseRebuilt &event) { if (event.was_successful) { event.town->cm.houses_reconstructed_this_month++; + this->towns_growth_tiles[event.tile] = TownGrowthTileState::RH_REBUILT; } else { event.town->cm.houses_demolished_this_month++; + this->towns_growth_tiles[event.tile] = TownGrowthTileState::RH_REMOVED; } }); + this->events.listen([this] (const event::HouseBuilt &event) { event.town->cm.houses_constructing++; + this->towns_growth_tiles[event.tile] = TownGrowthTileState::NEW_HOUSE; }); + this->events.listen([this] (const event::HouseCompleted &event) { event.town->cm.houses_constructing--; }); diff --git a/src/citymania/cm_game.hpp b/src/citymania/cm_game.hpp index 2caa4a1646..b7942a627e 100644 --- a/src/citymania/cm_game.hpp +++ b/src/citymania/cm_game.hpp @@ -7,7 +7,23 @@ namespace citymania { +/* BEGIN CMClient growth tiles */ +enum class TownGrowthTileState : uint8 { + NONE = 0, + RH_REMOVED, + NEW_HOUSE, + RH_REBUILT, // rebuilt and removed houses are also + CS, + HS, + HR +}; + class Game { +protected: + typedef std::map TownsGrowthTilesIndex; + TownsGrowthTilesIndex towns_growth_tiles_last_month; + TownsGrowthTilesIndex towns_growth_tiles; + public: event::Dispatcher events; diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 2adfab2c25..5db55683c7 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -881,10 +881,7 @@ static void TownTickHandler(Town *t) if (HasBit(t->flags, TOWN_IS_GROWING)) { int i = (int)t->grow_counter - 1; if (i < 0) { - uint16 prev_houses = t->cache.num_houses; - bool growth_res = GrowTown(t); - citymania::Emit((citymania::event::TownGrowthTick){t, growth_res, prev_houses}); - if (growth_res) { + if (GrowTown(t)) { i = t->growth_rate; } else { /* If growth failed wait a bit before retrying */ @@ -1570,17 +1567,24 @@ static bool GrowTownAtRoad(Town *t, TileIndex tile) break; } + uint16 prev_houses = t->cache.num_houses; do { RoadBits cur_rb = GetTownRoadBits(tile); // The RoadBits of the current tile /* Try to grow the town from this point */ GrowTownInTile(&tile, cur_rb, target_dir, t); - if (_grow_town_result == GROWTH_SUCCEED) return true; + if (_grow_town_result == GROWTH_SUCCEED) { + citymania::Emit(citymania::event::TownGrowthSucceeded{t, tile, prev_houses}); + return true; + } /* Exclude the source position from the bitmask * and return if no more road blocks available */ if (IsValidDiagDirection(target_dir)) cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir)); - if (cur_rb == ROAD_NONE) return false; + if (cur_rb == ROAD_NONE) { + citymania::Emit(citymania::event::TownGrowthFailed{t, tile}); + return false; + } if (IsTileType(tile, MP_TUNNELBRIDGE)) { /* Only build in the direction away from the tunnel or bridge. */ @@ -1589,7 +1593,10 @@ static bool GrowTownAtRoad(Town *t, TileIndex tile) /* Select a random bit from the blockmask, walk a step * and continue the search from there. */ do { - if (cur_rb == ROAD_NONE) return false; + if (cur_rb == ROAD_NONE) { + citymania::Emit(citymania::event::TownGrowthFailed{t, tile}); + return false; + } RoadBits target_bits; do { target_dir = RandomDiagDir(); @@ -1603,6 +1610,7 @@ static bool GrowTownAtRoad(Town *t, TileIndex tile) if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, RTT_ROAD)) { /* Don't allow building over roads of other cities */ if (IsRoadOwner(tile, RTT_ROAD, OWNER_TOWN) && Town::GetByTile(tile) != t) { + citymania::Emit(citymania::event::TownGrowthFailed{t, tile}); return false; } else if (IsRoadOwner(tile, RTT_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) { /* If we are in the SE, and this road-piece has no town owner yet, it just found an @@ -1615,6 +1623,7 @@ static bool GrowTownAtRoad(Town *t, TileIndex tile) /* Max number of times is checked. */ } while (--_grow_town_result >= 0); + citymania::Emit(citymania::event::TownGrowthFailed{t, tile}); return false; } @@ -1684,6 +1693,7 @@ static bool GrowTown(Town *t) RoadType rt = GetTownRoadType(t); DoCommand(tile, GenRandomRoadBits() | (rt << 4), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD); cur_company.Restore(); + citymania::Emit(citymania::event::TownGrowthSucceeded{t, tile, t->cache.num_houses}); return true; } } @@ -1692,6 +1702,7 @@ static bool GrowTown(Town *t) } cur_company.Restore(); + citymania::Emit(citymania::event::TownGrowthFailed{t, tile}); return false; }