Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2020-07-09 10:55:24 +03:00
10 changed files with 259 additions and 131 deletions

View File

@@ -613,23 +613,6 @@ water_cmd.cpp
waypoint_cmd.cpp waypoint_cmd.cpp
zoning_cmd.cpp zoning_cmd.cpp
# CityMania files
citymania/base64.h
citymania/base64.cpp
citymania/cm_bitstream.hpp
citymania/cm_bitstream.cpp
citymania/highlight.hpp
citymania/highlight.cpp
citymania/locations.hpp
citymania/locations.cpp
citymania/minimap.hpp
citymania/minimap.cpp
citymania/cm_saveload.hpp
citymania/cm_saveload.cpp
citymania/station_ui.hpp
citymania/station_ui.cpp
newgrf_revisions.hpp
# Save/Load handlers # Save/Load handlers
saveload/afterload.cpp saveload/afterload.cpp
saveload/ai_sl.cpp saveload/ai_sl.cpp
@@ -1220,6 +1203,8 @@ sound/null_s.cpp
thread.h thread.h
# CityMania # CityMania
citymania/cm_bitstream.hpp
citymania/cm_bitstream.cpp
citymania/cm_console_cmds.hpp citymania/cm_console_cmds.hpp
citymania/cm_console_cmds.cpp citymania/cm_console_cmds.cpp
citymania/cm_event.hpp citymania/cm_event.hpp
@@ -1232,5 +1217,21 @@ citymania/cm_main.cpp
citymania/cm_tooltips.hpp citymania/cm_tooltips.hpp
citymania/cm_tooltips.cpp citymania/cm_tooltips.cpp
citymania/cm_type.hpp citymania/cm_type.hpp
citymania/cm_saveload.hpp
citymania/cm_saveload.cpp
citymania/cm_settings.hpp
citymania/extensions/cmext_town.hpp citymania/extensions/cmext_town.hpp
citymania/extensions/cmext_company.hpp citymania/extensions/cmext_company.hpp
# CityMania client
citymania/base64.h
citymania/base64.cpp
citymania/highlight.hpp
citymania/highlight.cpp
citymania/locations.hpp
citymania/locations.cpp
citymania/minimap.hpp
citymania/minimap.cpp
citymania/station_ui.hpp
citymania/station_ui.cpp
newgrf_revisions.hpp

View File

@@ -2,6 +2,8 @@
#define CM_EVENT_HPP #define CM_EVENT_HPP
#include "cm_type.hpp" #include "cm_type.hpp"
#include "../console_func.h"
#include "../cargo_type.h" #include "../cargo_type.h"
#include "../company_type.h" #include "../company_type.h"
#include "../economy_type.h" #include "../economy_type.h"
@@ -42,12 +44,15 @@ struct HouseRebuilt {
struct HouseBuilt { struct HouseBuilt {
Town *town; Town *town;
TileIndex tile; TileIndex tile;
HouseID house_id;
const HouseSpec *house_spec; const HouseSpec *house_spec;
bool is_rebuilding;
}; };
struct HouseCleared { struct HouseCleared {
Town *town; Town *town;
TileIndex tile; TileIndex tile;
HouseID house_id;
const HouseSpec *house_spec; const HouseSpec *house_spec;
bool was_completed; ///< whether house was completed before destruction bool was_completed; ///< whether house was completed before destruction
}; };
@@ -55,6 +60,7 @@ struct HouseCleared {
struct HouseCompleted { struct HouseCompleted {
Town *town; Town *town;
TileIndex tile; TileIndex tile;
HouseID house_id;
const HouseSpec *house_spec; const HouseSpec *house_spec;
}; };
@@ -100,6 +106,13 @@ struct CompanyBalanceChanged {
Money delta; Money delta;
}; };
enum class Slot : uint8 {
GOAL = 10,
CONTROLLER = 20,
GAME = 30,
CONTROLLER_POST = 40,
RECORDER = 50,
};
class TypeDispatcherBase { class TypeDispatcherBase {
public: public:
@@ -115,14 +128,16 @@ public:
TypeDispatcher() { } TypeDispatcher() { }
virtual ~TypeDispatcher() {} virtual ~TypeDispatcher() {}
void listen(Handler &handler) { void listen(Slot slot, Handler &handler) {
this->new_handlers.push_back(handler); this->handler_map.insert(std::make_pair(slot, handler));
} }
void emit(const T &event) { void emit(const T &event) {
if (!this->new_handlers.empty()) { if (this->new_handlers) { // only rebuild handlers while not iterating
this->handlers.insert(this->handlers.end(), this->new_handlers.begin(), this->new_handlers.end()); this->handlers.clear();
this->new_handlers.clear(); for (auto &p : this->handler_map) {
this->handlers.push_back(p.second);
}
} }
for (auto &h : this->handlers) { for (auto &h : this->handlers) {
h(event); h(event);
@@ -131,7 +146,8 @@ public:
protected: protected:
std::vector<Handler> handlers; std::vector<Handler> handlers;
std::vector<Handler> new_handlers; std::multimap<Slot, Handler> handler_map;
bool new_handlers = false;
}; };
@@ -151,8 +167,8 @@ protected:
public: public:
template<typename T> template<typename T>
void listen(std::function<void(const T &)> handler) { void listen(Slot slot, std::function<void(const T &)> handler) {
this->get_dispatcher<T>().listen(handler); this->get_dispatcher<T>().listen(slot, handler);
} }
template<typename T> template<typename T>

View File

@@ -9,7 +9,7 @@
namespace citymania { namespace citymania {
Game::Game() { Game::Game() {
this->events.listen<event::NewMonth>([this] (const event::NewMonth &) { this->events.listen<event::NewMonth>(event::Slot::GAME, [this] (const event::NewMonth &) {
for (Town *t : Town::Iterate()) { for (Town *t : Town::Iterate()) {
t->cm.hs_last_month = t->cm.hs_total - t->cm.hs_total_prev; 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.hs_total_prev = t->cm.hs_total;
@@ -28,45 +28,45 @@ Game::Game() {
this->towns_growth_tiles.clear(); this->towns_growth_tiles.clear();
}); });
this->events.listen<event::TownGrowthSucceeded>([this] (const event::TownGrowthSucceeded &event) { this->events.listen<event::TownGrowthSucceeded>(event::Slot::GAME, [this] (const event::TownGrowthSucceeded &event) {
if (event.town->cache.num_houses <= event.prev_houses) { if (event.town->cache.num_houses <= event.prev_houses) {
event.town->cm.hs_total++; event.town->cm.hs_total++;
this->towns_growth_tiles[event.tile] = TownGrowthTileState::HS; this->set_town_growth_tile(event.tile, TownGrowthTileState::HS);
} }
}); });
this->events.listen<event::TownGrowthFailed>([this] (const event::TownGrowthFailed &event) { this->events.listen<event::TownGrowthFailed>(event::Slot::GAME, [this] (const event::TownGrowthFailed &event) {
event.town->cm.cs_total++; event.town->cm.cs_total++;
this->towns_growth_tiles[event.tile] = TownGrowthTileState::CS; this->set_town_growth_tile(event.tile, TownGrowthTileState::CS);
}); });
this->events.listen<event::HouseRebuilt>([this] (const event::HouseRebuilt &event) { this->events.listen<event::HouseRebuilt>(event::Slot::GAME, [this] (const event::HouseRebuilt &event) {
if (event.was_successful) { if (event.was_successful) {
event.town->cm.houses_reconstructed_this_month++; event.town->cm.houses_reconstructed_this_month++;
this->towns_growth_tiles[event.tile] = TownGrowthTileState::RH_REBUILT; this->set_town_growth_tile(event.tile, TownGrowthTileState::RH_REBUILT);
} else { } else {
event.town->cm.houses_demolished_this_month++; event.town->cm.houses_demolished_this_month++;
this->towns_growth_tiles[event.tile] = TownGrowthTileState::RH_REMOVED; this->set_town_growth_tile(event.tile, TownGrowthTileState::RH_REMOVED);
} }
}); });
this->events.listen<event::HouseBuilt>([this] (const event::HouseBuilt &event) { this->events.listen<event::HouseBuilt>(event::Slot::GAME, [this] (const event::HouseBuilt &event) {
event.town->cm.houses_constructing++; event.town->cm.houses_constructing++;
event.town->cm.real_population += event.house_spec->population; event.town->cm.real_population += event.house_spec->population;
this->towns_growth_tiles[event.tile] = TownGrowthTileState::NEW_HOUSE; this->set_town_growth_tile(event.tile, TownGrowthTileState::NEW_HOUSE);
}); });
this->events.listen<event::HouseCleared>([this] (const event::HouseCleared &event) { this->events.listen<event::HouseCleared>(event::Slot::GAME, [this] (const event::HouseCleared &event) {
if (!event.was_completed) if (!event.was_completed)
event.town->cm.houses_constructing--; event.town->cm.houses_constructing--;
event.town->cm.real_population -= event.house_spec->population; event.town->cm.real_population -= event.house_spec->population;
}); });
this->events.listen<event::HouseCompleted>([this] (const event::HouseCompleted &event) { this->events.listen<event::HouseCompleted>(event::Slot::GAME, [this] (const event::HouseCompleted &event) {
event.town->cm.houses_constructing--; event.town->cm.houses_constructing--;
}); });
this->events.listen<event::TownCachesRebuilt>([this] (const event::TownCachesRebuilt &event) { this->events.listen<event::TownCachesRebuilt>(event::Slot::GAME, [this] (const event::TownCachesRebuilt &event) {
for (Town *town : Town::Iterate()) { for (Town *town : Town::Iterate()) {
town->cm.real_population = 0; town->cm.real_population = 0;
town->cm.houses_constructing = 0; town->cm.houses_constructing = 0;
@@ -81,9 +81,13 @@ Game::Game() {
} }
}); });
this->events.listen<event::CargoAccepted>([this] (const event::CargoAccepted &event) { this->events.listen<event::CargoAccepted>(event::Slot::GAME, [this] (const event::CargoAccepted &event) {
event.company->cur_economy.cm.cargo_income[event.cargo_type] += event.profit; event.company->cur_economy.cm.cargo_income[event.cargo_type] += event.profit;
}); });
} }
void Game::set_town_growth_tile(TileIndex tile, TownGrowthTileState state) {
if (this->towns_growth_tiles[tile] < state) this->towns_growth_tiles[tile] = state;
}
} // namespace citymania } // namespace citymania

View File

@@ -1,5 +1,5 @@
#ifndef CMEXT_GAME_HPP #ifndef CM_GAME_HPP
#define CMEXT_GAME_HPP #define CM_GAME_HPP
#include "../town.h" #include "../town.h"
@@ -20,13 +20,14 @@ enum class TownGrowthTileState : uint8 {
class Game { class Game {
public: public:
event::Dispatcher events;
typedef std::map<TileIndex, TownGrowthTileState> TownsGrowthTilesIndex; typedef std::map<TileIndex, TownGrowthTileState> TownsGrowthTilesIndex;
TownsGrowthTilesIndex towns_growth_tiles_last_month; TownsGrowthTilesIndex towns_growth_tiles_last_month;
TownsGrowthTilesIndex towns_growth_tiles; TownsGrowthTilesIndex towns_growth_tiles;
event::Dispatcher events;
Game(); Game();
void set_town_growth_tile(TileIndex tile, TownGrowthTileState state);
TownGrowthTileState get_town_growth_tile(TileIndex tile) { TownGrowthTileState get_town_growth_tile(TileIndex tile) {
auto a = this->towns_growth_tiles.find(tile); auto a = this->towns_growth_tiles.find(tile);

View File

@@ -16,7 +16,7 @@ void ResetGame() {
} }
void SwitchToMode(SwitchMode new_mode) { void SwitchToMode(SwitchMode new_mode) {
ResetGame(); if (new_mode != SM_SAVE_GAME) ResetGame();
} }
void ToggleSmallMap() { void ToggleSmallMap() {

View File

@@ -8,6 +8,7 @@
#include "cm_bitstream.hpp" #include "cm_bitstream.hpp"
#include "cm_saveload.hpp" #include "cm_saveload.hpp"
#include "cm_settings.hpp"
#include "cm_game.hpp" #include "cm_game.hpp"
#include "cm_main.hpp" #include "cm_main.hpp"
@@ -116,7 +117,8 @@ void CBController_saveload_encode(BitOStream &bs) {
bs.WriteBytes(0 /* version */, 2); bs.WriteBytes(0 /* version */, 2);
// Controller::saveload_encode(bs); // Controller::saveload_encode(bs);
bs.WriteBytes(0, 1); bs.WriteBytes(0, 1);
bs.WriteBytes(_settings_client.gui.cb_distance_check, 1); bs.WriteBytes(0, 1);
// bs.WriteBytes(_settings_client.gui.cb_distance_check, 1);
bs.WriteBytes(0, 1); bs.WriteBytes(0, 1);
bs.WriteBytes(0, 1); bs.WriteBytes(0, 1);
bs.WriteBytes(0, 1); bs.WriteBytes(0, 1);
@@ -124,43 +126,43 @@ void CBController_saveload_encode(BitOStream &bs) {
bs.WriteBytes(0, 1); bs.WriteBytes(0, 1);
bs.WriteBytes(0, 1); bs.WriteBytes(0, 1);
std::vector<CargoID> cb_cargos; std::vector<CargoID> cb_cargos;
for(CargoID cargo = 0; cargo < NUM_CARGO; cargo++) { // for(CargoID cargo = 0; cargo < NUM_CARGO; cargo++) {
if (CB_GetReq(cargo) > 0) // if (CB_GetReq(cargo) > 0)
cb_cargos.push_back(cargo); // cb_cargos.push_back(cargo);
} // }
for (auto cargo_id : cb_cargos) { // for (auto cargo_id : cb_cargos) {
// bs.WriteBytes(req.cargo_id, 1); // // bs.WriteBytes(req.cargo_id, 1);
// bs.WriteBytes(req.amount, 4); // // bs.WriteBytes(req.amount, 4);
// bs.WriteBytes(req.from, 4); // // bs.WriteBytes(req.from, 4);
// bs.WriteBytes(req.decay, 1); // // bs.WriteBytes(req.decay, 1);
bs.WriteBytes(cargo_id, 1); // bs.WriteBytes(cargo_id, 1);
bs.WriteBytes(CB_GetReq(cargo_id), 4); // bs.WriteBytes(CB_GetReq(cargo_id), 4);
bs.WriteBytes(CB_GetFrom(cargo_id), 4); // bs.WriteBytes(CB_GetFrom(cargo_id), 4);
bs.WriteBytes(CB_GetDecay(cargo_id), 1); // bs.WriteBytes(CB_GetDecay(cargo_id), 1);
} // }
// uint16 cb_towns = 0; // // uint16 cb_towns = 0;
// ForEachCBTown([this, &cb_towns](Town *, Company *) { cb_towns++; }); // // ForEachCBTown([this, &cb_towns](Town *, Company *) { cb_towns++; });
bs.WriteBytes(Town::GetNumItems(), 2); // bs.WriteBytes(Town::GetNumItems(), 2);
for (Town *t : Town::Iterate()) { // for (Town *t : Town::Iterate()) {
auto &tcb = t->cb; // auto &tcb = t->cb;
bs.WriteBytes(t->index, 2); // bs.WriteBytes(t->index, 2);
bs.WriteBytes(tcb.pax_delivered, 4); // bs.WriteBytes(tcb.pax_delivered, 4);
bs.WriteBytes(tcb.mail_delivered, 4); // bs.WriteBytes(tcb.mail_delivered, 4);
bs.WriteBytes(tcb.pax_delivered_last_month, 4); // bs.WriteBytes(tcb.pax_delivered_last_month, 4);
bs.WriteBytes(tcb.mail_delivered_last_month, 4); // bs.WriteBytes(tcb.mail_delivered_last_month, 4);
bs.WriteBytes((uint8)tcb.growth_state, 1); // bs.WriteBytes((uint8)tcb.growth_state, 1);
bs.WriteBytes(tcb.shrink_effeciency, 1); // bs.WriteBytes(tcb.shrink_effeciency, 1);
bs.WriteBytes(tcb.shrink_rate, 2); // bs.WriteBytes(tcb.shrink_rate, 2);
bs.WriteBytes(tcb.shrink_counter, 2); // bs.WriteBytes(tcb.shrink_counter, 2);
for (auto cargo_id : cb_cargos) { // for (auto cargo_id : cb_cargos) {
bs.WriteBytes(tcb.stored[cargo_id], 4); // bs.WriteBytes(tcb.stored[cargo_id], 4);
bs.WriteBytes(tcb.delivered[cargo_id], 4); // bs.WriteBytes(tcb.delivered[cargo_id], 4);
bs.WriteBytes(tcb.required[cargo_id], 4); // bs.WriteBytes(tcb.required[cargo_id], 4);
bs.WriteBytes(tcb.delivered_last_month[cargo_id], 4); // bs.WriteBytes(tcb.delivered_last_month[cargo_id], 4);
bs.WriteBytes(tcb.required_last_month[cargo_id], 4); // bs.WriteBytes(tcb.required_last_month[cargo_id], 4);
} // }
} // }
} }
bool CBController_saveload_decode(BitIStream &bs) { bool CBController_saveload_decode(BitIStream &bs) {
@@ -171,7 +173,8 @@ bool CBController_saveload_decode(BitIStream &bs) {
// if (!Controller::saveload_decode(bs)) // if (!Controller::saveload_decode(bs))
// return false; // return false;
bs.ReadBytes(1); /* _settings_game.citymania.cb.requirements_type */ bs.ReadBytes(1); /* _settings_game.citymania.cb.requirements_type */
_settings_client.gui.cb_distance_check = bs.ReadBytes(1); /* _settings_game.citymania.cb.acceptance_range */ bs.ReadBytes(1); /* _settings_game.citymania.cb.acceptance_range */
// _settings_client.gui.cb_distance_check = bs.ReadBytes(1); /* _settings_game.citymania.cb.acceptance_range */
bs.ReadBytes(1); /* _settings_game.citymania.cb.storage_size */ bs.ReadBytes(1); /* _settings_game.citymania.cb.storage_size */
bs.ReadBytes(1); /* _settings_game.citymania.cb.town_protection_range */ bs.ReadBytes(1); /* _settings_game.citymania.cb.town_protection_range */
bs.ReadBytes(2); /* _settings_game.citymania.cb.claim_max_houses */ bs.ReadBytes(2); /* _settings_game.citymania.cb.claim_max_houses */
@@ -191,7 +194,7 @@ bool CBController_saveload_decode(BitIStream &bs) {
auto required = bs.ReadBytes(4); auto required = bs.ReadBytes(4);
auto from = bs.ReadBytes(4); auto from = bs.ReadBytes(4);
auto decay = bs.ReadBytes(1); auto decay = bs.ReadBytes(1);
CB_SetRequirements(cargo_id, required, from, decay); // CB_SetRequirements(cargo_id, required, from, decay);
// _settings_game.citymania.cb.requirements.push_back(CBRequirement(cargo_id, from, required, decay, i, "")); // _settings_game.citymania.cb.requirements.push_back(CBRequirement(cargo_id, from, required, decay, i, ""));
} }
@@ -205,28 +208,54 @@ bool CBController_saveload_decode(BitIStream &bs) {
return false; return false;
} }
auto &tcb = t->cb; // auto &tcb = t->cb;
tcb.pax_delivered = bs.ReadBytes(4); // tcb.pax_delivered = bs.ReadBytes(4);
tcb.mail_delivered = bs.ReadBytes(4); // tcb.mail_delivered = bs.ReadBytes(4);
tcb.pax_delivered_last_month = bs.ReadBytes(4); // tcb.pax_delivered_last_month = bs.ReadBytes(4);
tcb.mail_delivered_last_month = bs.ReadBytes(4); // tcb.mail_delivered_last_month = bs.ReadBytes(4);
tcb.growth_state = (TownGrowthState)bs.ReadBytes(1); // tcb.growth_state = (TownGrowthState)bs.ReadBytes(1);
tcb.shrink_effeciency = bs.ReadBytes(1); // tcb.shrink_effeciency = bs.ReadBytes(1);
tcb.shrink_rate = bs.ReadBytes(2); // tcb.shrink_rate = bs.ReadBytes(2);
tcb.shrink_counter = bs.ReadBytes(2); // tcb.shrink_counter = bs.ReadBytes(2);
for (auto cargo_id : cb_cargos) { // for (auto cargo_id : cb_cargos) {
tcb.stored[cargo_id] = bs.ReadBytes(4); // tcb.stored[cargo_id] = bs.ReadBytes(4);
tcb.delivered[cargo_id] = bs.ReadBytes(4); // tcb.delivered[cargo_id] = bs.ReadBytes(4);
tcb.required[cargo_id] = bs.ReadBytes(4); // tcb.required[cargo_id] = bs.ReadBytes(4);
tcb.delivered_last_month[cargo_id] = bs.ReadBytes(4); // tcb.delivered_last_month[cargo_id] = bs.ReadBytes(4);
tcb.required_last_month[cargo_id] = bs.ReadBytes(4); // tcb.required_last_month[cargo_id] = bs.ReadBytes(4);
} // }
}; };
return true; return true;
} }
uint8 _controller_type = 0; void EncodeSettings(BitOStream &bs, Settings &settings) {
uint8 _game_type = 0; bs.WriteBytes(settings.max_players_in_company, 1);
bs.WriteBytes(settings.destroyed_houses_per_month, 2);
bs.WriteBytes(settings.game_length_years, 2);
bs.WriteBytes(settings.protect_funded_industries, 1);
bs.WriteBytes(settings.same_depot_sell_years, 2);
bs.WriteBytes(settings.economy.cashback_for_extra_land_clear, 1);
bs.WriteBytes(settings.economy.cashback_for_bridges_and_tunnels, 1);
bs.WriteBytes(settings.economy.cashback_for_foundations, 1);
bs.WriteBytes(settings.limits.max_airports, 2);
bs.WriteBytes(settings.limits.disable_canals, 1);
bs.WriteBytes(settings.limits.min_distance_between_docks, 2);
}
void DecodeSettings(BitIStream &bs, Settings &settings) {
settings.max_players_in_company = bs.ReadBytes(1);
settings.destroyed_houses_per_month = bs.ReadBytes(2);
settings.game_length_years = bs.ReadBytes(2);
settings.protect_funded_industries = bs.ReadBytes(1);
settings.same_depot_sell_years = bs.ReadBytes(2);
settings.economy.cashback_for_extra_land_clear = bs.ReadBytes(1);
settings.economy.cashback_for_bridges_and_tunnels = bs.ReadBytes(1);
settings.economy.cashback_for_foundations = bs.ReadBytes(1);
settings.limits.max_airports = bs.ReadBytes(2);
settings.limits.disable_canals = bs.ReadBytes(1);
settings.limits.min_distance_between_docks = bs.ReadBytes(2);
}
uint16 _last_client_version = 1512; uint16 _last_client_version = 1512;
static u8vector EncodeData() { static u8vector EncodeData() {
@@ -234,37 +263,39 @@ static u8vector EncodeData() {
bs.Reserve(1000); bs.Reserve(1000);
bs.WriteBytes(SAVEGAME_DATA_FORMAT_VERSION, 2); bs.WriteBytes(SAVEGAME_DATA_FORMAT_VERSION, 2);
bs.WriteBytes(_last_client_version, 2); bs.WriteBytes(_last_client_version, 2);
bs.WriteBytes(_controller_type, 1); bs.WriteBytes(_settings_game.citymania.controller_type, 1);
bs.WriteBytes(_date, 4); // Just in case we'll need to detect that game bs.WriteBytes(_date, 4); // Just in case we'll need to detect that game
bs.WriteBytes(_date_fract, 1); // was saved by unmodified client bs.WriteBytes(_date_fract, 1); // was saved by unmodified client
bs.WriteBytes(_game_type, 1); bs.WriteBytes(_settings_game.citymania.game_type, 1);
bs.WriteBytes(0, 3); // Reserved bs.WriteBytes(0, 3); // Reserved
bs.WriteBytes(0, 4); // Reserved bs.WriteBytes(0, 4); // Reserved
EncodeSettings(bs, _settings_game.citymania);
EncodeCompanies(bs); EncodeCompanies(bs);
EncodeTowns(bs); EncodeTowns(bs);
EncodeTownsGrowthTiles(bs, _game->towns_growth_tiles); EncodeTownsGrowthTiles(bs, _game->towns_growth_tiles);
EncodeTownsGrowthTiles(bs, _game->towns_growth_tiles_last_month); EncodeTownsGrowthTiles(bs, _game->towns_growth_tiles_last_month);
if (_controller_type == 4) if (_settings_game.citymania.controller_type == 4)
CBController_saveload_encode(bs); CBController_saveload_encode(bs);
return bs.GetVector(); return bs.GetVector();
} }
static void DecodeDataV2(BitIStream &bs) { static void DecodeDataV2(BitIStream &bs) {
DecodeSettings(bs, _settings_game.citymania);
DecodeCompanies(bs); DecodeCompanies(bs);
DecodeTowns(bs); DecodeTowns(bs);
DecodeTownsGrowthTiles(bs, _game->towns_growth_tiles); DecodeTownsGrowthTiles(bs, _game->towns_growth_tiles);
DecodeTownsGrowthTiles(bs, _game->towns_growth_tiles_last_month); DecodeTownsGrowthTiles(bs, _game->towns_growth_tiles_last_month);
if (_controller_type == 4) CBController_saveload_decode(bs); if (_settings_game.citymania.controller_type == 4) CBController_saveload_decode(bs);
} }
static void DecodeTownsCargoV1(BitIStream &bs) static void DecodeTownsCargoV1(BitIStream &bs)
{ {
CB_SetStorage(bs.ReadBytes(1)); bs.ReadBytes(1);bs.ReadBytes(1);
_settings_client.gui.cb_distance_check = bs.ReadBytes(1); // CB_SetStorage(bs.ReadBytes(1));
// _settings_client.gui.cb_distance_check = bs.ReadBytes(1);
uint n_cb_cargos = bs.ReadBytes(1); uint n_cb_cargos = bs.ReadBytes(1);
CB_ResetRequirements(); // CB_ResetRequirements();
std::vector<CargoID> cb_cargos; std::vector<CargoID> cb_cargos;
for (uint i = 0; i < n_cb_cargos; i++) { for (uint i = 0; i < n_cb_cargos; i++) {
uint cargo = bs.ReadBytes(1); uint cargo = bs.ReadBytes(1);
@@ -276,7 +307,7 @@ static void DecodeTownsCargoV1(BitIStream &bs)
uint req = bs.ReadBytes(4); uint req = bs.ReadBytes(4);
uint from = bs.ReadBytes(4); uint from = bs.ReadBytes(4);
uint decay = bs.ReadBytes(1); uint decay = bs.ReadBytes(1);
CB_SetRequirements(cargo, req, from, decay); // CB_SetRequirements(cargo, req, from, decay);
} }
Town *t; Town *t;
uint n_affected_towns = bs.ReadBytes(2); uint n_affected_towns = bs.ReadBytes(2);
@@ -287,21 +318,21 @@ static void DecodeTownsCargoV1(BitIStream &bs)
DEBUG(sl, 0, "Invalid TownID in CB towns cargo data (%u)", town_id); DEBUG(sl, 0, "Invalid TownID in CB towns cargo data (%u)", town_id);
return; return;
} }
auto &tcb = t->cb; // auto &tcb = t->cb;
for (auto cargo_id : cb_cargos) { // for (auto cargo_id : cb_cargos) {
tcb.stored[cargo_id] = bs.ReadBytes(4); // tcb.stored[cargo_id] = bs.ReadBytes(4);
tcb.delivered_last_month[cargo_id] = bs.ReadBytes(4); // tcb.delivered_last_month[cargo_id] = bs.ReadBytes(4);
tcb.delivered[cargo_id] = bs.ReadBytes(4); // tcb.delivered[cargo_id] = bs.ReadBytes(4);
bs.ReadBytes(1); /* delivered enough */ // bs.ReadBytes(1); /* delivered enough */
tcb.required[cargo_id] = 0; // tcb.required[cargo_id] = 0;
tcb.required_last_month[cargo_id] = 0; // tcb.required_last_month[cargo_id] = 0;
} // }
} }
} }
static void DecodeDataV1(BitIStream &bs) { static void DecodeDataV1(BitIStream &bs) {
if (_controller_type != 0) DecodeTownsCargoV1(bs); if (_settings_game.citymania.controller_type != 0) DecodeTownsCargoV1(bs);
for (Town *t : Town::Iterate()) { for (Town *t : Town::Iterate()) {
t->cm.growing_by_chance = bs.ReadBytes(1); t->cm.growing_by_chance = bs.ReadBytes(1);
t->cm.houses_reconstructed_this_month = bs.ReadBytes(2); t->cm.houses_reconstructed_this_month = bs.ReadBytes(2);
@@ -348,15 +379,15 @@ static void DecodeData(u8vector &data) {
} }
DEBUG(sl, 2, "CityMania savegame data version %u", version); DEBUG(sl, 2, "CityMania savegame data version %u", version);
_last_client_version = bs.ReadBytes(2); _last_client_version = bs.ReadBytes(2);
_controller_type = bs.ReadBytes(1); _settings_game.citymania.controller_type = bs.ReadBytes(1);
if (version <= 1) _controller_type = (_controller_type ? 4 : 0); if (version <= 1) _settings_game.citymania.controller_type = (_settings_game.citymania.controller_type ? 4 : 0);
int32 date = bs.ReadBytes(4); int32 date = bs.ReadBytes(4);
uint32 date_fract = bs.ReadBytes(1); uint32 date_fract = bs.ReadBytes(1);
if (date != _date || date_fract != _date_fract) { if (date != _date || date_fract != _date_fract) {
DEBUG(sl, 0, "Savegame was run in unmodified client, extra save data " DEBUG(sl, 0, "Savegame was run in unmodified client, extra save data "
"preserved, but may not be accurate"); "preserved, but may not be accurate");
} }
_game_type = bs.ReadBytes(1); _settings_game.citymania.game_type = bs.ReadBytes(1);
bs.ReadBytes(3); // reserved bs.ReadBytes(3); // reserved
bs.ReadBytes(4); // reserved bs.ReadBytes(4); // reserved
if (version == 1) DecodeDataV1(bs); if (version == 1) DecodeDataV1(bs);

View File

@@ -0,0 +1,69 @@
#ifndef CM_SETTINGS_HPP
#define CM_SETTINGS_HPP
#include <memory>
#include <vector>
// #include "types.hpp"
namespace citymania {
class CBRequirement {
public:
CargoID cargo_id;
uint32 from;
uint32 amount;
uint8 decay;
uint8 index;
std::string name;
bool has_storage;
static CBRequirement Parse(const char *name, const char *value, uint8 index);
CBRequirement(CargoID cargo_id, uint32 from, uint32 amount, uint8 decay,
uint8 index, std::string name)
:cargo_id{cargo_id}, from{from}, amount{amount}, decay{decay},
index{index}, name{name}, has_storage{decay < 100} {}
};
struct EconomySettings {
bool cashback_for_extra_land_clear;
bool cashback_for_bridges_and_tunnels;
bool cashback_for_foundations;
};
struct LimitsSettings {
uint16 max_airports; ///< maximum number of airports per company, 0=unlimited
bool disable_canals;
uint16 min_distance_between_docks; ///< docks can be build only x tiles apart another, 0=disable check
};
struct CBSettings {
uint8 requirements_type; // 0 - regular 1 - income-based requirements (new cb only)
std::vector<CBRequirement> requirements;
uint8 acceptance_range; // How far can station be to count towards requiremnts
uint8 storage_size; // cargo storage multiplier (x * monthly requirements)
uint8 town_protection_range; // Claimed town protection range (square from centre), overlaped with tz0
uint16 claim_max_houses; // Max amount of houses claimable town can have
bool smooth_growth_rate; // Calculate growth rate precisely instead of rounding to 50 houses and allow going below 70 ticks (default max)
bool allow_negative_growth; // Make town shrink (with the same speed as growth) if requirements aren't satisfied
};
struct Settings {
CBSettings cb;
EconomySettings economy;
LimitsSettings limits;
uint8 game_type; // GameType
uint8 controller_type; // ControllerType
uint8 max_players_in_company;
uint16 destroyed_houses_per_month; // max amount of houses a company can destroy per month
uint16 game_length_years; // game length in years(0 = disabled)
bool protect_funded_industries;
uint16 same_depot_sell_years; // can only sell vehicles in the same place (20 tiles radius) for first x yearss of its lifetime (0 = disabled)
};
}; // namespace citymania
#endif

View File

@@ -18,7 +18,7 @@ public:
bool is_scored; ///< whether company is eligible for scoring bool is_scored; ///< whether company is eligible for scoring
}; };
} // namespace ext } // namespace citymania
} // namespace citymania } // namespace citymania

View File

@@ -20,6 +20,8 @@
#include "zoom_type.h" #include "zoom_type.h"
#include "openttd.h" #include "openttd.h"
#include "citymania/cm_settings.hpp"
/** Settings profiles and highscore tables. */ /** Settings profiles and highscore tables. */
enum SettingsProfile { enum SettingsProfile {
@@ -585,6 +587,8 @@ struct GameSettings {
LinkGraphSettings linkgraph; ///< settings for link graph calculations LinkGraphSettings linkgraph; ///< settings for link graph calculations
StationSettings station; ///< settings related to station management StationSettings station; ///< settings related to station management
LocaleSettings locale; ///< settings related to used currency/unit system in the current game LocaleSettings locale; ///< settings related to used currency/unit system in the current game
citymania::Settings citymania;
}; };
/** All settings that are only important for the local client. */ /** All settings that are only important for the local client. */

View File

@@ -258,7 +258,7 @@ enum TownGrowthResult {
// GROWTH_SEARCH_RUNNING >= 1 // GROWTH_SEARCH_RUNNING >= 1
}; };
static bool BuildTownHouse(Town *t, TileIndex tile); static bool BuildTownHouse(Town *t, TileIndex tile, bool is_rebuilding = false);
static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size, bool city, TownLayout layout); static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size, bool city, TownLayout layout);
static void TownDrawHouseLift(const TileInfo *ti) static void TownDrawHouseLift(const TileInfo *ti)
@@ -537,7 +537,7 @@ static void MakeSingleHouseBigger(TileIndex tile)
ResetHouseAge(tile); ResetHouseAge(tile);
if (hs->building_flags & BUILDING_HAS_1_TILE) if (hs->building_flags & BUILDING_HAS_1_TILE)
citymania::Emit(citymania::event::HouseCompleted{town, tile, hs}); citymania::Emit(citymania::event::HouseCompleted{town, tile, house_id, hs});
} }
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} }
@@ -673,7 +673,7 @@ static void TileLoop_Town(TileIndex tile)
/* Rebuild with another house? */ /* Rebuild with another house? */
bool rebuild_res = false; bool rebuild_res = false;
if (GB(r, 24, 8) >= 12) rebuild_res = BuildTownHouse(t, tile); if (GB(r, 24, 8) >= 12) rebuild_res = BuildTownHouse(t, tile, true);
citymania::Emit(citymania::event::HouseRebuilt{t, tile, rebuild_res}); citymania::Emit(citymania::event::HouseRebuilt{t, tile, rebuild_res});
} }
@@ -2745,7 +2745,7 @@ static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, int maxz, bool nosl
* @param tile where the house will be built * @param tile where the house will be built
* @return false iff no house can be built at this tile * @return false iff no house can be built at this tile
*/ */
static bool BuildTownHouse(Town *t, TileIndex tile) static bool BuildTownHouse(Town *t, TileIndex tile, bool is_rebuilding)
{ {
/* forbidden building here by town layout */ /* forbidden building here by town layout */
if (!TownLayoutAllowsHouseHere(t, tile)) return false; if (!TownLayoutAllowsHouseHere(t, tile)) return false;
@@ -2894,8 +2894,10 @@ static bool BuildTownHouse(Town *t, TileIndex tile)
UpdateTownGrowthRate(t); UpdateTownGrowthRate(t);
UpdateTownCargoes(t, tile); UpdateTownCargoes(t, tile);
citymania::Emit(citymania::event::HouseBuilt{t, tile, hs}); if (!_generating_world) {
if (completed) citymania::Emit(citymania::event::HouseCompleted{t, tile, hs}); citymania::Emit(citymania::event::HouseBuilt{t, tile, house, hs, is_rebuilding});
if (completed) citymania::Emit(citymania::event::HouseCompleted{t, tile, house, hs});
}
return true; return true;
} }
@@ -2986,7 +2988,7 @@ void ClearTownHouse(Town *t, TileIndex tile)
/* Update cargo acceptance. */ /* Update cargo acceptance. */
UpdateTownCargoes(t, tile); UpdateTownCargoes(t, tile);
citymania::Emit(citymania::event::HouseCleared{t, tile, hs, is_completed}); citymania::Emit(citymania::event::HouseCleared{t, tile, house, hs, is_completed});
} }
/** /**