00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "road_internal.h"
00014 #include "road_cmd.h"
00015 #include "landscape.h"
00016 #include "viewport_func.h"
00017 #include "cmd_helper.h"
00018 #include "command_func.h"
00019 #include "industry.h"
00020 #include "station_base.h"
00021 #include "company_base.h"
00022 #include "news_func.h"
00023 #include "gui.h"
00024 #include "object.h"
00025 #include "genworld.h"
00026 #include "newgrf_debug.h"
00027 #include "newgrf_house.h"
00028 #include "newgrf_text.h"
00029 #include "newgrf_config.h"
00030 #include "autoslope.h"
00031 #include "tunnelbridge_map.h"
00032 #include "strings_func.h"
00033 #include "window_func.h"
00034 #include "string_func.h"
00035 #include "newgrf_cargo.h"
00036 #include "cheat_type.h"
00037 #include "animated_tile_func.h"
00038 #include "date_func.h"
00039 #include "subsidy_func.h"
00040 #include "core/pool_func.hpp"
00041 #include "town.h"
00042 #include "townname_func.h"
00043 #include "townname_type.h"
00044 #include "core/random_func.hpp"
00045 #include "core/backup_type.hpp"
00046 #include "depot_base.h"
00047 #include "object_map.h"
00048 #include "object_base.h"
00049 #include "ai/ai.hpp"
00050
00051 #include "table/strings.h"
00052 #include "table/town_land.h"
00053
00054 TownID _new_town_id;
00055
00056
00057 TownPool _town_pool("Town");
00058 INSTANTIATE_POOL_METHODS(Town)
00059
00060 Town::~Town()
00061 {
00062 free(this->name);
00063
00064 if (CleaningPool()) return;
00065
00066
00067
00068 DeleteWindowById(WC_TOWN_VIEW, this->index);
00069
00070
00071 const Industry *i;
00072 FOR_ALL_INDUSTRIES(i) assert(i->town != this);
00073
00074
00075 const Object *o;
00076 FOR_ALL_OBJECTS(o) assert(o->town != this);
00077
00078
00079 for (TileIndex tile = 0; tile < MapSize(); ++tile) {
00080 switch (GetTileType(tile)) {
00081 case MP_HOUSE:
00082 assert(GetTownIndex(tile) != this->index);
00083 break;
00084
00085 case MP_ROAD:
00086 assert(!HasTownOwnedRoad(tile) || GetTownIndex(tile) != this->index);
00087 break;
00088
00089 case MP_TUNNELBRIDGE:
00090 assert(!IsTileOwner(tile, OWNER_TOWN) || ClosestTownFromTile(tile, UINT_MAX) != this);
00091 break;
00092
00093 default:
00094 break;
00095 }
00096 }
00097
00098 DeleteSubsidyWith(ST_TOWN, this->index);
00099 DeleteNewGRFInspectWindow(GSF_FAKE_TOWNS, this->index);
00100 CargoPacket::InvalidateAllFrom(ST_TOWN, this->index);
00101 MarkWholeScreenDirty();
00102 }
00103
00104
00110 void Town::PostDestructor(size_t index)
00111 {
00112 InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0);
00113 UpdateNearestTownForRoadTiles(false);
00114
00115
00116 Object *o;
00117 FOR_ALL_OBJECTS(o) {
00118 if (o->town == NULL) o->town = CalcClosestTownFromTile(o->location.tile, UINT_MAX);
00119 }
00120 }
00121
00125 void Town::InitializeLayout(TownLayout layout)
00126 {
00127 if (layout != TL_RANDOM) {
00128 this->layout = layout;
00129 return;
00130 }
00131
00132 this->layout = TileHash(TileX(this->xy), TileY(this->xy)) % (NUM_TLS - 1);
00133 }
00134
00144 Town *Town::GetRandom(EnumTownProc enum_proc, TownID skip, void *data)
00145 {
00146 assert(skip == INVALID_TOWN || Town::IsValidID(skip));
00147
00148 uint16 max_num = 0;
00149 if (enum_proc != NULL) {
00150
00151 Town *t;
00152 FOR_ALL_TOWNS(t) {
00153 if (t->index != skip && enum_proc(t, data)) max_num++;
00154 }
00155 } else {
00156 max_num = (uint16)Town::GetNumItems();
00157
00158
00159 if (skip != INVALID_TOWN) max_num--;
00160 }
00161 if (max_num == 0) return NULL;
00162
00163 uint num = RandomRange(max_num) + 1;
00164 size_t index = MAX_UVALUE(size_t);
00165 do {
00166 index++;
00167
00168
00169 while (!Town::IsValidID(index)) {
00170 index++;
00171 assert(index < Town::GetPoolSize());
00172 }
00173
00174 if (index != skip && (enum_proc == NULL || enum_proc(Town::Get(index), data))) num--;
00175 } while (num > 0);
00176
00177 return Town::Get(index);
00178 }
00179
00184 Money HouseSpec::GetRemovalCost() const
00185 {
00186 return (_price[PR_CLEAR_HOUSE] * this->removal_cost) >> 8;
00187 }
00188
00189
00190 static int _grow_town_result;
00191
00192
00193 enum TownGrowthResult {
00194 GROWTH_SUCCEED = -1,
00195 GROWTH_SEARCH_STOPPED = 0
00196
00197 };
00198
00199 static bool BuildTownHouse(Town *t, TileIndex tile);
00200 static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size, bool city, TownLayout layout);
00201
00202 static void TownDrawHouseLift(const TileInfo *ti)
00203 {
00204 AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile));
00205 }
00206
00207 typedef void TownDrawTileProc(const TileInfo *ti);
00208 static TownDrawTileProc * const _town_draw_tile_procs[1] = {
00209 TownDrawHouseLift
00210 };
00211
00217 static inline DiagDirection RandomDiagDir()
00218 {
00219 return (DiagDirection)(3 & Random());
00220 }
00221
00227 static void DrawTile_Town(TileInfo *ti)
00228 {
00229 HouseID house_id = GetHouseType(ti->tile);
00230
00231 if (house_id >= NEW_HOUSE_OFFSET) {
00232
00233
00234
00235 if (HouseSpec::Get(house_id)->grf_prop.spritegroup[0] != NULL) {
00236 DrawNewHouseTile(ti, house_id);
00237 return;
00238 } else {
00239 house_id = HouseSpec::Get(house_id)->grf_prop.subst_id;
00240 }
00241 }
00242
00243
00244 const DrawBuildingsTileStruct *dcts = &_town_draw_tile_data[house_id << 4 | TileHash2Bit(ti->x, ti->y) << 2 | GetHouseBuildingStage(ti->tile)];
00245
00246 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
00247
00248 DrawGroundSprite(dcts->ground.sprite, dcts->ground.pal);
00249
00250
00251 if (IsInvisibilitySet(TO_HOUSES)) return;
00252
00253
00254 SpriteID image = dcts->building.sprite;
00255 if (image != 0) {
00256 AddSortableSpriteToDraw(image, dcts->building.pal,
00257 ti->x + dcts->subtile_x,
00258 ti->y + dcts->subtile_y,
00259 dcts->width,
00260 dcts->height,
00261 dcts->dz,
00262 ti->z,
00263 IsTransparencySet(TO_HOUSES)
00264 );
00265
00266 if (IsTransparencySet(TO_HOUSES)) return;
00267 }
00268
00269 {
00270 int proc = dcts->draw_proc - 1;
00271
00272 if (proc >= 0) _town_draw_tile_procs[proc](ti);
00273 }
00274 }
00275
00276 static uint GetSlopeZ_Town(TileIndex tile, uint x, uint y)
00277 {
00278 return GetTileMaxZ(tile);
00279 }
00280
00282 static Foundation GetFoundation_Town(TileIndex tile, Slope tileh)
00283 {
00284 HouseID hid = GetHouseType(tile);
00285
00286
00287
00288
00289
00290 if (hid >= NEW_HOUSE_OFFSET) {
00291 const HouseSpec *hs = HouseSpec::Get(hid);
00292 if (hs->grf_prop.spritegroup[0] != NULL && HasBit(hs->callback_mask, CBM_HOUSE_DRAW_FOUNDATIONS)) {
00293 uint32 callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, hid, Town::GetByTile(tile), tile);
00294 if (callback_res == 0) return FOUNDATION_NONE;
00295 }
00296 }
00297 return FlatteningFoundation(tileh);
00298 }
00299
00306 static void AnimateTile_Town(TileIndex tile)
00307 {
00308 if (GetHouseType(tile) >= NEW_HOUSE_OFFSET) {
00309 AnimateNewHouseTile(tile);
00310 return;
00311 }
00312
00313 if (_tick_counter & 3) return;
00314
00315
00316
00317
00318
00319 if (!(HouseSpec::Get(GetHouseType(tile))->building_flags & BUILDING_IS_ANIMATED)) {
00320 DeleteAnimatedTile(tile);
00321 return;
00322 }
00323
00324 if (!LiftHasDestination(tile)) {
00325 uint i;
00326
00327
00328
00329
00330
00331 do {
00332 i = RandomRange(7);
00333 } while (i == 1 || i * 6 == GetLiftPosition(tile));
00334
00335 SetLiftDestination(tile, i);
00336 }
00337
00338 int pos = GetLiftPosition(tile);
00339 int dest = GetLiftDestination(tile) * 6;
00340 pos += (pos < dest) ? 1 : -1;
00341 SetLiftPosition(tile, pos);
00342
00343 if (pos == dest) {
00344 HaltLift(tile);
00345 DeleteAnimatedTile(tile);
00346 }
00347
00348 MarkTileDirtyByTile(tile);
00349 }
00350
00357 static bool IsCloseToTown(TileIndex tile, uint dist)
00358 {
00359 const Town *t;
00360
00361 FOR_ALL_TOWNS(t) {
00362 if (DistanceManhattan(tile, t->xy) < dist) return true;
00363 }
00364 return false;
00365 }
00366
00371 void Town::UpdateVirtCoord()
00372 {
00373 Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE);
00374 SetDParam(0, this->index);
00375 SetDParam(1, this->population);
00376 this->sign.UpdatePosition(pt.x, pt.y - 24,
00377 _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN);
00378
00379 SetWindowDirty(WC_TOWN_VIEW, this->index);
00380 }
00381
00383 void UpdateAllTownVirtCoords()
00384 {
00385 Town *t;
00386
00387 FOR_ALL_TOWNS(t) {
00388 t->UpdateVirtCoord();
00389 }
00390 }
00391
00397 static void ChangePopulation(Town *t, int mod)
00398 {
00399 t->population += mod;
00400 SetWindowDirty(WC_TOWN_VIEW, t->index);
00401 t->UpdateVirtCoord();
00402
00403 InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1);
00404 }
00405
00411 uint32 GetWorldPopulation()
00412 {
00413 uint32 pop = 0;
00414 const Town *t;
00415
00416 FOR_ALL_TOWNS(t) pop += t->population;
00417 return pop;
00418 }
00419
00424 static void MakeSingleHouseBigger(TileIndex tile)
00425 {
00426 assert(IsTileType(tile, MP_HOUSE));
00427
00428
00429 IncHouseConstructionTick(tile);
00430 if (GetHouseConstructionTick(tile) != 0) return;
00431
00432 AnimateNewHouseConstruction(tile);
00433
00434 if (IsHouseCompleted(tile)) {
00435
00436
00437 ChangePopulation(Town::GetByTile(tile), HouseSpec::Get(GetHouseType(tile))->population);
00438 ResetHouseAge(tile);
00439 }
00440 MarkTileDirtyByTile(tile);
00441 }
00442
00447 static void MakeTownHouseBigger(TileIndex tile)
00448 {
00449 uint flags = HouseSpec::Get(GetHouseType(tile))->building_flags;
00450 if (flags & BUILDING_HAS_1_TILE) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 0));
00451 if (flags & BUILDING_2_TILES_Y) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 1));
00452 if (flags & BUILDING_2_TILES_X) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 0));
00453 if (flags & BUILDING_HAS_4_TILES) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 1));
00454 }
00455
00462 static void TileLoop_Town(TileIndex tile)
00463 {
00464 HouseID house_id = GetHouseType(tile);
00465
00466
00467
00468 if (house_id >= NEW_HOUSE_OFFSET && !NewHouseTileLoop(tile)) return;
00469
00470 if (!IsHouseCompleted(tile)) {
00471
00472 MakeTownHouseBigger(tile);
00473 return;
00474 }
00475
00476 const HouseSpec *hs = HouseSpec::Get(house_id);
00477
00478
00479 if ((hs->building_flags & BUILDING_IS_ANIMATED) &&
00480 house_id < NEW_HOUSE_OFFSET &&
00481 !LiftHasDestination(tile) &&
00482 Chance16(1, 2)) {
00483 AddAnimatedTile(tile);
00484 }
00485
00486 Town *t = Town::GetByTile(tile);
00487 uint32 r = Random();
00488
00489 StationFinder stations(TileArea(tile, 1, 1));
00490
00491 if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
00492 for (uint i = 0; i < 256; i++) {
00493 uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, r, house_id, t, tile);
00494
00495 if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
00496
00497 CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grf_prop.grffile);
00498 if (cargo == CT_INVALID) continue;
00499
00500 uint amt = GB(callback, 0, 8);
00501 if (amt == 0) continue;
00502
00503 uint moved = MoveGoodsToStation(cargo, amt, ST_TOWN, t->index, stations.GetStations(), tile);
00504
00505 const CargoSpec *cs = CargoSpec::Get(cargo);
00506 switch (cs->town_effect) {
00507 case TE_PASSENGERS:
00508 t->pass.new_max += amt;
00509 t->pass.new_act += moved;
00510 break;
00511
00512 case TE_MAIL:
00513 t->mail.new_max += amt;
00514 t->mail.new_act += moved;
00515 break;
00516
00517 default:
00518 break;
00519 }
00520 }
00521 } else {
00522 if (GB(r, 0, 8) < hs->population) {
00523 uint amt = GB(r, 0, 8) / 8 + 1;
00524
00525 if (EconomyIsInRecession()) amt = (amt + 1) >> 1;
00526 t->pass.new_max += amt;
00527 t->pass.new_act += MoveGoodsToStation(CT_PASSENGERS, amt, ST_TOWN, t->index, stations.GetStations(), tile);
00528 }
00529
00530 if (GB(r, 8, 8) < hs->mail_generation) {
00531 uint amt = GB(r, 8, 8) / 8 + 1;
00532
00533 if (EconomyIsInRecession()) amt = (amt + 1) >> 1;
00534 t->mail.new_max += amt;
00535 t->mail.new_act += MoveGoodsToStation(CT_MAIL, amt, ST_TOWN, t->index, stations.GetStations(), tile);
00536 }
00537 }
00538
00539 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
00540
00541 if ((hs->building_flags & BUILDING_HAS_1_TILE) &&
00542 HasBit(t->flags, TOWN_IS_FUNDED) &&
00543 CanDeleteHouse(tile) &&
00544 GetHouseAge(tile) >= hs->minimum_life &&
00545 --t->time_until_rebuild == 0) {
00546 t->time_until_rebuild = GB(r, 16, 8) + 192;
00547
00548 ClearTownHouse(t, tile);
00549
00550
00551 if (GB(r, 24, 8) >= 12) BuildTownHouse(t, tile);
00552 }
00553
00554 cur_company.Restore();
00555 }
00556
00557 static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags)
00558 {
00559 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00560 if (!CanDeleteHouse(tile)) return CMD_ERROR;
00561
00562 const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
00563
00564 CommandCost cost(EXPENSES_CONSTRUCTION);
00565 cost.AddCost(hs->GetRemovalCost());
00566
00567 int rating = hs->remove_rating_decrease;
00568 Town *t = Town::GetByTile(tile);
00569
00570 if (Company::IsValidID(_current_company)) {
00571 if (rating > t->ratings[_current_company] && !(flags & DC_NO_TEST_TOWN_RATING) && !_cheats.magic_bulldozer.value) {
00572 SetDParam(0, t->index);
00573 return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
00574 }
00575 }
00576
00577 ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM, flags);
00578 if (flags & DC_EXEC) {
00579 ClearTownHouse(t, tile);
00580 }
00581
00582 return cost;
00583 }
00584
00585 static void AddProducedCargo_Town(TileIndex tile, CargoArray &produced)
00586 {
00587 HouseID house_id = GetHouseType(tile);
00588 const HouseSpec *hs = HouseSpec::Get(house_id);
00589 Town *t = Town::GetByTile(tile);
00590
00591 if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
00592 for (uint i = 0; i < 256; i++) {
00593 uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, house_id, t, tile);
00594
00595 if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
00596
00597 CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grf_prop.grffile);
00598
00599 if (cargo == CT_INVALID) continue;
00600 produced[cargo]++;
00601 }
00602 } else {
00603 if (hs->population > 0) {
00604 produced[CT_PASSENGERS]++;
00605 }
00606 if (hs->mail_generation > 0) {
00607 produced[CT_MAIL]++;
00608 }
00609 }
00610 }
00611
00612 static inline void AddAcceptedCargoSetMask(CargoID cargo, uint amount, CargoArray &acceptance, uint32 *always_accepted)
00613 {
00614 if (cargo == CT_INVALID || amount == 0) return;
00615 acceptance[cargo] += amount;
00616 SetBit(*always_accepted, cargo);
00617 }
00618
00619 static void AddAcceptedCargo_Town(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
00620 {
00621 const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
00622 CargoID accepts[3];
00623
00624
00625 for (uint8 i = 0; i < lengthof(accepts); i++) {
00626 accepts[i] = hs->accepts_cargo[i];
00627 }
00628
00629
00630 if (HasBit(hs->callback_mask, CBM_HOUSE_ACCEPT_CARGO)) {
00631 uint16 callback = GetHouseCallback(CBID_HOUSE_ACCEPT_CARGO, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
00632 if (callback != CALLBACK_FAILED) {
00633
00634 accepts[0] = GetCargoTranslation(GB(callback, 0, 5), hs->grf_prop.grffile);
00635 accepts[1] = GetCargoTranslation(GB(callback, 5, 5), hs->grf_prop.grffile);
00636 accepts[2] = GetCargoTranslation(GB(callback, 10, 5), hs->grf_prop.grffile);
00637 }
00638 }
00639
00640
00641 if (HasBit(hs->callback_mask, CBM_HOUSE_CARGO_ACCEPTANCE)) {
00642 uint16 callback = GetHouseCallback(CBID_HOUSE_CARGO_ACCEPTANCE, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
00643 if (callback != CALLBACK_FAILED) {
00644 AddAcceptedCargoSetMask(accepts[0], GB(callback, 0, 4), acceptance, always_accepted);
00645 AddAcceptedCargoSetMask(accepts[1], GB(callback, 4, 4), acceptance, always_accepted);
00646 if (_settings_game.game_creation.landscape != LT_TEMPERATE && HasBit(callback, 12)) {
00647
00648 AddAcceptedCargoSetMask(CT_FOOD, GB(callback, 8, 4), acceptance, always_accepted);
00649 } else {
00650 AddAcceptedCargoSetMask(accepts[2], GB(callback, 8, 4), acceptance, always_accepted);
00651 }
00652 return;
00653 }
00654 }
00655
00656
00657 for (uint8 i = 0; i < lengthof(accepts); i++) {
00658 AddAcceptedCargoSetMask(accepts[i], hs->cargo_acceptance[i], acceptance, always_accepted);
00659 }
00660 }
00661
00662 static void GetTileDesc_Town(TileIndex tile, TileDesc *td)
00663 {
00664 const HouseID house = GetHouseType(tile);
00665 const HouseSpec *hs = HouseSpec::Get(house);
00666 bool house_completed = IsHouseCompleted(tile);
00667
00668 td->str = hs->building_name;
00669
00670 uint16 callback_res = GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, house_completed ? 1 : 0, 0, house, Town::GetByTile(tile), tile);
00671 if (callback_res != CALLBACK_FAILED) {
00672 StringID new_name = GetGRFStringID(hs->grf_prop.grffile->grfid, 0xD000 + callback_res);
00673 if (new_name != STR_NULL && new_name != STR_UNDEFINED) {
00674 td->str = new_name;
00675 }
00676 }
00677
00678 if (!house_completed) {
00679 SetDParamX(td->dparam, 0, td->str);
00680 td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
00681 }
00682
00683 if (hs->grf_prop.grffile != NULL) {
00684 const GRFConfig *gc = GetGRFConfig(hs->grf_prop.grffile->grfid);
00685 td->grf = gc->GetName();
00686 }
00687
00688 td->owner[0] = OWNER_TOWN;
00689 }
00690
00691 static TrackStatus GetTileTrackStatus_Town(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
00692 {
00693
00694 return 0;
00695 }
00696
00697 static void ChangeTileOwner_Town(TileIndex tile, Owner old_owner, Owner new_owner)
00698 {
00699
00700 }
00701
00703 void UpdateTownCargoTotal(Town *t)
00704 {
00705 t->cargo_accepted_total = 0;
00706 MemSetT(t->cargo_accepted_weights, 0, lengthof(t->cargo_accepted_weights));
00707
00708
00709
00710
00711 const TileArea &area = t->cargo_accepted.GetArea();
00712 uint max_dist = max(DistanceMax(t->xy_aligned, area.tile), DistanceMax(t->xy_aligned, TILE_ADDXY(area.tile, area.w - 1, area.h - 1))) / AcceptanceMatrix::GRID;
00713 t->cargo_accepted_max_weight = max_dist * 2 + 1;
00714
00715
00716 TILE_AREA_LOOP(tile, area) {
00717 if (TileX(tile) % AcceptanceMatrix::GRID == 0 && TileY(tile) % AcceptanceMatrix::GRID == 0) {
00718 uint32 acc = t->cargo_accepted[tile];
00719 t->cargo_accepted_total |= acc;
00720
00721 CargoID cid;
00722 FOR_EACH_SET_CARGO_ID(cid, acc) {
00723
00724
00725 t->cargo_accepted_weights[cid] += t->cargo_accepted_max_weight - (DistanceMax(t->xy_aligned, tile) / AcceptanceMatrix::GRID) * 2;
00726 }
00727 }
00728 }
00729 }
00730
00737 static void UpdateTownCargos(Town *t, TileIndex start, bool update_total = true)
00738 {
00739 CargoArray accepted, produced;
00740 uint32 dummy;
00741
00742
00743
00744
00745 TileArea area = AcceptanceMatrix::GetAreaForTile(start, 1);
00746 TILE_AREA_LOOP(tile, area) {
00747 if (!IsTileType(tile, MP_HOUSE) || GetTownIndex(tile) != t->index) continue;
00748
00749 AddAcceptedCargo_Town(tile, accepted, &dummy);
00750 AddProducedCargo_Town(tile, produced);
00751 }
00752
00753
00754 uint32 acc = 0;
00755 for (uint cid = 0; cid < NUM_CARGO; cid++) {
00756 if (accepted[cid] >= 8) SetBit(acc, cid);
00757 if (produced[cid] > 0) SetBit(t->cargo_produced, cid);
00758 }
00759 t->cargo_accepted[start] = acc;
00760
00761 if (update_total) UpdateTownCargoTotal(t);
00762 }
00763
00765 void UpdateTownCargos(Town *t)
00766 {
00767 t->cargo_produced = 0;
00768
00769 const TileArea &area = t->cargo_accepted.GetArea();
00770 if (area.tile == INVALID_TILE) return;
00771
00772
00773 TILE_AREA_LOOP(tile, area) {
00774 if (TileX(tile) % AcceptanceMatrix::GRID == 0 && TileY(tile) % AcceptanceMatrix::GRID == 0) {
00775 UpdateTownCargos(t, tile, false);
00776 }
00777 }
00778
00779
00780 UpdateTownCargoTotal(t);
00781 }
00782
00783 static bool GrowTown(Town *t);
00784
00785 static void TownTickHandler(Town *t)
00786 {
00787 if (HasBit(t->flags, TOWN_IS_FUNDED)) {
00788 int i = t->grow_counter - 1;
00789 if (i < 0) {
00790 if (GrowTown(t)) {
00791 i = t->growth_rate;
00792 } else {
00793 i = 0;
00794 }
00795 }
00796 t->grow_counter = i;
00797 }
00798
00799 UpdateTownRadius(t);
00800 }
00801
00802 void OnTick_Town()
00803 {
00804 if (_game_mode == GM_EDITOR) return;
00805
00806 Town *t;
00807 FOR_ALL_TOWNS(t) {
00808
00809 if ((_tick_counter + t->index) % TOWN_GROWTH_FREQUENCY == 0) {
00810 TownTickHandler(t);
00811 }
00812 }
00813 }
00814
00823 static RoadBits GetTownRoadBits(TileIndex tile)
00824 {
00825 if (IsRoadDepotTile(tile) || IsStandardRoadStopTile(tile)) return ROAD_NONE;
00826
00827 return GetAnyRoadBits(tile, ROADTYPE_ROAD, true);
00828 }
00829
00840 static bool IsNeighborRoadTile(TileIndex tile, const DiagDirection dir, uint dist_multi)
00841 {
00842 if (!IsValidTile(tile)) return false;
00843
00844
00845 const TileIndexDiff tid_lt[3] = {
00846 TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT)),
00847 TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT)),
00848 TileOffsByDiagDir(ReverseDiagDir(dir)),
00849 };
00850
00851 dist_multi = (dist_multi + 1) * 4;
00852 for (uint pos = 4; pos < dist_multi; pos++) {
00853
00854 TileIndexDiff cur = tid_lt[(pos & 1) ? 0 : 1] * (pos / 4);
00855
00856
00857 if (pos & 2) cur += tid_lt[2];
00858
00859
00860 if (IsValidTile(tile + cur) &&
00861 GetTownRoadBits(TILE_ADD(tile, cur)) & DiagDirToRoadBits((pos & 2) ? dir : ReverseDiagDir(dir))) return true;
00862 }
00863 return false;
00864 }
00865
00874 static bool IsRoadAllowedHere(Town *t, TileIndex tile, DiagDirection dir)
00875 {
00876 if (DistanceFromEdge(tile) == 0) return false;
00877
00878 Slope cur_slope, desired_slope;
00879
00880 for (;;) {
00881
00882 if (GetTownRoadBits(tile) == ROAD_NONE) {
00883
00884
00885
00886 if (DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_Y : ROAD_X), 0, DC_AUTO, CMD_BUILD_ROAD).Failed() &&
00887 DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR).Failed())
00888 return false;
00889 }
00890
00891 cur_slope = _settings_game.construction.build_on_slopes ? GetFoundationSlope(tile, NULL) : GetTileSlope(tile, NULL);
00892 bool ret = !IsNeighborRoadTile(tile, dir, t->layout == TL_ORIGINAL ? 1 : 2);
00893 if (cur_slope == SLOPE_FLAT) return ret;
00894
00895
00896
00897 desired_slope = (dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? SLOPE_NW : SLOPE_NE;
00898 if (desired_slope != cur_slope && ComplementSlope(desired_slope) != cur_slope) {
00899 if (Chance16(1, 8)) {
00900 CommandCost res = CMD_ERROR;
00901 if (!_generating_world && Chance16(1, 10)) {
00902
00903 res = DoCommand(tile, Chance16(1, 16) ? cur_slope : cur_slope ^ SLOPE_ELEVATED, 0,
00904 DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
00905 }
00906 if (res.Failed() && Chance16(1, 3)) {
00907
00908 return ret;
00909 }
00910 }
00911 return false;
00912 }
00913 return ret;
00914 }
00915 }
00916
00917 static bool TerraformTownTile(TileIndex tile, int edges, int dir)
00918 {
00919 assert(tile < MapSize());
00920
00921 CommandCost r = DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
00922 if (r.Failed() || r.GetCost() >= (_price[PR_TERRAFORM] + 2) * 8) return false;
00923 DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER | DC_EXEC, CMD_TERRAFORM_LAND);
00924 return true;
00925 }
00926
00927 static void LevelTownLand(TileIndex tile)
00928 {
00929 assert(tile < MapSize());
00930
00931
00932 if (IsTileType(tile, MP_HOUSE)) return;
00933 Slope tileh = GetTileSlope(tile, NULL);
00934 if (tileh == SLOPE_FLAT) return;
00935
00936
00937 if (!TerraformTownTile(tile, ~tileh & SLOPE_ELEVATED, 1)) {
00938 TerraformTownTile(tile, tileh & SLOPE_ELEVATED, 0);
00939 }
00940 }
00941
00951 static RoadBits GetTownRoadGridElement(Town *t, TileIndex tile, DiagDirection dir)
00952 {
00953
00954 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
00955 RoadBits rcmd = ROAD_NONE;
00956
00957 switch (t->layout) {
00958 default: NOT_REACHED();
00959
00960 case TL_2X2_GRID:
00961 if ((grid_pos.x % 3) == 0) rcmd |= ROAD_Y;
00962 if ((grid_pos.y % 3) == 0) rcmd |= ROAD_X;
00963 break;
00964
00965 case TL_3X3_GRID:
00966 if ((grid_pos.x % 4) == 0) rcmd |= ROAD_Y;
00967 if ((grid_pos.y % 4) == 0) rcmd |= ROAD_X;
00968 break;
00969 }
00970
00971
00972 if (rcmd != ROAD_ALL) return rcmd;
00973
00974 RoadBits rb_template;
00975
00976 switch (GetTileSlope(tile, NULL)) {
00977 default: rb_template = ROAD_ALL; break;
00978 case SLOPE_W: rb_template = ROAD_NW | ROAD_SW; break;
00979 case SLOPE_SW: rb_template = ROAD_Y | ROAD_SW; break;
00980 case SLOPE_S: rb_template = ROAD_SW | ROAD_SE; break;
00981 case SLOPE_SE: rb_template = ROAD_X | ROAD_SE; break;
00982 case SLOPE_E: rb_template = ROAD_SE | ROAD_NE; break;
00983 case SLOPE_NE: rb_template = ROAD_Y | ROAD_NE; break;
00984 case SLOPE_N: rb_template = ROAD_NE | ROAD_NW; break;
00985 case SLOPE_NW: rb_template = ROAD_X | ROAD_NW; break;
00986 case SLOPE_STEEP_W:
00987 case SLOPE_STEEP_S:
00988 case SLOPE_STEEP_E:
00989 case SLOPE_STEEP_N:
00990 rb_template = ROAD_NONE;
00991 break;
00992 }
00993
00994
00995 if (DiagDirToRoadBits(ReverseDiagDir(dir)) & rb_template) return rb_template;
00996
00997 return DiagDirToRoadBits(dir) | DiagDirToRoadBits(ReverseDiagDir(dir));
00998 }
00999
01010 static bool GrowTownWithExtraHouse(Town *t, TileIndex tile)
01011 {
01012
01013 if (DistanceFromEdge(tile) == 0) return false;
01014
01015 uint counter = 0;
01016
01017
01018 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
01019
01020
01021
01022 switch (GetTileType(TileAddByDiagDir(tile, dir))) {
01023 case MP_HOUSE:
01024 case MP_VOID:
01025 counter++;
01026 break;
01027
01028 default:
01029 break;
01030 }
01031
01032
01033 if (counter >= 3) {
01034 if (BuildTownHouse(t, tile)) {
01035 _grow_town_result = GROWTH_SUCCEED;
01036 return true;
01037 }
01038 return false;
01039 }
01040 }
01041 return false;
01042 }
01043
01052 static bool GrowTownWithRoad(const Town *t, TileIndex tile, RoadBits rcmd)
01053 {
01054 if (DoCommand(tile, rcmd, t->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD).Succeeded()) {
01055 _grow_town_result = GROWTH_SUCCEED;
01056 return true;
01057 }
01058 return false;
01059 }
01060
01071 static bool GrowTownWithBridge(const Town *t, const TileIndex tile, const DiagDirection bridge_dir)
01072 {
01073 assert(bridge_dir < DIAGDIR_END);
01074
01075 const Slope slope = GetTileSlope(tile, NULL);
01076 if (slope == SLOPE_FLAT) return false;
01077
01078
01079
01080
01081 if (slope & InclinedSlope(bridge_dir)) return false;
01082
01083
01084 if (!(GetTownRoadBits(TileAddByDiagDir(tile, ReverseDiagDir(bridge_dir))) & DiagDirToRoadBits(bridge_dir))) return false;
01085
01086
01087 uint8 bridge_length = 0;
01088 TileIndex bridge_tile = tile;
01089
01090 const int delta = TileOffsByDiagDir(bridge_dir);
01091 do {
01092 if (bridge_length++ >= 11) {
01093
01094 return false;
01095 }
01096 bridge_tile += delta;
01097 } while (TileX(bridge_tile) != 0 && TileY(bridge_tile) != 0 && IsWaterTile(bridge_tile));
01098
01099
01100 if (bridge_length == 1) return false;
01101
01102 for (uint8 times = 0; times <= 22; times++) {
01103 byte bridge_type = RandomRange(MAX_BRIDGES - 1);
01104
01105
01106 if (DoCommand(tile, bridge_tile, bridge_type | ROADTYPES_ROAD << 8 | TRANSPORT_ROAD << 15, CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE).Succeeded()) {
01107 DoCommand(tile, bridge_tile, bridge_type | ROADTYPES_ROAD << 8 | TRANSPORT_ROAD << 15, DC_EXEC | CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE);
01108 _grow_town_result = GROWTH_SUCCEED;
01109 return true;
01110 }
01111 }
01112
01113 return false;
01114 }
01115
01133 static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection target_dir, Town *t1)
01134 {
01135 RoadBits rcmd = ROAD_NONE;
01136 TileIndex tile = *tile_ptr;
01137
01138 assert(tile < MapSize());
01139
01140 if (cur_rb == ROAD_NONE) {
01141
01142
01143 _grow_town_result = GROWTH_SEARCH_STOPPED;
01144
01145 if (!_settings_game.economy.allow_town_roads && !_generating_world) return;
01146 if (!_settings_game.economy.allow_town_level_crossings && IsTileType(tile, MP_RAILWAY)) return;
01147
01148
01149 if (!_settings_game.construction.build_on_slopes || Chance16(1, 6)) LevelTownLand(tile);
01150
01151
01152 switch (t1->layout) {
01153 default: NOT_REACHED();
01154
01155 case TL_3X3_GRID:
01156 case TL_2X2_GRID:
01157 rcmd = GetTownRoadGridElement(t1, tile, target_dir);
01158 if (rcmd == ROAD_NONE) return;
01159 break;
01160
01161 case TL_BETTER_ROADS:
01162 case TL_ORIGINAL:
01163 if (!IsRoadAllowedHere(t1, tile, target_dir)) return;
01164
01165 DiagDirection source_dir = ReverseDiagDir(target_dir);
01166
01167 if (Chance16(1, 4)) {
01168
01169 do target_dir = RandomDiagDir(); while (target_dir == source_dir);
01170 }
01171
01172 if (!IsRoadAllowedHere(t1, TileAddByDiagDir(tile, target_dir), target_dir)) {
01173
01174
01175 if (target_dir != ReverseDiagDir(source_dir)) return;
01176
01177
01178 if (!IsTileType(TileAddByDiagDir(tile, ChangeDiagDir(target_dir, DIAGDIRDIFF_90RIGHT)), MP_HOUSE) &&
01179 !IsTileType(TileAddByDiagDir(tile, ChangeDiagDir(target_dir, DIAGDIRDIFF_90LEFT)), MP_HOUSE)) {
01180 return;
01181 }
01182
01183
01184
01185 }
01186
01187 rcmd = DiagDirToRoadBits(target_dir) | DiagDirToRoadBits(source_dir);
01188 break;
01189 }
01190
01191 } else if (target_dir < DIAGDIR_END && !(cur_rb & DiagDirToRoadBits(ReverseDiagDir(target_dir)))) {
01192
01193
01194
01195 _grow_town_result = GROWTH_SEARCH_STOPPED;
01196
01197 if (!_settings_game.economy.allow_town_roads && !_generating_world) return;
01198
01199 switch (t1->layout) {
01200 default: NOT_REACHED();
01201
01202 case TL_3X3_GRID:
01203 case TL_2X2_GRID:
01204 rcmd = GetTownRoadGridElement(t1, tile, target_dir);
01205 break;
01206
01207 case TL_BETTER_ROADS:
01208 case TL_ORIGINAL:
01209 rcmd = DiagDirToRoadBits(ReverseDiagDir(target_dir));
01210 break;
01211 }
01212 } else {
01213 bool allow_house = true;
01214
01215
01216 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
01217 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
01218 *tile_ptr = GetOtherTunnelBridgeEnd(tile);
01219 }
01220 return;
01221 }
01222
01223
01224
01225 target_dir = RandomDiagDir();
01226 if (cur_rb & DiagDirToRoadBits(target_dir)) return;
01227
01228
01229 TileIndex house_tile = TileAddByDiagDir(tile, target_dir);
01230
01231
01232 if (HasTileWaterGround(house_tile)) return;
01233
01234 if (!IsValidTile(house_tile)) return;
01235
01236 if (_settings_game.economy.allow_town_roads || _generating_world) {
01237 switch (t1->layout) {
01238 default: NOT_REACHED();
01239
01240 case TL_3X3_GRID:
01241 GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir));
01242
01243
01244 case TL_2X2_GRID:
01245 rcmd = GetTownRoadGridElement(t1, house_tile, target_dir);
01246 allow_house = (rcmd == ROAD_NONE);
01247 break;
01248
01249 case TL_BETTER_ROADS:
01250 GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir));
01251
01252
01253 case TL_ORIGINAL:
01254
01255
01256 rcmd = DiagDirToRoadBits(target_dir);
01257 allow_house = (!IsRoadAllowedHere(t1, house_tile, target_dir) || Chance16(6, 10));
01258 break;
01259 }
01260 }
01261
01262 if (allow_house) {
01263
01264 if (!IsTileType(house_tile, MP_HOUSE)) {
01265
01266 if (Chance16(1, 6)) LevelTownLand(house_tile);
01267
01268
01269
01270 if (BuildTownHouse(t1, house_tile)) {
01271 _grow_town_result = GROWTH_SUCCEED;
01272 }
01273 }
01274 return;
01275 }
01276
01277 _grow_town_result = GROWTH_SEARCH_STOPPED;
01278 }
01279
01280
01281 if (HasTileWaterGround(tile)) return;
01282
01283
01284 rcmd = CleanUpRoadBits(tile, rcmd);
01285 if (rcmd == ROAD_NONE) return;
01286
01287
01288
01289
01290 if (GrowTownWithBridge(t1, tile, target_dir)) return;
01291
01292 GrowTownWithRoad(t1, tile, rcmd);
01293 }
01294
01301 static int GrowTownAtRoad(Town *t, TileIndex tile)
01302 {
01303
01304
01305
01306 DiagDirection target_dir = DIAGDIR_END;
01307
01308 assert(tile < MapSize());
01309
01310
01311
01312
01313 switch (t->layout) {
01314 case TL_BETTER_ROADS:
01315 _grow_town_result = 10 + t->num_houses * 2 / 9;
01316 break;
01317
01318 case TL_3X3_GRID:
01319 case TL_2X2_GRID:
01320 _grow_town_result = 10 + t->num_houses * 1 / 9;
01321 break;
01322
01323 default:
01324 _grow_town_result = 10 + t->num_houses * 4 / 9;
01325 break;
01326 }
01327
01328 do {
01329 RoadBits cur_rb = GetTownRoadBits(tile);
01330
01331
01332 GrowTownInTile(&tile, cur_rb, target_dir, t);
01333
01334
01335
01336 cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir));
01337 if (cur_rb == ROAD_NONE) {
01338 return _grow_town_result;
01339 }
01340
01341
01342
01343 do target_dir = RandomDiagDir(); while (!(cur_rb & DiagDirToRoadBits(target_dir)));
01344 tile = TileAddByDiagDir(tile, target_dir);
01345
01346 if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, ROADTYPE_ROAD)) {
01347
01348 if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN) && Town::GetByTile(tile) != t) {
01349 _grow_town_result = GROWTH_SUCCEED;
01350 } else if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) {
01351
01352
01353 SetRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN);
01354 SetTownIndex(tile, t->index);
01355 }
01356 }
01357
01358
01359 } while (--_grow_town_result >= 0);
01360
01361 return (_grow_town_result == -2);
01362 }
01363
01371 static RoadBits GenRandomRoadBits()
01372 {
01373 uint32 r = Random();
01374 uint a = GB(r, 0, 2);
01375 uint b = GB(r, 8, 2);
01376 if (a == b) b ^= 2;
01377 return (RoadBits)((ROAD_NW << a) + (ROAD_NW << b));
01378 }
01379
01385 static bool GrowTown(Town *t)
01386 {
01387 static const TileIndexDiffC _town_coord_mod[] = {
01388 {-1, 0},
01389 { 1, 1},
01390 { 1, -1},
01391 {-1, -1},
01392 {-1, 0},
01393 { 0, 2},
01394 { 2, 0},
01395 { 0, -2},
01396 {-1, -1},
01397 {-2, 2},
01398 { 2, 2},
01399 { 2, -2},
01400 { 0, 0}
01401 };
01402
01403
01404 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
01405
01406 TileIndex tile = t->xy;
01407
01408
01409 const TileIndexDiffC *ptr;
01410 for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
01411 if (GetTownRoadBits(tile) != ROAD_NONE) {
01412 int r = GrowTownAtRoad(t, tile);
01413 cur_company.Restore();
01414 return r != 0;
01415 }
01416 tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
01417 }
01418
01419
01420
01421 if (_settings_game.economy.allow_town_roads || _generating_world) {
01422 tile = t->xy;
01423 for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
01424
01425 if (!IsTileType(tile, MP_HOUSE) && GetTileSlope(tile, NULL) == SLOPE_FLAT) {
01426 if (DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded()) {
01427 DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD);
01428 cur_company.Restore();
01429 return true;
01430 }
01431 }
01432 tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
01433 }
01434 }
01435
01436 cur_company.Restore();
01437 return false;
01438 }
01439
01440 void UpdateTownRadius(Town *t)
01441 {
01442 static const uint32 _town_squared_town_zone_radius_data[23][5] = {
01443 { 4, 0, 0, 0, 0},
01444 { 16, 0, 0, 0, 0},
01445 { 25, 0, 0, 0, 0},
01446 { 36, 0, 0, 0, 0},
01447 { 49, 0, 4, 0, 0},
01448 { 64, 0, 4, 0, 0},
01449 { 64, 0, 9, 0, 1},
01450 { 64, 0, 9, 0, 4},
01451 { 64, 0, 16, 0, 4},
01452 { 81, 0, 16, 0, 4},
01453 { 81, 0, 16, 0, 4},
01454 { 81, 0, 25, 0, 9},
01455 { 81, 36, 25, 0, 9},
01456 { 81, 36, 25, 16, 9},
01457 { 81, 49, 0, 25, 9},
01458 { 81, 64, 0, 25, 9},
01459 { 81, 64, 0, 36, 9},
01460 { 81, 64, 0, 36, 16},
01461 {100, 81, 0, 49, 16},
01462 {100, 81, 0, 49, 25},
01463 {121, 81, 0, 49, 25},
01464 {121, 81, 0, 49, 25},
01465 {121, 81, 0, 49, 36},
01466 };
01467
01468 if (t->num_houses < 92) {
01469 memcpy(t->squared_town_zone_radius, _town_squared_town_zone_radius_data[t->num_houses / 4], sizeof(t->squared_town_zone_radius));
01470 } else {
01471 int mass = t->num_houses / 8;
01472
01473
01474
01475 t->squared_town_zone_radius[0] = mass * 15 - 40;
01476 t->squared_town_zone_radius[1] = mass * 9 - 15;
01477 t->squared_town_zone_radius[2] = 0;
01478 t->squared_town_zone_radius[3] = mass * 5 - 5;
01479 t->squared_town_zone_radius[4] = mass * 3 + 5;
01480 }
01481 }
01482
01483 void UpdateTownMaxPass(Town *t)
01484 {
01485 t->pass.old_max = t->population >> 3;
01486 t->mail.old_max = t->population >> 4;
01487 }
01488
01500 static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSize size, bool city, TownLayout layout, bool manual)
01501 {
01502 t->xy = tile;
01503 t->num_houses = 0;
01504 t->time_until_rebuild = 10;
01505 UpdateTownRadius(t);
01506 t->flags = 0;
01507 t->population = 0;
01508 t->grow_counter = 0;
01509 t->growth_rate = 250;
01510 t->pass.new_max = 0;
01511 t->mail.new_max = 0;
01512 t->pass.new_act = 0;
01513 t->mail.new_act = 0;
01514 t->pass.old_max = 0;
01515 t->mail.old_max = 0;
01516 t->pass.old_act = 0;
01517 t->mail.old_act = 0;
01518
01519 t->pct_pass_transported = 0;
01520 t->pct_mail_transported = 0;
01521 t->fund_buildings_months = 0;
01522 t->new_act_food = 0;
01523 t->new_act_water = 0;
01524 t->act_food = 0;
01525 t->act_water = 0;
01526
01527 for (uint i = 0; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL;
01528
01529 t->have_ratings = 0;
01530 t->exclusivity = INVALID_COMPANY;
01531 t->exclusive_counter = 0;
01532 t->statues = 0;
01533
01534 extern int _nb_orig_names;
01535 if (_settings_game.game_creation.town_name < _nb_orig_names) {
01536
01537 t->townnamegrfid = 0;
01538 t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name;
01539 } else {
01540
01541 t->townnamegrfid = GetGRFTownNameId(_settings_game.game_creation.town_name - _nb_orig_names);
01542 t->townnametype = GetGRFTownNameType(_settings_game.game_creation.town_name - _nb_orig_names);
01543 }
01544 t->townnameparts = townnameparts;
01545
01546 t->UpdateVirtCoord();
01547 InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0);
01548
01549 t->InitializeLayout(layout);
01550
01551 t->larger_town = city;
01552
01553
01554 uint town_x = (TileX(t->xy) / AcceptanceMatrix::GRID) * AcceptanceMatrix::GRID;
01555 uint town_y = (TileY(t->xy) / AcceptanceMatrix::GRID) * AcceptanceMatrix::GRID;
01556 t->xy_aligned= TileXY(town_x, town_y);
01557
01558 int x = (int)size * 16 + 3;
01559 if (size == TSZ_RANDOM) x = (Random() & 0xF) + 8;
01560
01561 if (city && (!manual || _game_mode == GM_EDITOR)) x *= _settings_game.economy.initial_city_size;
01562
01563 t->num_houses += x;
01564 UpdateTownRadius(t);
01565
01566 int i = x * 4;
01567 do {
01568 GrowTown(t);
01569 } while (--i);
01570
01571 t->num_houses -= x;
01572 UpdateTownRadius(t);
01573 UpdateTownMaxPass(t);
01574 UpdateAirportsNoise();
01575 }
01576
01582 static CommandCost TownCanBePlacedHere(TileIndex tile)
01583 {
01584
01585 if (DistanceFromEdge(tile) < 12) {
01586 return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB);
01587 }
01588
01589
01590 if (IsCloseToTown(tile, 20)) {
01591 return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN);
01592 }
01593
01594
01595 if ((!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) || GetTileSlope(tile, NULL) != SLOPE_FLAT) {
01596 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01597 }
01598
01599 return CommandCost(EXPENSES_OTHER);
01600 }
01601
01607 static bool IsUniqueTownName(const char *name)
01608 {
01609 const Town *t;
01610
01611 FOR_ALL_TOWNS(t) {
01612 if (t->name != NULL && strcmp(t->name, name) == 0) return false;
01613 }
01614
01615 return true;
01616 }
01617
01630 CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01631 {
01632 TownSize size = Extract<TownSize, 0, 2>(p1);
01633 bool city = HasBit(p1, 2);
01634 TownLayout layout = Extract<TownLayout, 3, 3>(p1);
01635 TownNameParams par(_settings_game.game_creation.town_name);
01636 bool random = HasBit(p1, 6);
01637 uint32 townnameparts = p2;
01638
01639 if (size >= TSZ_END) return CMD_ERROR;
01640 if (layout >= NUM_TLS) return CMD_ERROR;
01641
01642
01643 if (_game_mode != GM_EDITOR) {
01644 if (_settings_game.economy.found_town == TF_FORBIDDEN) return CMD_ERROR;
01645 if (size == TSZ_LARGE) return CMD_ERROR;
01646 if (random) return CMD_ERROR;
01647 if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT && layout != _settings_game.economy.town_layout) {
01648 return CMD_ERROR;
01649 }
01650 }
01651
01652 if (StrEmpty(text)) {
01653
01654 if (!VerifyTownName(townnameparts, &par)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
01655 } else {
01656
01657 if (Utf8StringLength(text) >= MAX_LENGTH_TOWN_NAME_CHARS) return CMD_ERROR;
01658 if (!IsUniqueTownName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
01659 }
01660
01661
01662 if (!Town::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_TOWNS);
01663
01664 if (!random) {
01665 CommandCost ret = TownCanBePlacedHere(tile);
01666 if (ret.Failed()) return ret;
01667 }
01668
01669 static const byte price_mult[][TSZ_RANDOM + 1] = {{ 15, 25, 40, 25 }, { 20, 35, 55, 35 }};
01670
01671 assert_compile(lengthof(price_mult[0]) == 4);
01672
01673 CommandCost cost(EXPENSES_OTHER, _price[PR_BUILD_TOWN]);
01674 byte mult = price_mult[city][size];
01675
01676 cost.MultiplyCost(mult);
01677
01678
01679 if (flags & DC_EXEC) {
01680 if (cost.GetCost() > GetAvailableMoneyForCommand()) {
01681 _additional_cash_required = cost.GetCost();
01682 return CommandCost(EXPENSES_OTHER);
01683 }
01684
01685 _generating_world = true;
01686 UpdateNearestTownForRoadTiles(true);
01687 Town *t;
01688 if (random) {
01689 t = CreateRandomTown(20, townnameparts, size, city, layout);
01690 if (t == NULL) {
01691 cost = CommandCost(STR_ERROR_NO_SPACE_FOR_TOWN);
01692 } else {
01693 _new_town_id = t->index;
01694 }
01695 } else {
01696 t = new Town(tile);
01697 DoCreateTown(t, tile, townnameparts, size, city, layout, true);
01698 }
01699 UpdateNearestTownForRoadTiles(false);
01700 _generating_world = false;
01701
01702 if (t != NULL && !StrEmpty(text)) {
01703 t->name = strdup(text);
01704 t->UpdateVirtCoord();
01705 }
01706
01707 if (_game_mode != GM_EDITOR) {
01708
01709 assert(!random);
01710 char company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH];
01711 SetDParam(0, _current_company);
01712 GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
01713
01714 char *cn = strdup(company_name);
01715 SetDParamStr(0, cn);
01716 SetDParam(1, t->index);
01717
01718 AddNewsItem(STR_NEWS_NEW_TOWN, NS_INDUSTRY_OPEN, NR_TILE, tile, NR_NONE, UINT32_MAX, cn);
01719 AI::BroadcastNewEvent(new AIEventTownFounded(t->index));
01720 }
01721 }
01722 return cost;
01723 }
01724
01734 static TileIndex AlignTileToGrid(TileIndex tile, TownLayout layout)
01735 {
01736 switch (layout) {
01737 case TL_2X2_GRID: return TileXY(TileX(tile) - TileX(tile) % 3, TileY(tile) - TileY(tile) % 3);
01738 case TL_3X3_GRID: return TileXY(TileX(tile) & ~3, TileY(tile) & ~3);
01739 default: return tile;
01740 }
01741 }
01742
01752 static bool IsTileAlignedToGrid(TileIndex tile, TownLayout layout)
01753 {
01754 switch (layout) {
01755 case TL_2X2_GRID: return TileX(tile) % 3 == 0 && TileY(tile) % 3 == 0;
01756 case TL_3X3_GRID: return TileX(tile) % 4 == 0 && TileY(tile) % 4 == 0;
01757 default: return true;
01758 }
01759 }
01760
01764 struct SpotData {
01765 TileIndex tile;
01766 uint max_dist;
01767 TownLayout layout;
01768 };
01769
01786 static bool FindFurthestFromWater(TileIndex tile, void *user_data)
01787 {
01788 SpotData *sp = (SpotData*)user_data;
01789 uint dist = GetClosestWaterDistance(tile, true);
01790
01791 if (IsTileType(tile, MP_CLEAR) &&
01792 GetTileSlope(tile, NULL) == SLOPE_FLAT &&
01793 IsTileAlignedToGrid(tile, sp->layout) &&
01794 dist > sp->max_dist) {
01795 sp->tile = tile;
01796 sp->max_dist = dist;
01797 }
01798
01799 return false;
01800 }
01801
01808 static bool FindNearestEmptyLand(TileIndex tile, void *user_data)
01809 {
01810 return IsTileType(tile, MP_CLEAR);
01811 }
01812
01825 static TileIndex FindNearestGoodCoastalTownSpot(TileIndex tile, TownLayout layout)
01826 {
01827 SpotData sp = { INVALID_TILE, 0, layout };
01828
01829 TileIndex coast = tile;
01830 if (CircularTileSearch(&coast, 40, FindNearestEmptyLand, NULL)) {
01831 CircularTileSearch(&coast, 10, FindFurthestFromWater, &sp);
01832 return sp.tile;
01833 }
01834
01835
01836 return INVALID_TILE;
01837 }
01838
01839 static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size, bool city, TownLayout layout)
01840 {
01841 if (!Town::CanAllocateItem()) return NULL;
01842
01843 do {
01844
01845 TileIndex tile = AlignTileToGrid(RandomTile(), layout);
01846
01847
01848
01849 if (IsTileType(tile, MP_WATER)) {
01850 tile = FindNearestGoodCoastalTownSpot(tile, layout);
01851 if (tile == INVALID_TILE) continue;
01852 }
01853
01854
01855 if (TownCanBePlacedHere(tile).Failed()) continue;
01856
01857
01858 Town *t = new Town(tile);
01859
01860 DoCreateTown(t, tile, townnameparts, size, city, layout, false);
01861
01862
01863
01864 if (t->population > 0) return t;
01865 DoCommand(t->xy, t->index, 0, DC_EXEC, CMD_DELETE_TOWN);
01866
01867
01868
01869
01870
01871 assert(Town::CanAllocateItem());
01872 } while (--attempts != 0);
01873
01874 return NULL;
01875 }
01876
01877 static const byte _num_initial_towns[4] = {5, 11, 23, 46};
01878
01886 bool GenerateTowns(TownLayout layout)
01887 {
01888 uint current_number = 0;
01889 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.number_towns : 0;
01890 uint total = (difficulty == (uint)CUSTOM_TOWN_NUMBER_DIFFICULTY) ? _settings_game.game_creation.custom_town_number : ScaleByMapSize(_num_initial_towns[difficulty] + (Random() & 7));
01891 uint32 townnameparts;
01892
01893 SetGeneratingWorldProgress(GWP_TOWN, total);
01894
01895
01896
01897
01898 do {
01899 bool city = (_settings_game.economy.larger_towns != 0 && Chance16(1, _settings_game.economy.larger_towns));
01900 IncreaseGeneratingWorldProgress(GWP_TOWN);
01901
01902 if (!GenerateTownName(&townnameparts)) continue;
01903
01904 if (CreateRandomTown(20, townnameparts, TSZ_RANDOM, city, layout) != NULL) current_number++;
01905 } while (--total);
01906
01907 if (current_number != 0) return true;
01908
01909
01910
01911 if (GenerateTownName(&townnameparts) &&
01912 CreateRandomTown(10000, townnameparts, TSZ_RANDOM, _settings_game.economy.larger_towns != 0, layout) != NULL) {
01913 return true;
01914 }
01915
01916
01917 if (Town::GetNumItems() == 0 && _game_mode != GM_EDITOR) {
01918 extern StringID _switch_mode_errorstr;
01919 _switch_mode_errorstr = STR_ERROR_COULD_NOT_CREATE_TOWN;
01920 }
01921
01922 return false;
01923 }
01924
01925
01932 HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile)
01933 {
01934 uint dist = DistanceSquare(tile, t->xy);
01935
01936 if (t->fund_buildings_months && dist <= 25) return HZB_TOWN_CENTRE;
01937
01938 HouseZonesBits smallest = HZB_TOWN_EDGE;
01939 for (HouseZonesBits i = HZB_BEGIN; i < HZB_END; i++) {
01940 if (dist < t->squared_town_zone_radius[i]) smallest = i;
01941 }
01942
01943 return smallest;
01944 }
01945
01956 static inline void ClearMakeHouseTile(TileIndex tile, Town *t, byte counter, byte stage, HouseID type, byte random_bits)
01957 {
01958 CommandCost cc = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
01959
01960 assert(cc.Succeeded());
01961
01962 IncreaseBuildingCount(t, type);
01963 MakeHouseTile(tile, t->index, counter, stage, type, random_bits);
01964 if (HouseSpec::Get(type)->building_flags & BUILDING_IS_ANIMATED) AddAnimatedTile(tile);
01965
01966 MarkTileDirtyByTile(tile);
01967 }
01968
01969
01980 static void MakeTownHouse(TileIndex t, Town *town, byte counter, byte stage, HouseID type, byte random_bits)
01981 {
01982 BuildingFlags size = HouseSpec::Get(type)->building_flags;
01983
01984 ClearMakeHouseTile(t, town, counter, stage, type, random_bits);
01985 if (size & BUILDING_2_TILES_Y) ClearMakeHouseTile(t + TileDiffXY(0, 1), town, counter, stage, ++type, random_bits);
01986 if (size & BUILDING_2_TILES_X) ClearMakeHouseTile(t + TileDiffXY(1, 0), town, counter, stage, ++type, random_bits);
01987 if (size & BUILDING_HAS_4_TILES) ClearMakeHouseTile(t + TileDiffXY(1, 1), town, counter, stage, ++type, random_bits);
01988 }
01989
01990
01999 static inline bool CanBuildHouseHere(TileIndex tile, TownID town, bool noslope)
02000 {
02001
02002 Slope slope = GetTileSlope(tile, NULL);
02003 if ((noslope && slope != SLOPE_FLAT) || IsSteepSlope(slope)) return false;
02004
02005
02006 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
02007
02008
02009 if (IsTileType(tile, MP_HOUSE) && GetTownIndex(tile) != town) return false;
02010
02011
02012 return DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded();
02013 }
02014
02015
02025 static inline bool CheckBuildHouseSameZ(TileIndex tile, TownID town, uint z, bool noslope)
02026 {
02027 if (!CanBuildHouseHere(tile, town, noslope)) return false;
02028
02029
02030 if (GetTileMaxZ(tile) != z) return false;
02031
02032 return true;
02033 }
02034
02035
02045 static bool CheckFree2x2Area(TileIndex tile, TownID town, uint z, bool noslope)
02046 {
02047
02048 if (!CheckBuildHouseSameZ(tile, town, z, noslope)) return false;
02049
02050 for (DiagDirection d = DIAGDIR_SE; d < DIAGDIR_END; d++) {
02051 tile += TileOffsByDiagDir(d);
02052 if (!CheckBuildHouseSameZ(tile, town, z, noslope)) return false;
02053 }
02054
02055 return true;
02056 }
02057
02058
02066 static inline bool TownLayoutAllowsHouseHere(Town *t, TileIndex tile)
02067 {
02068
02069 if (!_settings_game.economy.allow_town_roads && !_generating_world) return true;
02070
02071 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
02072
02073 switch (t->layout) {
02074 case TL_2X2_GRID:
02075 if ((grid_pos.x % 3) == 0 || (grid_pos.y % 3) == 0) return false;
02076 break;
02077
02078 case TL_3X3_GRID:
02079 if ((grid_pos.x % 4) == 0 || (grid_pos.y % 4) == 0) return false;
02080 break;
02081
02082 default:
02083 break;
02084 }
02085
02086 return true;
02087 }
02088
02089
02097 static inline bool TownLayoutAllows2x2HouseHere(Town *t, TileIndex tile)
02098 {
02099
02100 if (!_settings_game.economy.allow_town_roads && !_generating_world) return true;
02101
02102
02103 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
02104
02105 switch (t->layout) {
02106 case TL_2X2_GRID:
02107 grid_pos.x %= 3;
02108 grid_pos.y %= 3;
02109 if ((grid_pos.x != 2 && grid_pos.x != -1) ||
02110 (grid_pos.y != 2 && grid_pos.y != -1)) return false;
02111 break;
02112
02113 case TL_3X3_GRID:
02114 if ((grid_pos.x & 3) < 2 || (grid_pos.y & 3) < 2) return false;
02115 break;
02116
02117 default:
02118 break;
02119 }
02120
02121 return true;
02122 }
02123
02124
02134 static bool CheckTownBuild2House(TileIndex *tile, Town *t, uint maxz, bool noslope, DiagDirection second)
02135 {
02136
02137
02138 TileIndex tile2 = *tile + TileOffsByDiagDir(second);
02139 if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope)) return true;
02140
02141 tile2 = *tile + TileOffsByDiagDir(ReverseDiagDir(second));
02142 if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope)) {
02143 *tile = tile2;
02144 return true;
02145 }
02146
02147 return false;
02148 }
02149
02150
02159 static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, uint maxz, bool noslope)
02160 {
02161 TileIndex tile2 = *tile;
02162
02163 for (DiagDirection d = DIAGDIR_SE;;d++) {
02164 if (TownLayoutAllows2x2HouseHere(t, tile2) && CheckFree2x2Area(tile2, t->index, maxz, noslope)) {
02165 *tile = tile2;
02166 return true;
02167 }
02168 if (d == DIAGDIR_END) break;
02169 tile2 += TileOffsByDiagDir(ReverseDiagDir(d));
02170 }
02171
02172 return false;
02173 }
02174
02175
02182 static bool BuildTownHouse(Town *t, TileIndex tile)
02183 {
02184
02185 if (!TownLayoutAllowsHouseHere(t, tile)) return false;
02186
02187
02188 if (!CanBuildHouseHere(tile, t->index, false)) return false;
02189
02190 uint z;
02191 Slope slope = GetTileSlope(tile, &z);
02192
02193
02194
02195 HouseZonesBits rad = GetTownRadiusGroup(t, tile);
02196
02197
02198 int land = _settings_game.game_creation.landscape;
02199 if (land == LT_ARCTIC && z >= _settings_game.game_creation.snow_line) land = -1;
02200
02201 uint bitmask = (1 << rad) + (1 << (land + 12));
02202
02203
02204
02205
02206 HouseID houses[HOUSE_MAX];
02207 uint num = 0;
02208 uint probs[HOUSE_MAX];
02209 uint probability_max = 0;
02210
02211
02212 for (uint i = 0; i < HOUSE_MAX; i++) {
02213 const HouseSpec *hs = HouseSpec::Get(i);
02214
02215
02216 if ((~hs->building_availability & bitmask) != 0 || !hs->enabled || hs->grf_prop.override != INVALID_HOUSE_ID) continue;
02217
02218
02219 if (hs->class_id != HOUSE_NO_CLASS) {
02220
02221 if (t->building_counts.class_count[hs->class_id] == UINT16_MAX) continue;
02222 } else {
02223
02224 if (t->building_counts.id_count[i] == UINT16_MAX) continue;
02225 }
02226
02227
02228 uint cur_prob = (_loaded_newgrf_features.has_newhouses ? hs->probability : 1);
02229 probability_max += cur_prob;
02230 probs[num] = cur_prob;
02231 houses[num++] = (HouseID)i;
02232 }
02233
02234 uint maxz = GetTileMaxZ(tile);
02235
02236 while (probability_max > 0) {
02237 uint r = RandomRange(probability_max);
02238 uint i;
02239 for (i = 0; i < num; i++) {
02240 if (probs[i] > r) break;
02241 r -= probs[i];
02242 }
02243
02244 HouseID house = houses[i];
02245 probability_max -= probs[i];
02246
02247
02248 num--;
02249 houses[i] = houses[num];
02250 probs[i] = probs[num];
02251
02252 const HouseSpec *hs = HouseSpec::Get(house);
02253
02254 if (_loaded_newgrf_features.has_newhouses && !_generating_world &&
02255 _game_mode != GM_EDITOR && (hs->extra_flags & BUILDING_IS_HISTORICAL) != 0) {
02256 continue;
02257 }
02258
02259 if (_cur_year < hs->min_year || _cur_year > hs->max_year) continue;
02260
02261
02262 uint oneof = 0;
02263
02264 if (hs->building_flags & BUILDING_IS_CHURCH) {
02265 SetBit(oneof, TOWN_HAS_CHURCH);
02266 } else if (hs->building_flags & BUILDING_IS_STADIUM) {
02267 SetBit(oneof, TOWN_HAS_STADIUM);
02268 }
02269
02270 if (t->flags & oneof) continue;
02271
02272
02273 bool noslope = (hs->building_flags & TILE_NOT_SLOPED) != 0;
02274 if (noslope && slope != SLOPE_FLAT) continue;
02275
02276 if (hs->building_flags & TILE_SIZE_2x2) {
02277 if (!CheckTownBuild2x2House(&tile, t, maxz, noslope)) continue;
02278 } else if (hs->building_flags & TILE_SIZE_2x1) {
02279 if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SW)) continue;
02280 } else if (hs->building_flags & TILE_SIZE_1x2) {
02281 if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SE)) continue;
02282 } else {
02283
02284 }
02285
02286 byte random_bits = Random();
02287
02288 if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
02289 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile, true, random_bits);
02290 if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) == 0) continue;
02291 }
02292
02293
02294 t->num_houses++;
02295
02296
02297 t->flags |= oneof;
02298
02299 byte construction_counter = 0;
02300 byte construction_stage = 0;
02301
02302 if (_generating_world || _game_mode == GM_EDITOR) {
02303 uint32 r = Random();
02304
02305 construction_stage = TOWN_HOUSE_COMPLETED;
02306 if (Chance16(1, 7)) construction_stage = GB(r, 0, 2);
02307
02308 if (construction_stage == TOWN_HOUSE_COMPLETED) {
02309 ChangePopulation(t, hs->population);
02310 } else {
02311 construction_counter = GB(r, 2, 2);
02312 }
02313 }
02314
02315 MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits);
02316 UpdateTownCargos(t, tile);
02317
02318 return true;
02319 }
02320
02321 return false;
02322 }
02323
02330 static void DoClearTownHouseHelper(TileIndex tile, Town *t, HouseID house)
02331 {
02332 assert(IsTileType(tile, MP_HOUSE));
02333 DecreaseBuildingCount(t, house);
02334 DoClearSquare(tile);
02335 DeleteAnimatedTile(tile);
02336
02337 DeleteNewGRFInspectWindow(GSF_HOUSES, tile);
02338 }
02339
02347 TileIndexDiff GetHouseNorthPart(HouseID &house)
02348 {
02349 if (house >= 3) {
02350 if (HouseSpec::Get(house - 1)->building_flags & TILE_SIZE_2x1) {
02351 house--;
02352 return TileDiffXY(-1, 0);
02353 } else if (HouseSpec::Get(house - 1)->building_flags & BUILDING_2_TILES_Y) {
02354 house--;
02355 return TileDiffXY(0, -1);
02356 } else if (HouseSpec::Get(house - 2)->building_flags & BUILDING_HAS_4_TILES) {
02357 house -= 2;
02358 return TileDiffXY(-1, 0);
02359 } else if (HouseSpec::Get(house - 3)->building_flags & BUILDING_HAS_4_TILES) {
02360 house -= 3;
02361 return TileDiffXY(-1, -1);
02362 }
02363 }
02364 return 0;
02365 }
02366
02367 void ClearTownHouse(Town *t, TileIndex tile)
02368 {
02369 assert(IsTileType(tile, MP_HOUSE));
02370
02371 HouseID house = GetHouseType(tile);
02372
02373
02374 tile += GetHouseNorthPart(house);
02375
02376 const HouseSpec *hs = HouseSpec::Get(house);
02377
02378
02379 if (IsHouseCompleted(tile)) {
02380 ChangePopulation(t, -hs->population);
02381 }
02382
02383 t->num_houses--;
02384
02385
02386 if (hs->building_flags & BUILDING_IS_CHURCH) {
02387 ClrBit(t->flags, TOWN_HAS_CHURCH);
02388 } else if (hs->building_flags & BUILDING_IS_STADIUM) {
02389 ClrBit(t->flags, TOWN_HAS_STADIUM);
02390 }
02391
02392
02393 uint eflags = hs->building_flags;
02394 DoClearTownHouseHelper(tile, t, house);
02395 if (eflags & BUILDING_2_TILES_Y) DoClearTownHouseHelper(tile + TileDiffXY(0, 1), t, ++house);
02396 if (eflags & BUILDING_2_TILES_X) DoClearTownHouseHelper(tile + TileDiffXY(1, 0), t, ++house);
02397 if (eflags & BUILDING_HAS_4_TILES) DoClearTownHouseHelper(tile + TileDiffXY(1, 1), t, ++house);
02398
02399
02400 UpdateTownCargos(t, tile);
02401 }
02402
02412 CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
02413 {
02414 Town *t = Town::GetIfValid(p1);
02415 if (t == NULL) return CMD_ERROR;
02416
02417 bool reset = StrEmpty(text);
02418
02419 if (!reset) {
02420 if (Utf8StringLength(text) >= MAX_LENGTH_TOWN_NAME_CHARS) return CMD_ERROR;
02421 if (!IsUniqueTownName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
02422 }
02423
02424 if (flags & DC_EXEC) {
02425 free(t->name);
02426 t->name = reset ? NULL : strdup(text);
02427
02428 t->UpdateVirtCoord();
02429 InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1);
02430 InvalidateWindowClassesData(WC_TOWN_VIEW);
02431 InvalidateWindowClassesData(WC_INDUSTRY_VIEW);
02432 UpdateAllStationVirtCoords();
02433 }
02434 return CommandCost();
02435 }
02436
02446 CommandCost CmdExpandTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
02447 {
02448 if (_game_mode != GM_EDITOR) return CMD_ERROR;
02449 Town *t = Town::GetIfValid(p1);
02450 if (t == NULL) return CMD_ERROR;
02451
02452 if (flags & DC_EXEC) {
02453
02454 uint amount = RandomRange(ClampToU16(t->num_houses / 10)) + 3;
02455 t->num_houses += amount;
02456 UpdateTownRadius(t);
02457
02458 uint n = amount * 10;
02459 do GrowTown(t); while (--n);
02460
02461 t->num_houses -= amount;
02462 UpdateTownRadius(t);
02463
02464 UpdateTownMaxPass(t);
02465 }
02466
02467 return CommandCost();
02468 }
02469
02479 CommandCost CmdDeleteTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
02480 {
02481 if (_game_mode != GM_EDITOR) return CMD_ERROR;
02482 Town *t = Town::GetIfValid(p1);
02483 if (t == NULL) return CMD_ERROR;
02484
02485
02486 const Station *st;
02487 FOR_ALL_STATIONS(st) {
02488 if (st->town == t) {
02489
02490 if (!(st->facilities & FACIL_AIRPORT) || st->airport.type != AT_OILRIG) return CMD_ERROR;
02491
02492 CommandCost ret = DoCommand(st->airport.tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02493 if (ret.Failed()) return ret;
02494 }
02495 }
02496
02497
02498 const Depot *d;
02499 FOR_ALL_DEPOTS(d) {
02500 if (d->town == t) return CMD_ERROR;
02501 }
02502
02503
02504 for (TileIndex tile = 0; tile < MapSize(); ++tile) {
02505 bool try_clear = false;
02506 switch (GetTileType(tile)) {
02507 case MP_ROAD:
02508 try_clear = HasTownOwnedRoad(tile) && GetTownIndex(tile) == t->index;
02509 break;
02510
02511 case MP_TUNNELBRIDGE:
02512 try_clear = IsTileOwner(tile, OWNER_TOWN) && ClosestTownFromTile(tile, UINT_MAX) == t;
02513 break;
02514
02515 case MP_HOUSE:
02516 try_clear = GetTownIndex(tile) == t->index;
02517 break;
02518
02519 case MP_INDUSTRY:
02520 try_clear = Industry::GetByTile(tile)->town == t;
02521 break;
02522
02523 case MP_OBJECT:
02524 if (Town::GetNumItems() == 1) {
02525
02526 try_clear = true;
02527 } else {
02528 Object *o = Object::GetByTile(tile);
02529 if (o->town == t) {
02530 if (GetObjectType(tile) == OBJECT_STATUE) {
02531
02532 try_clear = true;
02533 } else {
02534
02535 if (flags & DC_EXEC) o->town = NULL;
02536 }
02537 }
02538 }
02539 break;
02540
02541 default:
02542 break;
02543 }
02544 if (try_clear) {
02545 CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02546 if (ret.Failed()) return ret;
02547 }
02548 }
02549
02550
02551 if (flags & DC_EXEC) delete t;
02552
02553 return CommandCost();
02554 }
02555
02560 const byte _town_action_costs[TACT_COUNT] = {
02561 2, 4, 9, 35, 48, 53, 117, 175
02562 };
02563
02564 static CommandCost TownActionAdvertiseSmall(Town *t, DoCommandFlag flags)
02565 {
02566 if (flags & DC_EXEC) {
02567 ModifyStationRatingAround(t->xy, _current_company, 0x40, 10);
02568 }
02569 return CommandCost();
02570 }
02571
02572 static CommandCost TownActionAdvertiseMedium(Town *t, DoCommandFlag flags)
02573 {
02574 if (flags & DC_EXEC) {
02575 ModifyStationRatingAround(t->xy, _current_company, 0x70, 15);
02576 }
02577 return CommandCost();
02578 }
02579
02580 static CommandCost TownActionAdvertiseLarge(Town *t, DoCommandFlag flags)
02581 {
02582 if (flags & DC_EXEC) {
02583 ModifyStationRatingAround(t->xy, _current_company, 0xA0, 20);
02584 }
02585 return CommandCost();
02586 }
02587
02588 static CommandCost TownActionRoadRebuild(Town *t, DoCommandFlag flags)
02589 {
02590
02591 if (!_settings_game.economy.fund_roads) return CMD_ERROR;
02592
02593 if (flags & DC_EXEC) {
02594 t->road_build_months = 6;
02595
02596 char company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH];
02597 SetDParam(0, _current_company);
02598 GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
02599
02600 char *cn = strdup(company_name);
02601 SetDParam(0, t->index);
02602 SetDParamStr(1, cn);
02603
02604 AddNewsItem(STR_NEWS_ROAD_REBUILDING, NS_GENERAL, NR_TOWN, t->index, NR_NONE, UINT32_MAX, cn);
02605 }
02606 return CommandCost();
02607 }
02608
02615 static bool SearchTileForStatue(TileIndex tile, void *user_data)
02616 {
02617
02618 if (IsSteepSlope(GetTileSlope(tile, NULL))) return false;
02619
02620 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
02621
02622 if (!IsTileType(tile, MP_HOUSE) &&
02623 !IsTileType(tile, MP_CLEAR) &&
02624 !IsTileType(tile, MP_TREES)) {
02625 return false;
02626 }
02627
02628 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
02629 CommandCost r = DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
02630 cur_company.Restore();
02631
02632 if (r.Failed()) return false;
02633
02634 return true;
02635 }
02636
02644 static CommandCost TownActionBuildStatue(Town *t, DoCommandFlag flags)
02645 {
02646 if (!Object::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_OBJECTS);
02647
02648 TileIndex tile = t->xy;
02649 if (CircularTileSearch(&tile, 9, SearchTileForStatue, NULL)) {
02650 if (flags & DC_EXEC) {
02651 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
02652 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
02653 cur_company.Restore();
02654 BuildObject(OBJECT_STATUE, tile, _current_company, t);
02655 SetBit(t->statues, _current_company);
02656 MarkTileDirtyByTile(tile);
02657 }
02658 return CommandCost();
02659 }
02660 return_cmd_error(STR_ERROR_STATUE_NO_SUITABLE_PLACE);
02661 }
02662
02663 static CommandCost TownActionFundBuildings(Town *t, DoCommandFlag flags)
02664 {
02665 if (flags & DC_EXEC) {
02666
02667 t->grow_counter = 1;
02668
02669 SetBit(t->flags, TOWN_IS_FUNDED);
02670
02671 t->fund_buildings_months = 3;
02672 }
02673 return CommandCost();
02674 }
02675
02676 static CommandCost TownActionBuyRights(Town *t, DoCommandFlag flags)
02677 {
02678
02679 if (!_settings_game.economy.exclusive_rights) return CMD_ERROR;
02680
02681 if (flags & DC_EXEC) {
02682 t->exclusive_counter = 12;
02683 t->exclusivity = _current_company;
02684
02685 ModifyStationRatingAround(t->xy, _current_company, 130, 17);
02686 }
02687 return CommandCost();
02688 }
02689
02690 static CommandCost TownActionBribe(Town *t, DoCommandFlag flags)
02691 {
02692 if (flags & DC_EXEC) {
02693 if (Chance16(1, 14)) {
02694
02695 t->unwanted[_current_company] = 6;
02696
02697
02698 Station *st;
02699 FOR_ALL_STATIONS(st) {
02700 if (st->town == t && st->owner == _current_company) {
02701 for (CargoID i = 0; i < NUM_CARGO; i++) st->goods[i].rating = 0;
02702 }
02703 }
02704
02705
02706
02707 if (IsLocalCompany()) ShowErrorMessage(STR_ERROR_BRIBE_FAILED, STR_ERROR_BRIBE_FAILED_2, WL_INFO);
02708
02709
02710
02711
02712
02713 if (t->ratings[_current_company] > RATING_BRIBE_DOWN_TO) {
02714 t->ratings[_current_company] = RATING_BRIBE_DOWN_TO;
02715 SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
02716 }
02717 } else {
02718 ChangeTownRating(t, RATING_BRIBE_UP_STEP, RATING_BRIBE_MAXIMUM, DC_EXEC);
02719 }
02720 }
02721 return CommandCost();
02722 }
02723
02724 typedef CommandCost TownActionProc(Town *t, DoCommandFlag flags);
02725 static TownActionProc * const _town_action_proc[] = {
02726 TownActionAdvertiseSmall,
02727 TownActionAdvertiseMedium,
02728 TownActionAdvertiseLarge,
02729 TownActionRoadRebuild,
02730 TownActionBuildStatue,
02731 TownActionFundBuildings,
02732 TownActionBuyRights,
02733 TownActionBribe
02734 };
02735
02743 uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t)
02744 {
02745 int num = 0;
02746 TownActions buttons = TACT_NONE;
02747
02748
02749 if (cid != COMPANY_SPECTATOR && !(_settings_game.economy.bribe && t->unwanted[cid])) {
02750
02751
02752 Money avail = Company::Get(cid)->money + _price[PR_STATION_VALUE] * 200;
02753
02754
02755
02756 for (uint i = 0; i != lengthof(_town_action_costs); i++) {
02757 const TownActions cur = (TownActions)(1 << i);
02758
02759
02760 if (cur == TACT_BRIBE && (!_settings_game.economy.bribe || t->ratings[cid] >= RATING_BRIBE_MAXIMUM)) continue;
02761
02762
02763 if (cur == TACT_BUY_RIGHTS && !_settings_game.economy.exclusive_rights) continue;
02764
02765
02766 if (cur == TACT_ROAD_REBUILD && !_settings_game.economy.fund_roads) continue;
02767
02768
02769 if (cur == TACT_BUILD_STATUE && HasBit(t->statues, cid)) continue;
02770
02771 if (avail >= _town_action_costs[i] * _price[PR_TOWN_ACTION] >> 8) {
02772 buttons |= cur;
02773 num++;
02774 }
02775 }
02776 }
02777
02778 if (nump != NULL) *nump = num;
02779 return buttons;
02780 }
02781
02793 CommandCost CmdDoTownAction(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
02794 {
02795 Town *t = Town::GetIfValid(p1);
02796 if (t == NULL || p2 >= lengthof(_town_action_proc)) return CMD_ERROR;
02797
02798 if (!HasBit(GetMaskOfTownActions(NULL, _current_company, t), p2)) return CMD_ERROR;
02799
02800 CommandCost cost(EXPENSES_OTHER, _price[PR_TOWN_ACTION] * _town_action_costs[p2] >> 8);
02801
02802 CommandCost ret = _town_action_proc[p2](t, flags);
02803 if (ret.Failed()) return ret;
02804
02805 if (flags & DC_EXEC) {
02806 SetWindowDirty(WC_TOWN_AUTHORITY, p1);
02807 }
02808
02809 return cost;
02810 }
02811
02812 static void UpdateTownGrowRate(Town *t)
02813 {
02814
02815 const Company *c;
02816 FOR_ALL_COMPANIES(c) {
02817 if (t->ratings[c->index] < RATING_GROWTH_MAXIMUM) {
02818 t->ratings[c->index] = min((int)RATING_GROWTH_MAXIMUM, t->ratings[c->index] + RATING_GROWTH_UP_STEP);
02819 }
02820 }
02821
02822 int n = 0;
02823
02824 const Station *st;
02825 FOR_ALL_STATIONS(st) {
02826 if (DistanceSquare(st->xy, t->xy) <= t->squared_town_zone_radius[0]) {
02827 if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
02828 n++;
02829 if (Company::IsValidID(st->owner)) {
02830 int new_rating = t->ratings[st->owner] + RATING_STATION_UP_STEP;
02831 t->ratings[st->owner] = min(new_rating, INT16_MAX);
02832 }
02833 } else {
02834 if (Company::IsValidID(st->owner)) {
02835 int new_rating = t->ratings[st->owner] + RATING_STATION_DOWN_STEP;
02836 t->ratings[st->owner] = max(new_rating, INT16_MIN);
02837 }
02838 }
02839 }
02840 }
02841
02842
02843 for (uint i = 0; i < MAX_COMPANIES; i++) {
02844 t->ratings[i] = Clamp(t->ratings[i], RATING_MINIMUM, RATING_MAXIMUM);
02845 }
02846
02847 SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
02848
02849 ClrBit(t->flags, TOWN_IS_FUNDED);
02850 if (_settings_game.economy.town_growth_rate == 0 && t->fund_buildings_months == 0) return;
02851
02856 static const uint16 _grow_count_values[2][6] = {
02857 { 120, 120, 120, 100, 80, 60 },
02858 { 320, 420, 300, 220, 160, 100 }
02859 };
02860
02861 uint16 m;
02862
02863 if (t->fund_buildings_months != 0) {
02864 m = _grow_count_values[0][min(n, 5)];
02865 t->fund_buildings_months--;
02866 } else {
02867 m = _grow_count_values[1][min(n, 5)];
02868 if (n == 0 && !Chance16(1, 12)) return;
02869 }
02870
02871 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
02872 if (TilePixelHeight(t->xy) >= GetSnowLine() && t->act_food == 0 && t->population > 90) return;
02873
02874 } else if (_settings_game.game_creation.landscape == LT_TROPIC) {
02875 if (GetTropicZone(t->xy) == TROPICZONE_DESERT && (t->act_food == 0 || t->act_water == 0) && t->population > 60) return;
02876 }
02877
02878
02879
02880 uint growth_multiplier = _settings_game.economy.town_growth_rate != 0 ? _settings_game.economy.town_growth_rate - 1 : 1;
02881
02882 m >>= growth_multiplier;
02883 if (t->larger_town) m /= 2;
02884
02885 t->growth_rate = m / (t->num_houses / 50 + 1);
02886 if (m <= t->grow_counter) {
02887 t->grow_counter = m;
02888 }
02889
02890 SetBit(t->flags, TOWN_IS_FUNDED);
02891 }
02892
02893 static void UpdateTownAmounts(Town *t)
02894 {
02895
02896 t->pct_pass_transported = t->pass.new_act * 256 / (t->pass.new_max + 1);
02897
02898 t->pass.NewMonth();
02899 t->act_food = t->new_act_food; t->new_act_food = 0;
02900 t->act_water = t->new_act_water; t->new_act_water = 0;
02901
02902
02903 t->pct_mail_transported = t->mail.new_act * 256 / (t->mail.new_max + 1);
02904 t->mail.NewMonth();
02905
02906 SetWindowDirty(WC_TOWN_VIEW, t->index);
02907 }
02908
02909 static void UpdateTownUnwanted(Town *t)
02910 {
02911 const Company *c;
02912
02913 FOR_ALL_COMPANIES(c) {
02914 if (t->unwanted[c->index] > 0) t->unwanted[c->index]--;
02915 }
02916 }
02917
02924 CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags)
02925 {
02926 if (!Company::IsValidID(_current_company) || (flags & DC_NO_TEST_TOWN_RATING)) return CommandCost();
02927
02928 Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority);
02929 if (t == NULL) return CommandCost();
02930
02931 if (t->ratings[_current_company] > RATING_VERYPOOR) return CommandCost();
02932
02933 SetDParam(0, t->index);
02934 return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
02935 }
02936
02945 Town *CalcClosestTownFromTile(TileIndex tile, uint threshold)
02946 {
02947 Town *t;
02948 uint best = threshold;
02949 Town *best_town = NULL;
02950
02951 FOR_ALL_TOWNS(t) {
02952 uint dist = DistanceManhattan(tile, t->xy);
02953 if (dist < best) {
02954 best = dist;
02955 best_town = t;
02956 }
02957 }
02958
02959 return best_town;
02960 }
02961
02970 Town *ClosestTownFromTile(TileIndex tile, uint threshold)
02971 {
02972 switch (GetTileType(tile)) {
02973 case MP_ROAD:
02974 if (IsRoadDepot(tile)) return CalcClosestTownFromTile(tile, threshold);
02975
02976 if (!HasTownOwnedRoad(tile)) {
02977 TownID tid = GetTownIndex(tile);
02978
02979 if (tid == (TownID)INVALID_TOWN) {
02980
02981 if (_generating_world) return CalcClosestTownFromTile(tile, threshold);
02982 assert(Town::GetNumItems() == 0);
02983 return NULL;
02984 }
02985
02986 assert(Town::IsValidID(tid));
02987 Town *town = Town::Get(tid);
02988
02989 if (DistanceManhattan(tile, town->xy) >= threshold) town = NULL;
02990
02991 return town;
02992 }
02993
02994
02995 case MP_HOUSE:
02996 return Town::GetByTile(tile);
02997
02998 default:
02999 return CalcClosestTownFromTile(tile, threshold);
03000 }
03001 }
03002
03003 static bool _town_rating_test = false;
03004 static SmallMap<const Town *, int, 4> _town_test_ratings;
03005
03011 void SetTownRatingTestMode(bool mode)
03012 {
03013 static int ref_count = 0;
03014 if (mode) {
03015 if (ref_count == 0) {
03016 _town_test_ratings.Clear();
03017 }
03018 ref_count++;
03019 } else {
03020 assert(ref_count > 0);
03021 ref_count--;
03022 }
03023 _town_rating_test = !(ref_count == 0);
03024 }
03025
03031 static int GetRating(const Town *t)
03032 {
03033 if (_town_rating_test) {
03034 SmallMap<const Town *, int>::iterator it = _town_test_ratings.Find(t);
03035 if (it != _town_test_ratings.End()) {
03036 return it->second;
03037 }
03038 }
03039 return t->ratings[_current_company];
03040 }
03041
03049 void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags)
03050 {
03051
03052 if (t == NULL || (flags & DC_NO_MODIFY_TOWN_RATING) ||
03053 !Company::IsValidID(_current_company) ||
03054 (_cheats.magic_bulldozer.value && add < 0)) {
03055 return;
03056 }
03057
03058 int rating = GetRating(t);
03059 if (add < 0) {
03060 if (rating > max) {
03061 rating += add;
03062 if (rating < max) rating = max;
03063 }
03064 } else {
03065 if (rating < max) {
03066 rating += add;
03067 if (rating > max) rating = max;
03068 }
03069 }
03070 if (_town_rating_test) {
03071 _town_test_ratings[t] = rating;
03072 } else {
03073 SetBit(t->have_ratings, _current_company);
03074 t->ratings[_current_company] = rating;
03075 SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
03076 }
03077 }
03078
03086 CommandCost CheckforTownRating(DoCommandFlag flags, Town *t, TownRatingCheckType type)
03087 {
03088
03089 if (t == NULL || !Company::IsValidID(_current_company) ||
03090 _cheats.magic_bulldozer.value || (flags & DC_NO_TEST_TOWN_RATING)) {
03091 return CommandCost();
03092 }
03093
03094
03095 static const int needed_rating[][TOWN_RATING_CHECK_TYPE_COUNT] = {
03096
03097 { RATING_ROAD_NEEDED_PERMISSIVE, RATING_TUNNEL_BRIDGE_NEEDED_PERMISSIVE},
03098 { RATING_ROAD_NEEDED_NEUTRAL, RATING_TUNNEL_BRIDGE_NEEDED_NEUTRAL},
03099 { RATING_ROAD_NEEDED_HOSTILE, RATING_TUNNEL_BRIDGE_NEEDED_HOSTILE},
03100 };
03101
03102
03103
03104
03105
03106 int needed = needed_rating[_settings_game.difficulty.town_council_tolerance][type];
03107
03108 if (GetRating(t) < needed) {
03109 SetDParam(0, t->index);
03110 return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
03111 }
03112
03113 return CommandCost();
03114 }
03115
03116 void TownsMonthlyLoop()
03117 {
03118 Town *t;
03119
03120 FOR_ALL_TOWNS(t) {
03121 if (t->road_build_months != 0) t->road_build_months--;
03122
03123 if (t->exclusive_counter != 0) {
03124 if (--t->exclusive_counter == 0) t->exclusivity = INVALID_COMPANY;
03125 }
03126
03127 UpdateTownGrowRate(t);
03128 UpdateTownAmounts(t);
03129 UpdateTownUnwanted(t);
03130 UpdateTownCargos(t);
03131 }
03132 }
03133
03134 void TownsYearlyLoop()
03135 {
03136
03137 for (TileIndex t = 0; t < MapSize(); t++) {
03138 if (!IsTileType(t, MP_HOUSE)) continue;
03139 IncrementHouseAge(t);
03140 }
03141 }
03142
03143 static CommandCost TerraformTile_Town(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
03144 {
03145 if (AutoslopeEnabled()) {
03146 HouseID house = GetHouseType(tile);
03147 GetHouseNorthPart(house);
03148 const HouseSpec *hs = HouseSpec::Get(house);
03149
03150
03151 if (((hs->building_flags & TILE_NOT_SLOPED) == 0) && !IsSteepSlope(tileh_new) &&
03152 (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
03153 bool allow_terraform = true;
03154
03155
03156 house = GetHouseType(tile);
03157 hs = HouseSpec::Get(house);
03158 if (HasBit(hs->callback_mask, CBM_HOUSE_AUTOSLOPE)) {
03159
03160 uint16 res = GetHouseCallback(CBID_HOUSE_AUTOSLOPE, 0, 0, house, Town::GetByTile(tile), tile);
03161 if ((res != 0) && (res != CALLBACK_FAILED)) allow_terraform = false;
03162 }
03163
03164 if (allow_terraform) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
03165 }
03166 }
03167
03168 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
03169 }
03170
03172 extern const TileTypeProcs _tile_type_town_procs = {
03173 DrawTile_Town,
03174 GetSlopeZ_Town,
03175 ClearTile_Town,
03176 AddAcceptedCargo_Town,
03177 GetTileDesc_Town,
03178 GetTileTrackStatus_Town,
03179 NULL,
03180 AnimateTile_Town,
03181 TileLoop_Town,
03182 ChangeTileOwner_Town,
03183 AddProducedCargo_Town,
03184 NULL,
03185 GetFoundation_Town,
03186 TerraformTile_Town,
03187 };
03188
03189
03190 HouseSpec _house_specs[HOUSE_MAX];
03191
03192 void ResetHouses()
03193 {
03194 memset(&_house_specs, 0, sizeof(_house_specs));
03195 memcpy(&_house_specs, &_original_house_specs, sizeof(_original_house_specs));
03196
03197
03198 _house_mngr.ResetOverride();
03199 }