diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index 87ac61f310..084a266f89 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -1373,13 +1373,18 @@ + + + + + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index 5e8a96d693..90e26ad076 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -3213,9 +3213,21 @@ Threading + + CityMania + + + CityMania + CityMania + + CityMania + + + CityMania + CityMania @@ -3234,6 +3246,9 @@ CityMania + + CityMania + diff --git a/projects/openttd_vs141.vcxproj b/projects/openttd_vs141.vcxproj index 30f3223e3c..632b86b126 100644 --- a/projects/openttd_vs141.vcxproj +++ b/projects/openttd_vs141.vcxproj @@ -1373,13 +1373,18 @@ + + + + + diff --git a/projects/openttd_vs141.vcxproj.filters b/projects/openttd_vs141.vcxproj.filters index 5e8a96d693..90e26ad076 100644 --- a/projects/openttd_vs141.vcxproj.filters +++ b/projects/openttd_vs141.vcxproj.filters @@ -3213,9 +3213,21 @@ Threading + + CityMania + + + CityMania + CityMania + + CityMania + + + CityMania + CityMania @@ -3234,6 +3246,9 @@ CityMania + + CityMania + diff --git a/projects/openttd_vs142.vcxproj b/projects/openttd_vs142.vcxproj index c41e992cbf..c4abf2060a 100644 --- a/projects/openttd_vs142.vcxproj +++ b/projects/openttd_vs142.vcxproj @@ -1373,13 +1373,18 @@ + + + + + diff --git a/projects/openttd_vs142.vcxproj.filters b/projects/openttd_vs142.vcxproj.filters index 5e8a96d693..90e26ad076 100644 --- a/projects/openttd_vs142.vcxproj.filters +++ b/projects/openttd_vs142.vcxproj.filters @@ -3213,9 +3213,21 @@ Threading + + CityMania + + + CityMania + CityMania + + CityMania + + + CityMania + CityMania @@ -3234,6 +3246,9 @@ CityMania + + CityMania + diff --git a/source.list b/source.list index 2acc57bdac..b1f3a0d0f7 100644 --- a/source.list +++ b/source.list @@ -1220,10 +1220,15 @@ sound/null_s.cpp thread.h # CityMania +citymania/cm_console_cmds.hpp +citymania/cm_console_cmds.cpp citymania/cm_event.hpp +citymania/cm_export.hpp +citymania/cm_export.cpp 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 +citymania/extensions/cmext_company.hpp diff --git a/src/cargo_table_gui.cpp b/src/cargo_table_gui.cpp index 21850d5060..d9224de3fc 100644 --- a/src/cargo_table_gui.cpp +++ b/src/cargo_table_gui.cpp @@ -155,14 +155,9 @@ struct CargosWindow : Window { case WID_CT_AMOUNT: for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) { const CargoSpec *cs = _sorted_cargo_specs[i]; - - if (this->cargoPeriod == WID_CT_OPTION_CARGO_MONTH) { - sum_cargo_amount += c->cargo_units_period[0][cs->Index()]; - SetDParam(0, c->cargo_units_period[0][cs->Index()]); - } else { - sum_cargo_amount += c->cargo_units[cs->Index()]; - SetDParam(0, c->cargo_units[cs->Index()]); - } + auto &economy = (this->cargoPeriod == WID_CT_OPTION_CARGO_MONTH ? c->old_economy[0] : c->cur_economy); + sum_cargo_amount += economy.delivered_cargo[cs->Index()]; + SetDParam(0, economy.delivered_cargo[cs->Index()]); DrawString(r.left, r.right, y + text_y_ofs, STR_TOOLBAR_CARGOS_UNITS, TC_FROMSTRING, SA_RIGHT); //cargo amount in pcs y += line_height; @@ -177,14 +172,10 @@ struct CargosWindow : Window { case WID_CT_INCOME: for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) { const CargoSpec *cs = _sorted_cargo_specs[i]; + auto &economy = (this->cargoPeriod == WID_CT_OPTION_CARGO_MONTH ? c->old_economy[0] : c->cur_economy); - if (this->cargoPeriod == WID_CT_OPTION_CARGO_MONTH) { - sum_cargo_income += c->cargo_income_period[0][cs->Index()]; - DrawPrice(c->cargo_income_period[0][cs->Index()], r.left, r.right, y + text_y_ofs); - } else { - sum_cargo_income += c->cargo_income[cs->Index()]; - DrawPrice(c->cargo_income[cs->Index()], r.left, r.right, y + text_y_ofs); - } + sum_cargo_income += economy.cm.cargo_income[cs->Index()]; + DrawPrice(economy.cm.cargo_income[cs->Index()], r.left, r.right, y + text_y_ofs); y += line_height; } diff --git a/src/citymania/cm_console_cmds.cpp b/src/citymania/cm_console_cmds.cpp new file mode 100644 index 0000000000..8414c50a3e --- /dev/null +++ b/src/citymania/cm_console_cmds.cpp @@ -0,0 +1,31 @@ +#include "../stdafx.h" + +#include "cm_console_cmds.hpp" + +#include "cm_export.hpp" + +#include "../console_func.h" +#include "../console_type.h" + +#include "../safeguards.h" + +namespace citymania { + +static void IConsoleHelp(const char *str) +{ + IConsolePrintF(CC_WARNING, "- %s", str); +} + +bool ConExport(byte argc, char *argv[]) { + if (argc == 0) { + IConsoleHelp("Exports various game data in json format to openttd.json file"); + return true; + } + + auto filename = "openttd.json"; + citymania::ExportOpenttdData(filename); + IConsolePrintF(CC_DEFAULT, "Data successfully saved to %s", filename); + return true; +} + +} // namespace citymania diff --git a/src/citymania/cm_console_cmds.hpp b/src/citymania/cm_console_cmds.hpp new file mode 100644 index 0000000000..b01e03fd6e --- /dev/null +++ b/src/citymania/cm_console_cmds.hpp @@ -0,0 +1,12 @@ +#ifndef CM_CONSOLE_CMDS_HPP +#define CM_CONSOLE_CMDS_HPP + +namespace citymania { + +bool ConExport(byte argc, char *argv[]); + +} // namespace citymania + +#endif + + diff --git a/src/citymania/cm_event.hpp b/src/citymania/cm_event.hpp index 7f8a6d106f..f0b73ccc6c 100644 --- a/src/citymania/cm_event.hpp +++ b/src/citymania/cm_event.hpp @@ -5,6 +5,7 @@ #include "../cargo_type.h" #include "../company_type.h" #include "../economy_type.h" +#include "../industry_type.h" #include "../station_type.h" #include "../town_type.h" @@ -61,6 +62,19 @@ struct CompanyEvent { Company *company; }; +struct CargoDeliveredToIndustry { + Industry *industry; + CargoID cargo_type; + uint amount; + const Station *station; +}; + +struct CargoDeliveredToUnknown { + CargoID cargo_type; + uint amount; + const Station *station; +}; + struct CargoAccepted { Company *company; CargoID cargo_type; diff --git a/src/citymania/cm_export.cpp b/src/citymania/cm_export.cpp new file mode 100644 index 0000000000..1e247e1868 --- /dev/null +++ b/src/citymania/cm_export.cpp @@ -0,0 +1,273 @@ +#include "../stdafx.h" + +#include "cm_export.hpp" + +#include "../cargotype.h" +#include "../gfx_func.h" +#include "../gfx_type.h" +#include "../engine_base.h" +#include "../spritecache.h" +#include "../strings_func.h" +#include "../strings_type.h" +#include "../table/palettes.h" +#include "../table/sprites.h" +#include "../table/train_cmd.h" + +#include +#include +#include +#include + +#include "../safeguards.h" + +namespace citymania { + +extern SpriteID (*GetDefaultTrainSprite)(uint8, Direction); // train_cmd.cpp + +namespace data_export { + +class JsonWriter { +protected: + int i = 0; + bool no_comma = true; + char buffer[128]; + +public: + std::ofstream f; + + JsonWriter(const std::string &fname) { + f.open(fname.c_str()); + f << "OPENTTD = {"; + no_comma = true; + } + + ~JsonWriter() { + this->ident(false); + f << "}" << std::endl; + f.close(); + } + + void ident(bool comma=true) { + if (comma && !no_comma) f << ","; + no_comma = false; + f << std::endl; + for(int j = 0; j < i; j++) f << " "; + } + + void key(const char *k) { + const char *kn; + for (kn = k + strlen(k); kn >= k && *kn != '>' && *kn != '.'; kn--); + kn++; + this->ident(); + f << "\"" << kn << "\": "; + } + + void value(bool val) { + f << (val ? "true" : "false"); + } + + void value(unsigned int val) { + f << val; + } + + void value(uint64 val) { + f << val; + } + + void value(Money val) { + f << val; + } + + void value(int val) { + f << val; + } + + void value(const char *v) { + f << "\"" << v << "\""; + } + + void value(const std::string &s) { + f << "\"" << s << "\""; + } + + template + void kv(const char *k, T v) { + key(k); + value(v); + } + + void ks(const char *k, StringID s) { + GetString(buffer, s, lastof(buffer)); + key(k); + value(buffer); + } + + void begin_dict_with_key(const char *k) { + key(k); + f << "{"; + no_comma = true; + i++; + } + + void begin_dict() { + this->ident(); + f << "{"; + no_comma = true; + i++; + } + + void end_dict() { + i--; + this->ident(false); + f << "}"; + } + + void begin_list_with_key(const char *k) { + key(k); + f << "["; + no_comma = true; + i++; + } + + void end_list() { + i--; + this->ident(false); + f << "]"; + } +}; + +#define JKV(j, field) j.kv(#field, field) + +void WriteHouseSpecInfo(JsonWriter &j) { + j.begin_list_with_key("cargo_specs"); + const CargoSpec *cs; + char buffer[128]; + char cargo_label[16]; + bool first = true; + SetDParam(0, 123); + FOR_ALL_CARGOSPECS(cs) { + j.begin_dict(); + JKV(j, cs->initial_payment); + j.kv("id", cs->bitnum); + j.kv("transit_days_1", cs->transit_days[0]); + j.kv("transit_days_2", cs->transit_days[1]); + JKV(j, cs->weight); + JKV(j, cs->multiplier); + JKV(j, cs->is_freight); + JKV(j, cs->legend_colour); + JKV(j, cs->rating_colour); + JKV(j, cs->sprite); + j.ks("name", cs->name); + j.ks("name_single", cs->name_single); + j.ks("units_volume", cs->units_volume); + j.ks("quantifier", cs->quantifier); + j.ks("abbrev", cs->abbrev); + + for (uint i = 0; i < sizeof(cs->label); i++) { + cargo_label[i] = GB(cs->label, (uint8)(sizeof(cs->label) - i - 1) * 8, 8); + } + cargo_label[sizeof(cs->label)] = '\0'; + JKV(j, cs->label); + j.kv("label_str", cargo_label); + j.end_dict(); + } + j.end_list(); +} + +// extern const Palette _palette; +void WritePaletteInfo(JsonWriter &j) { + j.begin_list_with_key("palette"); + for (uint i = 0; i < 256; i++) { + j.begin_dict(); + auto &c = _palette.palette[i]; + JKV(j, c.r); + JKV(j, c.g); + JKV(j, c.b); + std::ostringstream hex; + hex << "#" << std::hex << std::setfill('0'); + hex << std::setw(2) << (int)c.r; + hex << std::setw(2) << (int)c.g; + hex << std::setw(2) << (int)c.b; + j.kv("hex", hex.str()); + j.end_dict(); + } + j.end_list(); + j.begin_list_with_key("gradients"); + for (auto i = 0; i < COLOUR_END; i++) { + if (i != 0) j.f << ","; + j.f << std::endl << "["; + for (auto k = 0; k < 8; k++) { + if (k != 0) j.f << ", "; + j.f << (int)_colour_gradient[i][k] << " "; + } + j.f << "]"; + } + j.end_list(); + const byte *remap = GetNonSprite(GB(PALETTE_TO_RED, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; +} + +void WriteEngineInfo(JsonWriter &j) { + j.begin_list_with_key("engines"); + const Engine *e; + for (const Engine *e : Engine::Iterate()) { + if (e->type != VEH_TRAIN) continue; + j.begin_dict(); + JKV(j, e->index); + j.kv("name", (e->name ? e->name : "null")); + j.kv("cost", e->GetCost()); + j.kv("running_cost", e->GetRunningCost()); + { + j.begin_dict_with_key("info"); + JKV(j, e->info.cargo_type); + JKV(j, e->info.cargo_age_period); + JKV(j, e->info.climates); + JKV(j, e->info.base_intro); + JKV(j, e->info.lifelength); + JKV(j, e->info.base_life); + JKV(j, e->info.refit_mask); + JKV(j, e->info.refit_cost); + JKV(j, e->info.load_amount); + j.ks("name", e->info.string_id); + j.end_dict(); + } + { + const RailVehicleInfo *rvi = &e->u.rail; + j.begin_dict_with_key("rail"); + JKV(j, rvi->image_index); + JKV(j, rvi->railveh_type); + JKV(j, rvi->railtype); + JKV(j, rvi->max_speed); + JKV(j, rvi->power); + JKV(j, rvi->weight); + JKV(j, rvi->running_cost); + JKV(j, rvi->running_cost_class); + JKV(j, rvi->engclass); + JKV(j, rvi->tractive_effort); + JKV(j, rvi->air_drag); + JKV(j, rvi->capacity); + SpriteID sprite = GetDefaultTrainSprite(e->original_image_index, DIR_W); + JKV(j, sprite); + if (rvi->railveh_type == RAILVEH_MULTIHEAD) { + j.kv("rev_sprite", + GetDefaultTrainSprite(e->original_image_index + 1, DIR_W)); + } else if (rvi->railveh_type == RAILVEH_WAGON) { + j.kv("full_sprite", + sprite + _wagon_full_adder[e->original_image_index]); + } + j.end_dict(); + } + j.end_dict(); + } + j.end_list(); +} + +} // namespace export + +void ExportOpenttdData(const std::string &filename) { + data_export::JsonWriter j(filename); + data_export::WriteHouseSpecInfo(j); + data_export::WritePaletteInfo(j); + data_export::WriteEngineInfo(j); +} + +} // namespace citymania diff --git a/src/citymania/cm_export.hpp b/src/citymania/cm_export.hpp new file mode 100644 index 0000000000..b83259500a --- /dev/null +++ b/src/citymania/cm_export.hpp @@ -0,0 +1,12 @@ +#ifndef CM_EXPORT_HPP +#define CM_EXPORT_HPP + +namespace citymania { + +void ExportOpenttdData(const std::string &filename); + +} // namespace citymania + +#endif + + diff --git a/src/citymania/cm_game.cpp b/src/citymania/cm_game.cpp index d544ac0d00..fc3891fc0d 100644 --- a/src/citymania/cm_game.cpp +++ b/src/citymania/cm_game.cpp @@ -2,6 +2,8 @@ #include "cm_game.hpp" +#include "../company_base.h" + #include "../safeguards.h" namespace citymania { @@ -78,6 +80,10 @@ Game::Game() { town->cm.real_population += HouseSpec::Get(house_id)->population; } }); + + this->events.listen([this] (const event::CargoAccepted &event) { + event.company->cur_economy.cm.cargo_income[event.cargo_type] += event.profit; + }); } } // namespace citymania \ No newline at end of file diff --git a/src/citymania/extensions/cmext_company.hpp b/src/citymania/extensions/cmext_company.hpp new file mode 100644 index 0000000000..57b73a826c --- /dev/null +++ b/src/citymania/extensions/cmext_company.hpp @@ -0,0 +1,18 @@ +#ifndef CMEXT_COMPANY_HPP +#define CMEXT_COMPANY_HPP + +#include "../../cargo_type.h" + +namespace citymania { + +namespace ext { +class CompanyEconomyEntry { +public: + Money cargo_income[NUM_CARGO]; ///< Cargo income from each cargo type +}; + +} // namespace citymania + +} // namespace citymania + +#endif diff --git a/src/company_base.h b/src/company_base.h index 324d56a5af..df5137f74a 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -15,9 +15,10 @@ #include "autoreplace_type.h" #include "tile_type.h" #include "settings_type.h" -#include "cargo_type.h" #include "group.h" +#include "citymania/extensions/cmext_company.hpp" + /** Statistics about the economy. */ struct CompanyEconomyEntry { Money income; ///< The amount of income. @@ -25,7 +26,7 @@ struct CompanyEconomyEntry { CargoArray delivered_cargo; ///< The amount of delivered cargo. int32 performance_history; ///< Company score (scale 0-1000) Money company_value; ///< The value of the company. - Money cargo_income[NUM_CARGO]; ///< Cargo income from each cargo type + citymania::ext::CompanyEconomyEntry cm; ///< CityMania extra economy data. }; struct CompanyInfrastructure { @@ -132,12 +133,6 @@ struct Company : CompanyPool::PoolItem<&_company_pool>, CompanyProperties { CompanyInfrastructure infrastructure; ///< NOSAVE: Counts of company owned infrastructure. - uint32 cargo_units[NUM_CARGO]; ///< Total amount of transported cargo for each cargo ID - Money cargo_income[NUM_CARGO]; ///< Total income from transported cargo for each cargo ID - - uint32 cargo_units_period[2][NUM_CARGO]; ///< Monthly amount of transported cargo for each cargo ID - Money cargo_income_period[2][NUM_CARGO]; ///< Monthly income from transported cargo for each cargo ID - /** * Is this company a valid company, controlled by the computer (a NoAI program)? * @param index Index in the pool. diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index e33b7618c3..0a88a1b20c 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -586,21 +586,9 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY) if (!is_ai) UpdateAllTownVirtCoords(); //coloured rating - for (uint j = 0; j < NUM_CARGO; j++) { - c->cargo_income[j] = 0; - c->cargo_units[j] = 0; - } - CargoResetPeriods(c); - return c; } -void CargoResetPeriods(Company *c){ - memmove(&c->cargo_income_period[1], &c->cargo_income_period[0], sizeof(c->cargo_income_period[0])); - memset(&c->cargo_income_period, 0, sizeof(c->cargo_income_period[0])); - memmove(&c->cargo_units_period[1], &c->cargo_units_period[0], sizeof(c->cargo_units_period[0])); - memset(&c->cargo_units_period, 0, sizeof(c->cargo_units_period[0])); -} /** Start the next competitor now. */ void StartupCompanies() { diff --git a/src/company_func.h b/src/company_func.h index bafb8eaf00..cec6110044 100644 --- a/src/company_func.h +++ b/src/company_func.h @@ -29,7 +29,6 @@ void SubtractMoneyFromCompany(CommandCost cost); void SubtractMoneyFromCompanyFract(CompanyID company, CommandCost cost); CommandCost CheckOwnership(Owner owner, TileIndex tile = 0); CommandCost CheckTileOwnership(TileIndex tile); -void CargoResetPeriods(Company *c); extern CompanyID _local_company; extern CompanyID _current_company; diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 8fe4ccc515..4121945965 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -40,6 +40,8 @@ #include "table/strings.h" #include +#include "citymania/cm_console_cmds.hpp" + #include "safeguards.h" /* scriptfile handling */ @@ -2221,4 +2223,6 @@ void IConsoleStdLibRegister() /* NewGRF development stuff */ IConsoleCmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool); IConsoleCmdRegister("newgrf_profile", ConNewGRFProfile, ConHookNewGRFDeveloperTool); + + IConsoleCmdRegister("cmexport", citymania::ConExport); } diff --git a/src/economy.cpp b/src/economy.cpp index 019aa64fcd..86abad9b6f 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -53,6 +53,8 @@ #include "table/pricebase.h" #include "cargo_table_gui.h" +#include "citymania/cm_main.hpp" + #include "safeguards.h" @@ -1056,6 +1058,10 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n /* Update the cargo monitor. */ AddCargoDelivery(cargo_type, company, amount, ST_INDUSTRY, source, st, ind->index); + + if (amount > 0) + citymania::Emit(citymania::event::CargoDeliveredToIndustry{ind, cargo_type, amount, st}); + } return accepted; @@ -1124,15 +1130,11 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, Ti } } - company->cargo_income[cargo_type] += profit; - company->cargo_units[cargo_type] += num_pieces; - - company->cargo_income_period[0][cargo_type] += profit; - company->cargo_units_period[0][cargo_type] += num_pieces; - - company->cur_economy.cargo_income[cargo_type] += profit; - - InvalidateCargosWindows(company->index); + if (accepted_total > 0) { + if (accepted_ind != accepted_total) + citymania::Emit(citymania::event::CargoDeliveredToUnknown{cargo_type, accepted_total - accepted_ind, st}); + citymania::Emit(citymania::event::CargoAccepted{company, cargo_type, accepted_total, st, profit, src_type, src}); + } return profit; } @@ -1976,10 +1978,6 @@ void CompaniesMonthlyLoop() } CompaniesPayInterest(); HandleEconomyFluctuations(); - - for (Company *c : Company::Iterate()) { - CargoResetPeriods(c); - } } static void DoAcquireCompany(Company *c) diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index f889b913b9..08111af43a 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -872,7 +872,7 @@ struct IncomeGraphWindow : ExcludingCargoBaseGraphWindow { const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { if (!HasBit(_legend_excluded_cargo, cs->Index())){ - total_income += c->old_economy[j].cargo_income[cs->Index()]; + total_income += c->old_economy[j].cm.cargo_income[cs->Index()]; } } return total_income; diff --git a/src/rev.cpp b/src/rev.cpp index a45964a8a6..91db4f6e8e 100644 --- a/src/rev.cpp +++ b/src/rev.cpp @@ -88,4 +88,4 @@ const byte _openttd_revision_tagged = 1; const uint32 _openttd_newgrf_version = 1 << 28 | 10 << 24 | 0 << 20 | 1 << 19 | 28004; -const char _citymania_version[] = "20200619-master-m2010f236c6 20.06.20"; +const char _citymania_version[] = "20200620-master-m2380beede6 04.07.20"; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index f6b9726412..edf470b539 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -4018,3 +4018,7 @@ Trackdir Train::GetVehicleTrackdir() const return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction); } + +namespace citymania { + auto GetDefaultTrainSprite = &::GetDefaultTrainSprite; +}