diff --git a/.gitignore b/.gitignore index 90009635cb..709b88727a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,15 +4,14 @@ bin/ai/* !bin/ai/compat*.nut !bin/ai/regression !bin/data +!bin/baseset bin/baseset/* !bin/baseset/openttd.grf !bin/baseset/opntitle.dat !bin/baseset/orig_extra.grf -!bin/baseset/orig_*.obg -!bin/baseset/orig_*.obs -!bin/baseset/no_sound.obs -!bin/baseset/no_music.obm -!bin/baseset/orig_*.obm +!bin/game +bin/game/* +!bin/game/compat*.nut !bin/scripts bin/scripts/* !bin/scripts/*.example @@ -50,8 +49,3 @@ src/os/windows/ottdres.rc !/config.lib !*.in *.tmp - -/game/ -/openttd -grf/.nmlcache/ -grf/cmclient.grf diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index 588a2248cc..87ac61f310 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -1373,6 +1373,13 @@ + + + + + + + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index 6953eef76c..5e8a96d693 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -103,6 +103,9 @@ {c76ff9f1-1e62-46d8-8d55-000000000033} + + {c76ff9f1-1e62-46d8-8d55-000000000034} + @@ -3210,6 +3213,27 @@ Threading + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + diff --git a/projects/openttd_vs141.vcxproj b/projects/openttd_vs141.vcxproj index ecce50f7d6..30f3223e3c 100644 --- a/projects/openttd_vs141.vcxproj +++ b/projects/openttd_vs141.vcxproj @@ -1373,6 +1373,13 @@ + + + + + + + diff --git a/projects/openttd_vs141.vcxproj.filters b/projects/openttd_vs141.vcxproj.filters index 6953eef76c..5e8a96d693 100644 --- a/projects/openttd_vs141.vcxproj.filters +++ b/projects/openttd_vs141.vcxproj.filters @@ -103,6 +103,9 @@ {c76ff9f1-1e62-46d8-8d55-000000000033} + + {c76ff9f1-1e62-46d8-8d55-000000000034} + @@ -3210,6 +3213,27 @@ Threading + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + diff --git a/projects/openttd_vs142.vcxproj b/projects/openttd_vs142.vcxproj index 97738b0682..c41e992cbf 100644 --- a/projects/openttd_vs142.vcxproj +++ b/projects/openttd_vs142.vcxproj @@ -1373,6 +1373,13 @@ + + + + + + + diff --git a/projects/openttd_vs142.vcxproj.filters b/projects/openttd_vs142.vcxproj.filters index 6953eef76c..5e8a96d693 100644 --- a/projects/openttd_vs142.vcxproj.filters +++ b/projects/openttd_vs142.vcxproj.filters @@ -103,6 +103,9 @@ {c76ff9f1-1e62-46d8-8d55-000000000033} + + {c76ff9f1-1e62-46d8-8d55-000000000034} + @@ -3210,6 +3213,27 @@ Threading + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + diff --git a/source.list b/source.list index 844a768c38..2acc57bdac 100644 --- a/source.list +++ b/source.list @@ -1218,3 +1218,12 @@ sound/null_s.cpp # Threading thread.h + +# CityMania +citymania/cm_event.hpp +citymania/cm_game.hpp +citymania/cm_game.cpp +citymania/cm_main.hpp +citymania/cm_main.cpp +citymania/cm_type.hpp +citymania/extensions/cmext_town.hpp diff --git a/src/citymania/cm_event.hpp b/src/citymania/cm_event.hpp new file mode 100644 index 0000000000..9fd7c122ac --- /dev/null +++ b/src/citymania/cm_event.hpp @@ -0,0 +1,123 @@ +#ifndef CM_EVENT_HPP +#define CM_EVENT_HPP + +#include "cm_type.hpp" +#include "../cargo_type.h" +#include "../company_type.h" +#include "../economy_type.h" +#include "../station_type.h" +#include "../town_type.h" + +#include +#include +#include +#include + +namespace citymania { + +namespace event { + +struct NewMonth { +}; + +struct TownGrowthTick { + Town *town; + bool growth_result; + uint16 prev_houses; +}; + +struct CompanyEvent { + Company *company; +}; + +struct CargoAccepted { + Company *company; + CargoID cargo_type; + uint amount; + const Station *station; + Money profit; + SourceType src_type; + SourceID src; +}; + +struct CompanyMoneyChanged { + Company *company; + Money delta; +}; + +struct CompanyLoanChanged { + Company *company; + Money delta; +}; + +struct CompanyBalanceChanged { + Company *company; + Money delta; +}; + + +class TypeDispatcherBase { +public: + virtual ~TypeDispatcherBase() {} +}; + + +template +class TypeDispatcher: public TypeDispatcherBase { +public: + typedef std::function Handler; + + TypeDispatcher() { } + virtual ~TypeDispatcher() {} + + void listen(Handler &handler) { + this->new_handlers.push_back(handler); + } + + void emit(const T &event) { + if (!this->new_handlers.empty()) { + this->handlers.insert(this->handlers.end(), this->new_handlers.begin(), this->new_handlers.end()); + this->new_handlers.clear(); + } + for (auto &h : this->handlers) { + h(event); + } + } + +protected: + std::vector handlers; + std::vector new_handlers; +}; + + +class Dispatcher { +protected: + std::map> dispacthers; + + template + TypeDispatcher &get_dispatcher() { + auto p = this->dispacthers.find(typeid(T)); + if (p == this->dispacthers.end()) { + auto x = make_up>(); + p = this->dispacthers.emplace_hint(p, typeid(T), std::move(x)); + } + return *(static_cast *>((*p).second.get())); + } + +public: + template + void listen(std::function handler) { + this->get_dispatcher().listen(handler); + } + + template + void emit(const T &event) { + this->get_dispatcher().emit(event); + } +}; + +} // namespace event + +} // namespace citymania + +#endif diff --git a/src/citymania/cm_game.cpp b/src/citymania/cm_game.cpp new file mode 100644 index 0000000000..9e6ced6d4d --- /dev/null +++ b/src/citymania/cm_game.cpp @@ -0,0 +1,31 @@ +#include "../stdafx.h" + +#include "cm_game.hpp" + +#include "../safeguards.h" + +namespace citymania { + +Game::Game() { + this->events.listen([] (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; + t->cm.cs_last_month = t->cm.cs_total - t->cm.cs_total_prev; + t->cm.cs_total_prev = t->cm.cs_total; + t->cm.hr_last_month = t->cm.hr_total - t->cm.hr_total_prev; + t->cm.hr_total_prev = t->cm.hr_total; + } + }); + 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++; + } + }); +} + +} // namespace citymania \ No newline at end of file diff --git a/src/citymania/cm_game.hpp b/src/citymania/cm_game.hpp new file mode 100644 index 0000000000..2caa4a1646 --- /dev/null +++ b/src/citymania/cm_game.hpp @@ -0,0 +1,19 @@ +#ifndef CMEXT_GAME_HPP +#define CMEXT_GAME_HPP + +#include "../town.h" + +#include "cm_event.hpp" + +namespace citymania { + +class Game { +public: + event::Dispatcher events; + + Game(); +}; + +} // namespace citymania + +#endif diff --git a/src/citymania/cm_main.cpp b/src/citymania/cm_main.cpp new file mode 100644 index 0000000000..4fb14f046d --- /dev/null +++ b/src/citymania/cm_main.cpp @@ -0,0 +1,20 @@ +#include "../stdafx.h" + +#include "cm_main.hpp" + +#include "../safeguards.h" + +namespace citymania { + +up _game = nullptr; + +void ResetGame() { + _game = make_up(); +} + +void SwitchToMode(SwitchMode new_mode) { + ResetGame(); +} + + +} // namespace citymania \ No newline at end of file diff --git a/src/citymania/cm_main.hpp b/src/citymania/cm_main.hpp new file mode 100644 index 0000000000..32cb44fc2f --- /dev/null +++ b/src/citymania/cm_main.hpp @@ -0,0 +1,20 @@ +#ifndef CMEXT_MAIN_HPP +#define CMEXT_MAIN_HPP + +#include "cm_type.hpp" +#include "cm_game.hpp" + +namespace citymania { + +extern up _game; + +void SwitchToMode(SwitchMode new_mode); + +template +void Emit(const T &event) { + _game->events.emit(event); +} + +} // namespace citymania + +#endif diff --git a/src/citymania/cm_saveload.cpp b/src/citymania/cm_saveload.cpp index 4aa6ad9849..6cec829eea 100644 --- a/src/citymania/cm_saveload.cpp +++ b/src/citymania/cm_saveload.cpp @@ -57,22 +57,22 @@ static void EncodeTownsLayoutErrors(BitOStream &bs) { uint n_affected_towns = 0; for (const Town *t : Town::Iterate()) { - if (t->cb_houses_removed || t->houses_skipped || t->cycles_skipped) + if (t->cm.hr_total || t->cm.hs_total || t->cm.cs_total) n_affected_towns++; } bs.WriteBytes(n_affected_towns, 2); for (const Town *t : Town::Iterate()) { - if (t->cb_houses_removed || t->houses_skipped || t->cycles_skipped) { + if (t->cm.hr_total || t->cm.hs_total || t->cm.cs_total) { bs.WriteBytes(t->index, 2); - bs.WriteBytes(t->houses_skipped, 2); - bs.WriteBytes(t->houses_skipped_prev, 2); - bs.WriteBytes(t->houses_skipped_last_month, 2); - bs.WriteBytes(t->cycles_skipped, 2); - bs.WriteBytes(t->cycles_skipped_prev, 2); - bs.WriteBytes(t->cycles_skipped_last_month, 2); - bs.WriteBytes(t->cb_houses_removed, 2); - bs.WriteBytes(t->cb_houses_removed_prev, 2); - bs.WriteBytes(t->cb_houses_removed_last_month, 2); + bs.WriteBytes(t->cm.hs_total, 2); + bs.WriteBytes(t->cm.hs_total_prev, 2); + bs.WriteBytes(t->cm.hs_last_month, 2); + bs.WriteBytes(t->cm.cs_total, 2); + bs.WriteBytes(t->cm.cs_total_prev, 2); + bs.WriteBytes(t->cm.cs_last_month, 2); + bs.WriteBytes(t->cm.hr_total, 2); + bs.WriteBytes(t->cm.hr_total_prev, 2); + bs.WriteBytes(t->cm.hr_last_month, 2); } } EncodeTownsGrowthTiles(bs, _towns_growth_tiles); @@ -117,15 +117,15 @@ static void DecodeTownsLayoutErrors(BitIStream &bs) DEBUG(sl, 0, "Invalid TownID in CB towns layout errors (%u)", town_id); continue; } - t->houses_skipped = bs.ReadBytes(2); - t->houses_skipped_prev = bs.ReadBytes(2); - t->houses_skipped_last_month = bs.ReadBytes(2); - t->cycles_skipped = bs.ReadBytes(2); - t->cycles_skipped_prev = bs.ReadBytes(2); - t->cycles_skipped_last_month = bs.ReadBytes(2); - t->cb_houses_removed = bs.ReadBytes(2); - t->cb_houses_removed_prev = bs.ReadBytes(2); - t->cb_houses_removed_last_month = bs.ReadBytes(2); + t->cm.hs_total = bs.ReadBytes(2); + t->cm.hs_total_prev = bs.ReadBytes(2); + t->cm.hs_last_month = bs.ReadBytes(2); + t->cm.cs_total = bs.ReadBytes(2); + t->cm.cs_total_prev = bs.ReadBytes(2); + t->cm.cs_last_month = bs.ReadBytes(2); + t->cm.hr_total = bs.ReadBytes(2); + t->cm.hr_total_prev = bs.ReadBytes(2); + t->cm.hr_last_month = bs.ReadBytes(2); } DecodeTownsGrowthTiles(bs, _towns_growth_tiles); DecodeTownsGrowthTiles(bs, _towns_growth_tiles_last_month); diff --git a/src/citymania/cm_type.hpp b/src/citymania/cm_type.hpp new file mode 100644 index 0000000000..56bd4c7e45 --- /dev/null +++ b/src/citymania/cm_type.hpp @@ -0,0 +1,53 @@ +#ifndef CMEXT_TYPE_HPP +#define CMEXT_TYPE_HPP + +#include +#include +#include +#include + +/* C++14 implementation of make_unique */ +namespace std { + template struct _Unique_if { + typedef unique_ptr _Single_object; + }; + + template struct _Unique_if { + typedef unique_ptr _Unknown_bound; + }; + + template struct _Unique_if { + typedef void _Known_bound; + }; + + template + typename _Unique_if::_Single_object + make_unique(Args&&... args) { + return unique_ptr(new T(std::forward(args)...)); + } + + template + typename _Unique_if::_Unknown_bound + make_unique(size_t n) { + typedef typename remove_extent::type U; + return unique_ptr(new U[n]()); + } + + template + typename _Unique_if::_Known_bound + make_unique(Args&&...) = delete; +} // namespace std + +namespace citymania { + +// Make smart pointers easier to type +template using up=std::unique_ptr; +template using sp=std::shared_ptr; +template using wp=std::weak_ptr; + +template const auto make_up = std::make_unique; +template const auto make_sp = std::make_shared; + +} // namespace citymania + +#endif diff --git a/src/citymania/extensions/cmext_town.hpp b/src/citymania/extensions/cmext_town.hpp new file mode 100644 index 0000000000..cd07b37a08 --- /dev/null +++ b/src/citymania/extensions/cmext_town.hpp @@ -0,0 +1,25 @@ +#ifndef CMEXT_TOWN_HPP +#define CMEXT_TOWN_HPP + +namespace citymania { + +namespace ext { + +class Town { +public: + uint32 hs_total = 0; ///< number of skipped house buildings (HS) in total + uint32 hs_total_prev = 0; ///< number of skipped house buildings (HS) in total at the end of last month + uint32 hs_last_month = 0; ///< number of skipped house buildings (HS) during last month + uint32 cs_total = 0; ///< number of skipped growth cycles (CS) in total + uint32 cs_total_prev = 0; ///< number of skipped growth cycles (CS) in total at the end of last month + uint32 cs_last_month = 0; ///< number of skipped growth cycles (CS) during last month + uint32 hr_total = 0; ///< number of houses removed by the server (HR) in total + uint32 hr_total_prev = 0; ///< number of houses removed by the server (HR) in total at the end of last month + uint32 hr_last_month = 0; ///< number of houses removed by the server (HR) during last month +}; + +} // namespace citymania + +} // namespace citymania + +#endif diff --git a/src/date.cpp b/src/date.cpp index 97758a3ebf..621b1265c5 100644 --- a/src/date.cpp +++ b/src/date.cpp @@ -20,6 +20,8 @@ #include "saveload/saveload.h" #include "newgrf_profiling.h" +#include "citymania/cm_main.hpp" + #include "safeguards.h" Year _cur_year; ///< Current year, starting at 0 @@ -238,6 +240,7 @@ static void OnNewMonth() IndustryMonthlyLoop(); SubsidyMonthlyLoop(); StationMonthlyLoop(); + citymania::Emit(citymania::event::NewMonth()); if (_network_server) NetworkServerMonthlyLoop(); } diff --git a/src/openttd.cpp b/src/openttd.cpp index 44cbf240cf..1f56ee0ab1 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -69,6 +69,7 @@ #include "linkgraph/linkgraphschedule.h" #include "citymania/highlight.hpp" +#include "citymania/cm_main.hpp" #include #include @@ -1047,6 +1048,7 @@ bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, void SwitchToMode(SwitchMode new_mode) { + citymania::SwitchToMode(new_mode); /* If we are saving something, the network stays in his current state */ if (new_mode != SM_SAVE_GAME) { /* If the network is active, make it not-active */ diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index b0e91b4e75..1d3612ae31 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -141,17 +141,6 @@ void AfterLoadRoadStops() } } -/** - * (Re)scan for station docking tiles after loading a savegame. - */ -void AfterLoadScanDockingTiles() -{ - /* Scan for docking tiles */ - for (Station *st : Station::Iterate()) { - if (st->ship_station.tile != INVALID_TILE) UpdateStationDockingTiles(st); - } -} - static const SaveLoad _roadstop_desc[] = { SLE_VAR(RoadStop, xy, SLE_UINT32), SLE_CONDNULL(1, SL_MIN_VERSION, SLV_45), diff --git a/src/town.h b/src/town.h index d0c1d89916..3150f90b30 100644 --- a/src/town.h +++ b/src/town.h @@ -23,6 +23,8 @@ #include #include +#include "citymania/extensions/cmext_town.hpp" + template struct BuildingCounts { T id_count[NUM_HOUSES]; @@ -110,15 +112,6 @@ struct Town : TownPool::PoolItem<&_town_pool> { StringID town_label; ///< Label dependent on _local_company rating. CBTownInfo cb; bool growing_by_chance; ///< town growing due to 1/12 chance? - uint16 houses_skipped; ///< number of failed house buildings with next counter reset - uint16 houses_skipped_prev; ///< house_failures on start of previous month - uint16 houses_skipped_last_month; ///< house_failures during last month - uint16 cycles_skipped; ///< number of house building cycles skipped due to placement failure - uint16 cycles_skipped_prev; - uint16 cycles_skipped_last_month; - uint16 cb_houses_removed; ///< houses removed by cb server (excluding ones when town is not growing) - uint16 cb_houses_removed_prev; ///< houses removed by cb server on start of previous month - uint16 cb_houses_removed_last_month; ///< houses removed by cb server during last month uint houses_construction; ///< number of houses currently being built uint houses_reconstruction; ///< number of houses currently being rebuilt uint houses_demolished; ///< number of houses demolished this month @@ -155,6 +148,8 @@ struct Town : TownPool::PoolItem<&_town_pool> { std::list psa_list; + citymania::ext::Town cm; + /** * Creates a new town. * @param tile center tile of the town diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index c2649734fe..b734d2b1f0 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -53,6 +53,7 @@ #include "table/town_land.h" #include "citymania/highlight.hpp" +#include "citymania/cm_main.hpp" #include "safeguards.h" @@ -709,7 +710,7 @@ static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags) if (flags & DC_EXEC) { if (_current_company == COMPANY_FIRST && Company::Get(_current_company)->money > NOVAPOLIS_COMPANY_MONEY_THRESHOLD) { - if (t->cb.growth_state == TownGrowthState::GROWING) t->cb_houses_removed++; + if (t->cb.growth_state == TownGrowthState::GROWING) t->cm.hr_total++; UpdateTownGrowthTile(tile, t->cb.growth_state == TownGrowthState::GROWING ? TGTS_CB_HOUSE_REMOVED: TGTS_CB_HOUSE_REMOVED_NOGROW); } ClearTownHouse(t, tile); @@ -1025,15 +1026,12 @@ static void TownTickHandler(Town *t) int i = (int)t->grow_counter - 1; uint16 houses_prev = t->cache.num_houses; if (i < 0) { - if (GrowTown(t)) { + 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) { i = t->growth_rate; - if (t->cache.num_houses <= houses_prev && (t->cb.growth_state == TownGrowthState::GROWING || !CB_Enabled())){ - t->houses_skipped++; - } } else { - if (t->cb.growth_state == TownGrowthState::GROWING || !CB_Enabled()){ - t->cycles_skipped++; - } /* If growth failed wait a bit before retrying */ i = min(t->growth_rate, TOWN_GROWTH_TICKS - 1); } @@ -4048,12 +4046,6 @@ void TownsMonthlyLoop() t->houses_demolished = 0; t->houses_reconstruction = 0; - t->houses_skipped_last_month = t->houses_skipped - t->houses_skipped_prev; - t->houses_skipped_prev = t->houses_skipped; - t->cycles_skipped_last_month = t->cycles_skipped - t->cycles_skipped_prev; - t->cycles_skipped_prev = t->cycles_skipped; - t->cb_houses_removed_last_month = t->cb_houses_removed - t->cb_houses_removed_prev; - t->cb_houses_removed_prev = t->cb_houses_removed; } UpdateTownCargoBitmap(); diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 01be498439..0c0cf185be 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -1415,12 +1415,12 @@ static void DrawExtraTownInfo (const Rect &r, uint &y, Town *town, uint line, bo } ///houses stats - SetDParam(0, town->houses_skipped); - SetDParam(1, town->houses_skipped_last_month); - SetDParam(2, town->cycles_skipped); - SetDParam(3, town->cycles_skipped_last_month); - SetDParam(4, town->cb_houses_removed); - SetDParam(5, town->cb_houses_removed_last_month); + SetDParam(0, town->cm.hs_total); + SetDParam(1, town->cm.hs_last_month); + SetDParam(2, town->cm.cs_total); + SetDParam(3, town->cm.cs_last_month); + SetDParam(4, town->cm.hr_total); + SetDParam(5, town->cm.hr_last_month); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += line, STR_TOWN_VIEW_GROWTH_TILES); }