diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index 5bc6254ff7..835d1e8ebd 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -1348,6 +1348,13 @@ + + + + + + + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index 0405740d4c..f7f90603a6 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -100,6 +100,9 @@ {c76ff9f1-1e62-46d8-8d55-000000000032} + + {c76ff9f1-1e62-46d8-8d55-000000000033} + @@ -3132,6 +3135,27 @@ Threading + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + diff --git a/projects/openttd_vs141.vcxproj b/projects/openttd_vs141.vcxproj index 8df3d47daf..d290f90500 100644 --- a/projects/openttd_vs141.vcxproj +++ b/projects/openttd_vs141.vcxproj @@ -1348,6 +1348,13 @@ + + + + + + + diff --git a/projects/openttd_vs141.vcxproj.filters b/projects/openttd_vs141.vcxproj.filters index 0405740d4c..f7f90603a6 100644 --- a/projects/openttd_vs141.vcxproj.filters +++ b/projects/openttd_vs141.vcxproj.filters @@ -100,6 +100,9 @@ {c76ff9f1-1e62-46d8-8d55-000000000032} + + {c76ff9f1-1e62-46d8-8d55-000000000033} + @@ -3132,6 +3135,27 @@ Threading + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + diff --git a/projects/openttd_vs142.vcxproj b/projects/openttd_vs142.vcxproj index 487bb95fd3..3b8e8e34fe 100644 --- a/projects/openttd_vs142.vcxproj +++ b/projects/openttd_vs142.vcxproj @@ -1348,6 +1348,13 @@ + + + + + + + diff --git a/projects/openttd_vs142.vcxproj.filters b/projects/openttd_vs142.vcxproj.filters index 0405740d4c..f7f90603a6 100644 --- a/projects/openttd_vs142.vcxproj.filters +++ b/projects/openttd_vs142.vcxproj.filters @@ -100,6 +100,9 @@ {c76ff9f1-1e62-46d8-8d55-000000000032} + + {c76ff9f1-1e62-46d8-8d55-000000000033} + @@ -3132,6 +3135,27 @@ Threading + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + + + CityMania + diff --git a/source.list b/source.list index fd68c010e8..3d1d04c4b1 100644 --- a/source.list +++ b/source.list @@ -1191,3 +1191,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_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 7d9bd09a61..615ce7f822 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -68,6 +68,8 @@ #include "linkgraph/linkgraphschedule.h" +#include "citymania/cm_main.hpp" + #include #include @@ -1042,6 +1044,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/town.h b/src/town.h index 8399fa63f3..aeb8d6f563 100644 --- a/src/town.h +++ b/src/town.h @@ -18,6 +18,8 @@ #include "tilematrix_type.hpp" #include +#include "citymania/extensions/cmext_town.hpp" + template struct BuildingCounts { T id_count[NUM_HOUSES]; @@ -104,6 +106,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 1d550fb028..aaa955640e 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -52,6 +52,8 @@ #include "table/strings.h" #include "table/town_land.h" +#include "citymania/cm_main.hpp" + #include "safeguards.h" TownID _new_town_id; @@ -871,7 +873,10 @@ static void TownTickHandler(Town *t) if (HasBit(t->flags, TOWN_IS_GROWING)) { int i = (int)t->grow_counter - 1; 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; } else { /* If growth failed wait a bit before retrying */