Move road layout error counters to cmbase

This commit is contained in:
dP
2020-06-10 02:10:01 +03:00
22 changed files with 438 additions and 70 deletions

14
.gitignore vendored
View File

@@ -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

View File

@@ -1373,6 +1373,13 @@
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
<ClCompile Include="..\src\os\windows\win32.cpp" />
<ClInclude Include="..\src\thread.h" />
<ClInclude Include="..\src\citymania\cm_event.hpp" />
<ClInclude Include="..\src\citymania\cm_game.hpp" />
<ClCompile Include="..\src\citymania\cm_game.cpp" />
<ClInclude Include="..\src\citymania\cm_main.hpp" />
<ClCompile Include="..\src\citymania\cm_main.cpp" />
<ClInclude Include="..\src\citymania\cm_type.hpp" />
<ClInclude Include="..\src\citymania\extensions\cmext_town.hpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\media\openttd.ico" />

View File

@@ -103,6 +103,9 @@
<Filter Include="Threading">
<UniqueIdentifier>{c76ff9f1-1e62-46d8-8d55-000000000033}</UniqueIdentifier>
</Filter>
<Filter Include="CityMania">
<UniqueIdentifier>{c76ff9f1-1e62-46d8-8d55-000000000034}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\airport.cpp">
@@ -3210,6 +3213,27 @@
<ClInclude Include="..\src\thread.h">
<Filter>Threading</Filter>
</ClInclude>
<ClInclude Include="..\src\citymania\cm_event.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClInclude Include="..\src\citymania\cm_game.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClCompile Include="..\src\citymania\cm_game.cpp">
<Filter>CityMania</Filter>
</ClCompile>
<ClInclude Include="..\src\citymania\cm_main.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClCompile Include="..\src\citymania\cm_main.cpp">
<Filter>CityMania</Filter>
</ClCompile>
<ClInclude Include="..\src\citymania\cm_type.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClInclude Include="..\src\citymania\extensions\cmext_town.hpp">
<Filter>CityMania</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\media\openttd.ico" />

View File

@@ -1373,6 +1373,13 @@
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
<ClCompile Include="..\src\os\windows\win32.cpp" />
<ClInclude Include="..\src\thread.h" />
<ClInclude Include="..\src\citymania\cm_event.hpp" />
<ClInclude Include="..\src\citymania\cm_game.hpp" />
<ClCompile Include="..\src\citymania\cm_game.cpp" />
<ClInclude Include="..\src\citymania\cm_main.hpp" />
<ClCompile Include="..\src\citymania\cm_main.cpp" />
<ClInclude Include="..\src\citymania\cm_type.hpp" />
<ClInclude Include="..\src\citymania\extensions\cmext_town.hpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\media\openttd.ico" />

View File

@@ -103,6 +103,9 @@
<Filter Include="Threading">
<UniqueIdentifier>{c76ff9f1-1e62-46d8-8d55-000000000033}</UniqueIdentifier>
</Filter>
<Filter Include="CityMania">
<UniqueIdentifier>{c76ff9f1-1e62-46d8-8d55-000000000034}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\airport.cpp">
@@ -3210,6 +3213,27 @@
<ClInclude Include="..\src\thread.h">
<Filter>Threading</Filter>
</ClInclude>
<ClInclude Include="..\src\citymania\cm_event.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClInclude Include="..\src\citymania\cm_game.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClCompile Include="..\src\citymania\cm_game.cpp">
<Filter>CityMania</Filter>
</ClCompile>
<ClInclude Include="..\src\citymania\cm_main.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClCompile Include="..\src\citymania\cm_main.cpp">
<Filter>CityMania</Filter>
</ClCompile>
<ClInclude Include="..\src\citymania\cm_type.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClInclude Include="..\src\citymania\extensions\cmext_town.hpp">
<Filter>CityMania</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\media\openttd.ico" />

View File

@@ -1373,6 +1373,13 @@
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
<ClCompile Include="..\src\os\windows\win32.cpp" />
<ClInclude Include="..\src\thread.h" />
<ClInclude Include="..\src\citymania\cm_event.hpp" />
<ClInclude Include="..\src\citymania\cm_game.hpp" />
<ClCompile Include="..\src\citymania\cm_game.cpp" />
<ClInclude Include="..\src\citymania\cm_main.hpp" />
<ClCompile Include="..\src\citymania\cm_main.cpp" />
<ClInclude Include="..\src\citymania\cm_type.hpp" />
<ClInclude Include="..\src\citymania\extensions\cmext_town.hpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\media\openttd.ico" />

View File

@@ -103,6 +103,9 @@
<Filter Include="Threading">
<UniqueIdentifier>{c76ff9f1-1e62-46d8-8d55-000000000033}</UniqueIdentifier>
</Filter>
<Filter Include="CityMania">
<UniqueIdentifier>{c76ff9f1-1e62-46d8-8d55-000000000034}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\airport.cpp">
@@ -3210,6 +3213,27 @@
<ClInclude Include="..\src\thread.h">
<Filter>Threading</Filter>
</ClInclude>
<ClInclude Include="..\src\citymania\cm_event.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClInclude Include="..\src\citymania\cm_game.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClCompile Include="..\src\citymania\cm_game.cpp">
<Filter>CityMania</Filter>
</ClCompile>
<ClInclude Include="..\src\citymania\cm_main.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClCompile Include="..\src\citymania\cm_main.cpp">
<Filter>CityMania</Filter>
</ClCompile>
<ClInclude Include="..\src\citymania\cm_type.hpp">
<Filter>CityMania</Filter>
</ClInclude>
<ClInclude Include="..\src\citymania\extensions\cmext_town.hpp">
<Filter>CityMania</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\media\openttd.ico" />

View File

@@ -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

123
src/citymania/cm_event.hpp Normal file
View File

@@ -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 <functional>
#include <map>
#include <typeindex>
#include <typeinfo>
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<typename T>
class TypeDispatcher: public TypeDispatcherBase {
public:
typedef std::function<void(const T &)> 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<Handler> handlers;
std::vector<Handler> new_handlers;
};
class Dispatcher {
protected:
std::map<std::type_index, up<TypeDispatcherBase>> dispacthers;
template<typename T>
TypeDispatcher<T> &get_dispatcher() {
auto p = this->dispacthers.find(typeid(T));
if (p == this->dispacthers.end()) {
auto x = make_up<TypeDispatcher<T>>();
p = this->dispacthers.emplace_hint(p, typeid(T), std::move(x));
}
return *(static_cast<TypeDispatcher<T> *>((*p).second.get()));
}
public:
template<typename T>
void listen(std::function<void(const T &)> handler) {
this->get_dispatcher<T>().listen(handler);
}
template<typename T>
void emit(const T &event) {
this->get_dispatcher<T>().emit(event);
}
};
} // namespace event
} // namespace citymania
#endif

31
src/citymania/cm_game.cpp Normal file
View File

@@ -0,0 +1,31 @@
#include "../stdafx.h"
#include "cm_game.hpp"
#include "../safeguards.h"
namespace citymania {
Game::Game() {
this->events.listen<event::NewMonth>([] (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<event::TownGrowthTick>([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

19
src/citymania/cm_game.hpp Normal file
View File

@@ -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

20
src/citymania/cm_main.cpp Normal file
View File

@@ -0,0 +1,20 @@
#include "../stdafx.h"
#include "cm_main.hpp"
#include "../safeguards.h"
namespace citymania {
up<Game> _game = nullptr;
void ResetGame() {
_game = make_up<Game>();
}
void SwitchToMode(SwitchMode new_mode) {
ResetGame();
}
} // namespace citymania

20
src/citymania/cm_main.hpp Normal file
View File

@@ -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> _game;
void SwitchToMode(SwitchMode new_mode);
template <typename T>
void Emit(const T &event) {
_game->events.emit<T>(event);
}
} // namespace citymania
#endif

View File

@@ -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);

53
src/citymania/cm_type.hpp Normal file
View File

@@ -0,0 +1,53 @@
#ifndef CMEXT_TYPE_HPP
#define CMEXT_TYPE_HPP
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
/* C++14 implementation of make_unique */
namespace std {
template<class T> struct _Unique_if {
typedef unique_ptr<T> _Single_object;
};
template<class T> struct _Unique_if<T[]> {
typedef unique_ptr<T[]> _Unknown_bound;
};
template<class T, size_t N> struct _Unique_if<T[N]> {
typedef void _Known_bound;
};
template<class T, class... Args>
typename _Unique_if<T>::_Single_object
make_unique(Args&&... args) {
return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
template<class T>
typename _Unique_if<T>::_Unknown_bound
make_unique(size_t n) {
typedef typename remove_extent<T>::type U;
return unique_ptr<T>(new U[n]());
}
template<class T, class... Args>
typename _Unique_if<T>::_Known_bound
make_unique(Args&&...) = delete;
} // namespace std
namespace citymania {
// Make smart pointers easier to type
template<class T> using up=std::unique_ptr<T>;
template<class T> using sp=std::shared_ptr<T>;
template<class T> using wp=std::weak_ptr<T>;
template<typename T> const auto make_up = std::make_unique<T>;
template<typename T> const auto make_sp = std::make_shared<T>;
} // namespace citymania
#endif

View File

@@ -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

View File

@@ -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();
}

View File

@@ -69,6 +69,7 @@
#include "linkgraph/linkgraphschedule.h"
#include "citymania/highlight.hpp"
#include "citymania/cm_main.hpp"
#include <stdarg.h>
#include <system_error>
@@ -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 */

View File

@@ -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),

View File

@@ -23,6 +23,8 @@
#include <list>
#include <map>
#include "citymania/extensions/cmext_town.hpp"
template <typename T>
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<PersistentStorage *> psa_list;
citymania::ext::Town cm;
/**
* Creates a new town.
* @param tile center tile of the town

View File

@@ -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();

View File

@@ -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);
}