tron@2186: /* $Id$ */ tron@2186: rubidium@9111: /** @file town.h Base of the town class. */ belugas@6422: truelight@0: #ifndef TOWN_H truelight@0: #define TOWN_H truelight@0: matthijs@5216: #include "oldpool.h" skidd13@8796: #include "core/bitmath_func.hpp" rubidium@8131: #include "core/random_func.hpp" rubidium@8131: #include "cargo_type.h" rubidium@8138: #include "tile_type.h" rubidium@8140: #include "date_type.h" rubidium@8213: #include "town_type.h" rubidium@10208: #include "company_type.h" skidd13@8796: #include "settings_type.h" rubidium@8959: #include "strings_type.h" rubidium@9127: #include "viewport_type.h" belugas@9463: #include "economy_type.h" michi_cc@10270: #include "map_type.h" truelight@0: rubidium@5299: enum { maedhros@6332: HOUSE_NO_CLASS = 0, maedhros@6332: NEW_HOUSE_OFFSET = 110, maedhros@6332: HOUSE_MAX = 512, maedhros@6332: INVALID_TOWN = 0xFFFF, maedhros@6332: INVALID_HOUSE_ID = 0xFFFF, maedhros@6332: maedhros@6332: /* There can only be as many classes as there are new houses, plus one for maedhros@6332: * NO_CLASS, as the original houses don't have classes. */ maedhros@6332: HOUSE_CLASS_MAX = HOUSE_MAX - NEW_HOUSE_OFFSET + 1, maedhros@6332: }; maedhros@6332: maedhros@6332: enum BuildingFlags { maedhros@6332: TILE_NO_FLAG = 0, maedhros@6332: TILE_SIZE_1x1 = 1U << 0, maedhros@6332: TILE_NOT_SLOPED = 1U << 1, maedhros@6332: TILE_SIZE_2x1 = 1U << 2, maedhros@6332: TILE_SIZE_1x2 = 1U << 3, maedhros@6332: TILE_SIZE_2x2 = 1U << 4, maedhros@6332: BUILDING_IS_ANIMATED = 1U << 5, maedhros@6332: BUILDING_IS_CHURCH = 1U << 6, maedhros@6332: BUILDING_IS_STADIUM = 1U << 7, maedhros@6332: BUILDING_HAS_1_TILE = TILE_SIZE_1x1 | TILE_SIZE_2x1 | TILE_SIZE_1x2 | TILE_SIZE_2x2, maedhros@6332: BUILDING_2_TILES_X = TILE_SIZE_2x1 | TILE_SIZE_2x2, maedhros@6332: BUILDING_2_TILES_Y = TILE_SIZE_1x2 | TILE_SIZE_2x2, maedhros@6332: BUILDING_HAS_4_TILES = TILE_SIZE_2x2, maedhros@6332: }; maedhros@6332: maedhros@6332: DECLARE_ENUM_AS_BIT_SET(BuildingFlags) maedhros@6332: belugas@8308: enum HouseZonesBits { smatz@8814: HZB_BEGIN = 0, belugas@8308: HZB_TOWN_EDGE = 0, belugas@8308: HZB_TOWN_OUTSKIRT, belugas@8308: HZB_TOWN_OUTER_SUBURB, belugas@8308: HZB_TOWN_INNER_SUBURB, belugas@8308: HZB_TOWN_CENTRE, smatz@8814: HZB_END, belugas@8308: }; smatz@8814: assert_compile(HZB_END == 5); smatz@8814: smatz@8814: DECLARE_POSTFIX_INCREMENT(HouseZonesBits) belugas@8308: maedhros@6332: enum HouseZones { ///< Bit Value Meaning maedhros@6332: HZ_NOZNS = 0x0000, ///< 0 This is just to get rid of zeros, meaning none belugas@8308: HZ_ZON1 = 1U << HZB_TOWN_EDGE, ///< 0..4 1,2,4,8,10 which town zones the building can be built in, Zone1 been the further suburb belugas@8308: HZ_ZON2 = 1U << HZB_TOWN_OUTSKIRT, belugas@8308: HZ_ZON3 = 1U << HZB_TOWN_OUTER_SUBURB, belugas@8308: HZ_ZON4 = 1U << HZB_TOWN_INNER_SUBURB, belugas@8308: HZ_ZON5 = 1U << HZB_TOWN_CENTRE, ///< center of town maedhros@6332: HZ_ZONALL = 0x001F, ///< 1F This is just to englobe all above types at once maedhros@6332: HZ_SUBARTC_ABOVE = 0x0800, ///< 11 800 can appear in sub-arctic climate above the snow line maedhros@6332: HZ_TEMP = 0x1000, ///< 12 1000 can appear in temperate climate maedhros@6332: HZ_SUBARTC_BELOW = 0x2000, ///< 13 2000 can appear in sub-arctic climate below the snow line maedhros@6332: HZ_SUBTROPIC = 0x4000, ///< 14 4000 can appear in subtropical climate maedhros@6332: HZ_TOYLND = 0x8000 ///< 15 8000 can appear in toyland climate maedhros@6332: }; maedhros@6332: maedhros@6332: DECLARE_ENUM_AS_BIT_SET(HouseZones) maedhros@6332: maedhros@6332: enum HouseExtraFlags { maedhros@6332: NO_EXTRA_FLAG = 0, maedhros@6332: BUILDING_IS_HISTORICAL = 1U << 0, ///< this house will only appear during town generation in random games, thus the historical rubidium@10207: BUILDING_IS_PROTECTED = 1U << 1, ///< towns and AI will not remove this house, while human players will be able to maedhros@6332: SYNCHRONISED_CALLBACK_1B = 1U << 2, ///< synchronized callback 1B will be performed, on multi tile houses maedhros@6332: CALLBACK_1A_RANDOM_BITS = 1U << 3, ///< callback 1A needs random bits maedhros@6332: }; maedhros@6332: maedhros@6332: DECLARE_ENUM_AS_BIT_SET(HouseExtraFlags) maedhros@6332: maedhros@6332: struct BuildingCounts { maedhros@6332: uint8 id_count[HOUSE_MAX]; maedhros@6332: uint8 class_count[HOUSE_CLASS_MAX]; rubidium@5299: }; rubidium@5299: rubidium@7386: DECLARE_OLD_POOL(Town, Town, 3, 8000) rubidium@7386: rubidium@7386: struct Town : PoolItem { truelight@0: TileIndex xy; truelight@0: belugas@6422: /* Current population of people and amount of houses. */ skidd13@8707: uint32 num_houses; truelight@0: uint32 population; truelight@193: belugas@6422: /* Town name */ glx@6956: uint32 townnamegrfid; truelight@0: uint16 townnametype; truelight@0: uint32 townnameparts; peter1138@8258: char *name; truelight@193: belugas@6422: /* NOSAVE: Location of name sign, UpdateTownVirtCoord updates this. */ truelight@0: ViewportSign sign; truelight@193: belugas@6422: /* Makes sure we don't build certain house types twice. belugas@6422: * bit 0 = Building funds received belugas@6422: * bit 1 = CHURCH belugas@6422: * bit 2 = STADIUM */ truelight@0: byte flags12; truelight@0: belugas@9334: /* level of noise that all the airports are generating */ belugas@9334: uint16 noise_reached; belugas@9334: rubidium@10207: /* Which companies have a statue? */ truelight@0: byte statues; truelight@0: rubidium@10207: /* Company ratings as well as a mask that determines which companies have a rating. */ rubidium@10207: CompanyMask have_ratings; rubidium@10207: uint8 unwanted[MAX_COMPANIES]; ///< how many months companies aren't wanted by towns (bribe) rubidium@10207: CompanyByte exclusivity; ///< which company has exclusivity rubidium@10207: uint8 exclusive_counter; ///< months till the exclusivity expires rubidium@10207: int16 ratings[MAX_COMPANIES]; truelight@193: belugas@6422: /* Maximum amount of passengers and mail that can be transported. */ celestar@1377: uint32 max_pass; celestar@1377: uint32 max_mail; celestar@1377: uint32 new_max_pass; celestar@1377: uint32 new_max_mail; celestar@1377: uint32 act_pass; celestar@1377: uint32 act_mail; celestar@1377: uint32 new_act_pass; celestar@1377: uint32 new_act_mail; truelight@0: belugas@6422: /* Amount of passengers that were transported. */ truelight@0: byte pct_pass_transported; truelight@0: byte pct_mail_transported; truelight@0: belugas@6422: /* Amount of food and paper that was transported. Actually a bit mask would be enough. */ truelight@0: uint16 act_food; darkvater@4: uint16 act_water; truelight@0: uint16 new_act_food; darkvater@4: uint16 new_act_water; truelight@193: belugas@6422: /* Time until we rebuild a house. */ maedhros@6454: uint16 time_until_rebuild; truelight@0: belugas@6422: /* When to grow town next time. */ maedhros@6454: uint16 grow_counter; maedhros@6454: int16 growth_rate; truelight@0: belugas@6422: /* Fund buildings program in action? */ truelight@0: byte fund_buildings_months; truelight@193: belugas@6422: /* Fund road reconstruction in action? */ truelight@0: byte road_build_months; truelight@0: maedhros@6486: /* If this is a larger town, and should grow more quickly. */ maedhros@6486: bool larger_town; maedhros@6486: belugas@6422: /* NOSAVE: UpdateTownRadius updates this given the house count. */ rubidium@8943: uint32 squared_town_zone_radius[HZB_END]; maedhros@6332: belugas@6422: /* NOSAVE: The number of each type of building in the town. */ maedhros@6332: BuildingCounts building_counts; rubidium@7386: skidd13@8796: /* NOSAVE: The town specific road layout */ skidd13@8796: TownLayout layout; skidd13@8796: rubidium@7386: /** rubidium@7386: * Creates a new town rubidium@7386: */ rubidium@7386: Town(TileIndex tile = 0); rubidium@7386: rubidium@7386: /** Destroy the town */ rubidium@7386: ~Town(); rubidium@7386: rubidium@7496: inline bool IsValid() const { return this->xy != 0; } skidd13@8796: skidd13@8796: void InitializeLayout(); skidd13@8796: skidd13@8796: inline TownLayout GetActiveLayout() const; belugas@9334: belugas@9334: /** Calculate the max town noise belugas@9334: * The value is counted using the population divided by the content of the belugas@9334: * entry in town_noise_population corespondig to the town's tolerance. belugas@9334: * To this result, we add 3, which is the noise of the lowest airport. belugas@9334: * So user can at least buld that airport belugas@9334: * @return the maximum noise level the town will tolerate */ belugas@9334: inline uint16 MaxTownNoise() const { belugas@9334: if (this->population == 0) return 0; // no population? no noise belugas@9334: rubidium@9413: return ((this->population / _settings_game.economy.town_noise_population[_settings_game.difficulty.town_council_tolerance]) + 3); belugas@9334: } truelight@0: }; truelight@0: skidd13@8796: /** skidd13@8796: * Get the current valid layout for the town skidd13@8796: * @return the active layout for this town skidd13@8796: */ skidd13@8796: inline TownLayout Town::GetActiveLayout() const skidd13@8796: { rubidium@9413: return (_settings_game.economy.town_layout == TL_RANDOM) ? this->layout : _settings_game.economy.town_layout; skidd13@8796: } skidd13@8796: maedhros@6332: struct HouseSpec { maedhros@6332: /* Standard properties */ belugas@9450: Year min_year; ///< introduction year of the house belugas@9450: Year max_year; ///< last year it can be built maedhros@6332: byte population; ///< population (Zero on other tiles in multi tile house.) maedhros@6332: byte removal_cost; ///< cost multiplier for removing it rubidium@8959: StringID building_name; ///< building name maedhros@6332: uint16 remove_rating_decrease; ///< rating decrease if removed maedhros@6332: byte mail_generation; ///< mail generation multiplier (tile based, as the acceptances below) belugas@6341: byte cargo_acceptance[3]; ///< acceptance level for the cargo slots belugas@6341: CargoID accepts_cargo[3]; ///< 3 input cargo slots maedhros@6332: BuildingFlags building_flags; ///< some flags that describe the house (size, stadium etc...) maedhros@6332: HouseZones building_availability; ///< where can it be built (climates, zones) maedhros@6605: bool enabled; ///< the house is available to build (true by default, but can be disabled by newgrf) maedhros@6332: maedhros@6332: /* NewHouses properties */ maedhros@6605: HouseID substitute_id; ///< which original house this one is based on maedhros@6332: struct SpriteGroup *spritegroup; ///< pointer to the different sprites of the house maedhros@6332: HouseID override; ///< which house this one replaces maedhros@6332: uint16 callback_mask; ///< House callback flags maedhros@6332: byte random_colour[4]; ///< 4 "random" colours maedhros@6332: byte probability; ///< Relative probability of appearing (16 is the standard value) maedhros@6332: HouseExtraFlags extra_flags; ///< some more flags maedhros@6332: HouseClassID class_id; ///< defines the class this house has (grf file based) @See HouseGetVariable, prop 0x44 maedhros@6332: byte animation_frames; ///< number of animation frames maedhros@6332: byte animation_speed; ///< amount of time between each of those frames maedhros@6332: byte processing_time; ///< Periodic refresh multiplier maedhros@6605: byte minimum_life; ///< The minimum number of years this house will survive before the town rebuilds it maedhros@6332: maedhros@6332: /* grf file related properties*/ maedhros@6332: uint8 local_id; ///< id defined by the grf file for this house maedhros@6332: const struct GRFFile *grffile; ///< grf file that introduced this house belugas@9463: belugas@9463: /** belugas@9463: * Get the cost for removing this house belugas@9463: * @return the cost (inflation corrected etc) belugas@9463: */ belugas@9463: Money GetRemovalCost() const; belugas@9463: maedhros@6332: }; maedhros@6332: rubidium@8268: extern HouseSpec _house_specs[HOUSE_MAX]; maedhros@6332: rubidium@6247: uint32 GetWorldPopulation(); truelight@0: truelight@835: void UpdateTownVirtCoord(Town *t); rubidium@7969: void UpdateAllTownVirtCoords(); rubidium@6247: void InitializeTown(); Darkvater@3346: void ShowTownViewWindow(TownID town); truelight@0: void ExpandTown(Town *t); maedhros@6486: Town *CreateRandomTown(uint attempts, TownSizeMode mode, uint size); truelight@0: truelight@0: enum { truelight@0: ROAD_REMOVE = 0, truelight@0: UNMOVEABLE_REMOVE = 1, truelight@0: TUNNELBRIDGE_REMOVE = 1, truelight@0: INDUSTRY_REMOVE = 2 truelight@0: }; truelight@0: maedhros@6454: /** This is the number of ticks between towns being processed for building new maedhros@6454: * houses or roads. This value originally came from the size of the town array maedhros@6454: * in TTD. */ maedhros@6454: static const byte TOWN_GROWTH_FREQUENCY = 70; maedhros@6454: maedhros@6454: /** Simple value that indicates the house has reached the final stage of maedhros@6454: * construction. */ maedhros@6454: static const byte TOWN_HOUSE_COMPLETED = 3; belugas@3432: belugas@6422: /** This enum is used in conjonction with town->flags12. belugas@3432: * IT simply states what bit is used for. belugas@3432: * It is pretty unrealistic (IMHO) to only have one church/stadium belugas@3432: * per town, NO MATTER the population of it. belugas@3432: * And there are 5 more bits available on flags12... belugas@3432: */ belugas@3432: enum { belugas@6422: TOWN_IS_FUNDED = 0, ///< Town has received some funds for belugas@6422: TOWN_HAS_CHURCH = 1, ///< There can be only one church by town. belugas@6422: TOWN_HAS_STADIUM = 2 ///< There can be only one stadium by town. celestar@1005: }; celestar@1005: tron@2958: bool CheckforTownRating(uint32 flags, Town *t, byte type); truelight@0: maedhros@6332: static inline HouseSpec *GetHouseSpecs(HouseID house_id) maedhros@6332: { maedhros@6332: assert(house_id < HOUSE_MAX); maedhros@6332: return &_house_specs[house_id]; maedhros@6332: } maedhros@6332: michi_cc@10269: TileIndexDiff GetHouseNorthPart(HouseID &house); frosch@9594: truelight@1260: /** belugas@6422: * Check if a TownID is valid. belugas@6484: * @param index to inquiry in the pool of town belugas@6422: * @return true if it exists belugas@6422: */ rubidium@5299: static inline bool IsValidTownID(TownID index) rubidium@5299: { rubidium@7386: return index < GetTownPoolSize() && GetTown(index)->IsValid(); rubidium@5299: } rubidium@5299: rubidium@6247: static inline TownID GetMaxTownIndex() truelight@4354: { truelight@4354: /* TODO - This isn't the real content of the function, but truelight@4354: * with the new pool-system this will be replaced with one that matthijs@5247: * _really_ returns the highest index. Now it just returns truelight@4354: * the next safe value we are sure about everything is below. truelight@4354: */ rubidium@5298: return GetTownPoolSize() - 1; matthijs@5247: } matthijs@5247: rubidium@6247: static inline uint GetNumTowns() matthijs@5247: { rubidium@8268: extern uint _total_towns; rubidium@8268: truelight@4357: return _total_towns; truelight@4354: } truelight@4354: truelight@4356: /** truelight@4356: * Return a random valid town. truelight@4356: */ rubidium@6247: static inline Town *GetRandomTown() truelight@4356: { rubidium@5299: int num = RandomRange(GetNumTowns()); rubidium@5299: TownID index = INVALID_TOWN; truelight@4356: rubidium@5299: while (num >= 0) { truelight@4356: num--; truelight@4356: truelight@4356: index++; rubidium@5982: /* Make sure we have a valid town */ rubidium@5299: while (!IsValidTownID(index)) { truelight@4356: index++; rubidium@5299: assert(index <= GetMaxTownIndex()); truelight@4356: } truelight@4356: } truelight@4356: truelight@4356: return GetTown(index); truelight@4356: } truelight@4356: rubidium@8268: Town *CalcClosestTownFromTile(TileIndex tile, uint threshold); rubidium@5969: rubidium@7386: #define FOR_ALL_TOWNS_FROM(t, start) for (t = GetTown(start); t != NULL; t = (t->index + 1U < GetTownPoolSize()) ? GetTown(t->index + 1U) : NULL) if (t->IsValid()) truelight@1260: #define FOR_ALL_TOWNS(t) FOR_ALL_TOWNS_FROM(t, 0) truelight@1260: rubidium@8268: extern Town *_cleared_town; rubidium@8268: extern int _cleared_town_rating; truelight@0: maedhros@6332: void ResetHouses(); maedhros@6332: maedhros@6332: void ClearTownHouse(Town *t, TileIndex tile); rubidium@8131: void AfterLoadTown(); rubidium@8131: void UpdateTownMaxPass(Town *t); skidd13@8707: void UpdateTownRadius(Town *t); rubidium@8131: bool CheckIfAuthorityAllows(TileIndex tile); rubidium@8131: Town *ClosestTownFromTile(TileIndex tile, uint threshold); rubidium@8131: void ChangeTownRating(Town *t, int add, int max); belugas@8308: HouseZonesBits GetTownRadiusGroup(const Town* t, TileIndex tile); glx@8232: void SetTownRatingTestMode(bool mode); maedhros@6332: skidd13@8796: /** skidd13@8796: * Calculate a hash value from a tile position skidd13@8796: * skidd13@8796: * @param x The X coordinate skidd13@8796: * @param y The Y coordinate skidd13@8796: * @return The hash of the tile skidd13@8796: */ skidd13@8796: static inline uint TileHash(uint x, uint y) skidd13@8796: { skidd13@8796: uint hash = x >> 4; skidd13@8796: hash ^= x >> 6; skidd13@8796: hash ^= y >> 4; skidd13@8796: hash -= y >> 6; skidd13@8796: return hash; skidd13@8796: } skidd13@8796: skidd13@8796: /** skidd13@8796: * Get the last two bits of the TileHash skidd13@8796: * from a tile position. skidd13@8796: * skidd13@8796: * @see TileHash() skidd13@8796: * @param x The X coordinate skidd13@8796: * @param y The Y coordinate skidd13@8796: * @return The last two bits from hash of the tile skidd13@8796: */ skidd13@8796: static inline uint TileHash2Bit(uint x, uint y) skidd13@8796: { skidd13@8796: return GB(TileHash(x, y), 0, 2); skidd13@8796: } skidd13@8796: truelight@0: #endif /* TOWN_H */