00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "openttd.h"
00014 #include "road_type.h"
00015 #include "road_internal.h"
00016 #include "road_cmd.h"
00017 #include "landscape.h"
00018 #include "viewport_func.h"
00019 #include "command_func.h"
00020 #include "industry.h"
00021 #include "station_base.h"
00022 #include "company_base.h"
00023 #include "news_func.h"
00024 #include "gui.h"
00025 #include "unmovable_map.h"
00026 #include "variables.h"
00027 #include "genworld.h"
00028 #include "newgrf.h"
00029 #include "newgrf_house.h"
00030 #include "newgrf_commons.h"
00031 #include "newgrf_text.h"
00032 #include "autoslope.h"
00033 #include "transparency.h"
00034 #include "tunnelbridge_map.h"
00035 #include "strings_func.h"
00036 #include "window_func.h"
00037 #include "string_func.h"
00038 #include "newgrf_cargo.h"
00039 #include "cheat_type.h"
00040 #include "functions.h"
00041 #include "animated_tile_func.h"
00042 #include "date_func.h"
00043 #include "subsidy_func.h"
00044 #include "core/smallmap_type.hpp"
00045 #include "core/pool_func.hpp"
00046 #include "town.h"
00047 #include "townname_func.h"
00048 #include "townname_type.h"
00049
00050 #include "table/strings.h"
00051 #include "table/town_land.h"
00052
00053 static Town *_cleared_town;
00054 static int _cleared_town_rating;
00055 TownID _new_town_id;
00056
00057
00058 TownPool _town_pool("Town");
00059 INSTANTIATE_POOL_METHODS(Town)
00060
00061 Town::~Town()
00062 {
00063 free(this->name);
00064
00065 if (CleaningPool()) return;
00066
00067 Industry *i;
00068
00069
00070
00071 DeleteWindowById(WC_TOWN_VIEW, this->index);
00072
00073
00074 FOR_ALL_INDUSTRIES(i) if (i->town == this) delete i;
00075
00076
00077 for (TileIndex tile = 0; tile < MapSize(); ++tile) {
00078 switch (GetTileType(tile)) {
00079 case MP_HOUSE:
00080 if (Town::GetByTile(tile) == this) DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
00081 break;
00082
00083 case MP_ROAD:
00084
00085 if (HasTownOwnedRoad(tile) && GetTownIndex(tile) == this->index) {
00086 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
00087 }
00088 break;
00089
00090 case MP_TUNNELBRIDGE:
00091 if (IsTileOwner(tile, OWNER_TOWN) &&
00092 ClosestTownFromTile(tile, UINT_MAX) == this)
00093 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
00094 break;
00095
00096 default:
00097 break;
00098 }
00099 }
00100
00101 DeleteSubsidyWith(ST_TOWN, this->index);
00102 CargoPacket::InvalidateAllFrom(ST_TOWN, this->index);
00103 MarkWholeScreenDirty();
00104 }
00105
00106
00112 void Town::PostDestructor(size_t index)
00113 {
00114 InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0);
00115 UpdateNearestTownForRoadTiles(false);
00116 }
00117
00121 void Town::InitializeLayout(TownLayout layout)
00122 {
00123 if (layout != TL_RANDOM) {
00124 this->layout = layout;
00125 return;
00126 }
00127
00128 this->layout = TileHash(TileX(this->xy), TileY(this->xy)) % (NUM_TLS - 1);
00129 }
00130
00135 Town *Town::GetRandom()
00136 {
00137 if (Town::GetNumItems() == 0) return NULL;
00138 int num = RandomRange((uint16)Town::GetNumItems());
00139 size_t index = MAX_UVALUE(size_t);
00140
00141 while (num >= 0) {
00142 num--;
00143 index++;
00144
00145
00146 while (!Town::IsValidID(index)) {
00147 index++;
00148 assert(index < Town::GetPoolSize());
00149 }
00150 }
00151
00152 return Town::Get(index);
00153 }
00154
00155 Money HouseSpec::GetRemovalCost() const
00156 {
00157 return (_price[PR_CLEAR_HOUSE] * this->removal_cost) >> 8;
00158 }
00159
00160
00161 static int _grow_town_result;
00162
00163
00164 enum TownGrowthResult {
00165 GROWTH_SUCCEED = -1,
00166 GROWTH_SEARCH_STOPPED = 0
00167
00168 };
00169
00170 static bool BuildTownHouse(Town *t, TileIndex tile);
00171 static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size, bool city, TownLayout layout);
00172
00173 static void TownDrawHouseLift(const TileInfo *ti)
00174 {
00175 AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile));
00176 }
00177
00178 typedef void TownDrawTileProc(const TileInfo *ti);
00179 static TownDrawTileProc * const _town_draw_tile_procs[1] = {
00180 TownDrawHouseLift
00181 };
00182
00188 static inline DiagDirection RandomDiagDir()
00189 {
00190 return (DiagDirection)(3 & Random());
00191 }
00192
00198 static void DrawTile_Town(TileInfo *ti)
00199 {
00200 HouseID house_id = GetHouseType(ti->tile);
00201
00202 if (house_id >= NEW_HOUSE_OFFSET) {
00203
00204
00205
00206 if (HouseSpec::Get(house_id)->spritegroup != NULL) {
00207 DrawNewHouseTile(ti, house_id);
00208 return;
00209 } else {
00210 house_id = HouseSpec::Get(house_id)->substitute_id;
00211 }
00212 }
00213
00214
00215 const DrawBuildingsTileStruct *dcts = &_town_draw_tile_data[house_id << 4 | TileHash2Bit(ti->x, ti->y) << 2 | GetHouseBuildingStage(ti->tile)];
00216
00217 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
00218
00219 DrawGroundSprite(dcts->ground.sprite, dcts->ground.pal);
00220
00221
00222 if (IsInvisibilitySet(TO_HOUSES)) return;
00223
00224
00225 SpriteID image = dcts->building.sprite;
00226 if (image != 0) {
00227 AddSortableSpriteToDraw(image, dcts->building.pal,
00228 ti->x + dcts->subtile_x,
00229 ti->y + dcts->subtile_y,
00230 dcts->width,
00231 dcts->height,
00232 dcts->dz,
00233 ti->z,
00234 IsTransparencySet(TO_HOUSES)
00235 );
00236
00237 if (IsTransparencySet(TO_HOUSES)) return;
00238 }
00239
00240 {
00241 int proc = dcts->draw_proc - 1;
00242
00243 if (proc >= 0) _town_draw_tile_procs[proc](ti);
00244 }
00245 }
00246
00247 static uint GetSlopeZ_Town(TileIndex tile, uint x, uint y)
00248 {
00249 return GetTileMaxZ(tile);
00250 }
00251
00253 static Foundation GetFoundation_Town(TileIndex tile, Slope tileh)
00254 {
00255 HouseID hid = GetHouseType(tile);
00256
00257
00258
00259
00260
00261 if (hid >= NEW_HOUSE_OFFSET) {
00262 const HouseSpec *hs = HouseSpec::Get(hid);
00263 if (hs->spritegroup != NULL && HasBit(hs->callback_mask, CBM_HOUSE_DRAW_FOUNDATIONS)) {
00264 uint32 callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, hid, Town::GetByTile(tile), tile);
00265 if (callback_res == 0) return FOUNDATION_NONE;
00266 }
00267 }
00268 return FlatteningFoundation(tileh);
00269 }
00270
00277 static void AnimateTile_Town(TileIndex tile)
00278 {
00279 if (GetHouseType(tile) >= NEW_HOUSE_OFFSET) {
00280 AnimateNewHouseTile(tile);
00281 return;
00282 }
00283
00284 if (_tick_counter & 3) return;
00285
00286
00287
00288
00289
00290 if (!(HouseSpec::Get(GetHouseType(tile))->building_flags & BUILDING_IS_ANIMATED)) {
00291 DeleteAnimatedTile(tile);
00292 return;
00293 }
00294
00295 if (!LiftHasDestination(tile)) {
00296 uint i;
00297
00298
00299
00300
00301
00302 do {
00303 i = RandomRange(7);
00304 } while (i == 1 || i * 6 == GetLiftPosition(tile));
00305
00306 SetLiftDestination(tile, i);
00307 }
00308
00309 int pos = GetLiftPosition(tile);
00310 int dest = GetLiftDestination(tile) * 6;
00311 pos += (pos < dest) ? 1 : -1;
00312 SetLiftPosition(tile, pos);
00313
00314 if (pos == dest) {
00315 HaltLift(tile);
00316 DeleteAnimatedTile(tile);
00317 }
00318
00319 MarkTileDirtyByTile(tile);
00320 }
00321
00328 static bool IsCloseToTown(TileIndex tile, uint dist)
00329 {
00330 const Town *t;
00331
00332 FOR_ALL_TOWNS(t) {
00333 if (DistanceManhattan(tile, t->xy) < dist) return true;
00334 }
00335 return false;
00336 }
00337
00342 void Town::UpdateVirtCoord()
00343 {
00344 Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE);
00345 SetDParam(0, this->index);
00346 SetDParam(1, this->population);
00347 this->sign.UpdatePosition(pt.x, pt.y - 24,
00348 _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN);
00349
00350 SetWindowDirty(WC_TOWN_VIEW, this->index);
00351 }
00352
00354 void UpdateAllTownVirtCoords()
00355 {
00356 Town *t;
00357
00358 FOR_ALL_TOWNS(t) {
00359 t->UpdateVirtCoord();
00360 }
00361 }
00362
00368 static void ChangePopulation(Town *t, int mod)
00369 {
00370 t->population += mod;
00371 SetWindowDirty(WC_TOWN_VIEW, t->index);
00372 t->UpdateVirtCoord();
00373
00374 InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1);
00375 }
00376
00382 uint32 GetWorldPopulation()
00383 {
00384 uint32 pop = 0;
00385 const Town *t;
00386
00387 FOR_ALL_TOWNS(t) pop += t->population;
00388 return pop;
00389 }
00390
00395 static void MakeSingleHouseBigger(TileIndex tile)
00396 {
00397 assert(IsTileType(tile, MP_HOUSE));
00398
00399
00400 if (LiftHasDestination(tile)) return;
00401
00402
00403 IncHouseConstructionTick(tile);
00404 if (GetHouseConstructionTick(tile) != 0) return;
00405
00406 const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
00407
00408
00409 if (HasBit(hs->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) {
00410 uint16 callback_res = GetHouseCallback(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
00411 if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(hs->grffile, tile, callback_res);
00412 }
00413
00414 if (IsHouseCompleted(tile)) {
00415
00416
00417 ChangePopulation(Town::GetByTile(tile), hs->population);
00418 ResetHouseAge(tile);
00419 }
00420 MarkTileDirtyByTile(tile);
00421 }
00422
00426 static void MakeTownHouseBigger(TileIndex tile)
00427 {
00428 uint flags = HouseSpec::Get(GetHouseType(tile))->building_flags;
00429 if (flags & BUILDING_HAS_1_TILE) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 0));
00430 if (flags & BUILDING_2_TILES_Y) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 1));
00431 if (flags & BUILDING_2_TILES_X) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 0));
00432 if (flags & BUILDING_HAS_4_TILES) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 1));
00433 }
00434
00441 static void TileLoop_Town(TileIndex tile)
00442 {
00443 HouseID house_id = GetHouseType(tile);
00444
00445
00446
00447 if (house_id >= NEW_HOUSE_OFFSET && !NewHouseTileLoop(tile)) return;
00448
00449 if (!IsHouseCompleted(tile)) {
00450
00451 MakeTownHouseBigger(tile);
00452 return;
00453 }
00454
00455 const HouseSpec *hs = HouseSpec::Get(house_id);
00456
00457
00458 if ((hs->building_flags & BUILDING_IS_ANIMATED) &&
00459 house_id < NEW_HOUSE_OFFSET &&
00460 !LiftHasDestination(tile) &&
00461 Chance16(1, 2)) {
00462 AddAnimatedTile(tile);
00463 }
00464
00465 Town *t = Town::GetByTile(tile);
00466 uint32 r = Random();
00467
00468 StationFinder stations(TileArea(tile, 1, 1));
00469
00470 if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
00471 for (uint i = 0; i < 256; i++) {
00472 uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, r, house_id, t, tile);
00473
00474 if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
00475
00476 CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grffile);
00477 if (cargo == CT_INVALID) continue;
00478
00479 uint amt = GB(callback, 0, 8);
00480 if (amt == 0) continue;
00481
00482 uint moved = MoveGoodsToStation(cargo, amt, ST_TOWN, t->index, stations.GetStations());
00483
00484 const CargoSpec *cs = CargoSpec::Get(cargo);
00485 switch (cs->town_effect) {
00486 case TE_PASSENGERS:
00487 t->new_max_pass += amt;
00488 t->new_act_pass += moved;
00489 break;
00490
00491 case TE_MAIL:
00492 t->new_max_mail += amt;
00493 t->new_act_mail += moved;
00494 break;
00495
00496 default:
00497 break;
00498 }
00499 }
00500 } else {
00501 if (GB(r, 0, 8) < hs->population) {
00502 uint amt = GB(r, 0, 8) / 8 + 1;
00503
00504 if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
00505 t->new_max_pass += amt;
00506 t->new_act_pass += MoveGoodsToStation(CT_PASSENGERS, amt, ST_TOWN, t->index, stations.GetStations());
00507 }
00508
00509 if (GB(r, 8, 8) < hs->mail_generation) {
00510 uint amt = GB(r, 8, 8) / 8 + 1;
00511
00512 if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
00513 t->new_max_mail += amt;
00514 t->new_act_mail += MoveGoodsToStation(CT_MAIL, amt, ST_TOWN, t->index, stations.GetStations());
00515 }
00516 }
00517
00518 _current_company = OWNER_TOWN;
00519
00520 if ((hs->building_flags & BUILDING_HAS_1_TILE) &&
00521 HasBit(t->flags, TOWN_IS_FUNDED) &&
00522 CanDeleteHouse(tile) &&
00523 GetHouseAge(tile) >= hs->minimum_life &&
00524 --t->time_until_rebuild == 0) {
00525 t->time_until_rebuild = GB(r, 16, 8) + 192;
00526
00527 ClearTownHouse(t, tile);
00528
00529
00530 if (GB(r, 24, 8) >= 12) BuildTownHouse(t, tile);
00531 }
00532
00533 _current_company = OWNER_NONE;
00534 }
00535
00536 static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags)
00537 {
00538 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
00539 if (!CanDeleteHouse(tile)) return CMD_ERROR;
00540
00541 const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
00542
00543 CommandCost cost(EXPENSES_CONSTRUCTION);
00544 cost.AddCost(hs->GetRemovalCost());
00545
00546 int rating = hs->remove_rating_decrease;
00547 _cleared_town_rating += rating;
00548 Town *t = _cleared_town = Town::GetByTile(tile);
00549
00550 if (Company::IsValidID(_current_company)) {
00551 if (rating > t->ratings[_current_company] && !(flags & DC_NO_TEST_TOWN_RATING) && !_cheats.magic_bulldozer.value) {
00552 SetDParam(0, t->index);
00553 return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
00554 }
00555 }
00556
00557 ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM, flags);
00558 if (flags & DC_EXEC) {
00559 ClearTownHouse(t, tile);
00560 }
00561
00562 return cost;
00563 }
00564
00565 static void AddProducedCargo_Town(TileIndex tile, CargoArray &produced)
00566 {
00567 HouseID house_id = GetHouseType(tile);
00568 const HouseSpec *hs = HouseSpec::Get(house_id);
00569 Town *t = Town::GetByTile(tile);
00570
00571 if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
00572 for (uint i = 0; i < 256; i++) {
00573 uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, house_id, t, tile);
00574
00575 if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
00576
00577 CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grffile);
00578
00579 if (cargo == CT_INVALID) continue;
00580 produced[cargo]++;
00581 }
00582 } else {
00583 if (hs->population > 0) {
00584 produced[CT_PASSENGERS]++;
00585 }
00586 if (hs->mail_generation > 0) {
00587 produced[CT_MAIL]++;
00588 }
00589 }
00590 }
00591
00592 static inline void AddAcceptedCargoSetMask(CargoID cargo, uint amount, CargoArray &acceptance, uint32 *always_accepted)
00593 {
00594 if (cargo == CT_INVALID || amount == 0) return;
00595 acceptance[cargo] += amount;
00596 SetBit(*always_accepted, cargo);
00597 }
00598
00599 static void AddAcceptedCargo_Town(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
00600 {
00601 const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
00602 CargoID accepts[3];
00603
00604
00605 for (uint8 i = 0; i < lengthof(accepts); i++) {
00606 accepts[i] = hs->accepts_cargo[i];
00607 }
00608
00609
00610 if (HasBit(hs->callback_mask, CBM_HOUSE_ACCEPT_CARGO)) {
00611 uint16 callback = GetHouseCallback(CBID_HOUSE_ACCEPT_CARGO, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
00612 if (callback != CALLBACK_FAILED) {
00613
00614 accepts[0] = GetCargoTranslation(GB(callback, 0, 5), hs->grffile);
00615 accepts[1] = GetCargoTranslation(GB(callback, 5, 5), hs->grffile);
00616 accepts[2] = GetCargoTranslation(GB(callback, 10, 5), hs->grffile);
00617 }
00618 }
00619
00620
00621 if (HasBit(hs->callback_mask, CBM_HOUSE_CARGO_ACCEPTANCE)) {
00622 uint16 callback = GetHouseCallback(CBID_HOUSE_CARGO_ACCEPTANCE, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
00623 if (callback != CALLBACK_FAILED) {
00624 AddAcceptedCargoSetMask(accepts[0], GB(callback, 0, 4), acceptance, always_accepted);
00625 AddAcceptedCargoSetMask(accepts[1], GB(callback, 4, 4), acceptance, always_accepted);
00626 if (_settings_game.game_creation.landscape != LT_TEMPERATE && HasBit(callback, 12)) {
00627
00628 AddAcceptedCargoSetMask(CT_FOOD, GB(callback, 8, 4), acceptance, always_accepted);
00629 } else {
00630 AddAcceptedCargoSetMask(accepts[2], GB(callback, 8, 4), acceptance, always_accepted);
00631 }
00632 return;
00633 }
00634 }
00635
00636
00637 for (uint8 i = 0; i < lengthof(accepts); i++) {
00638 AddAcceptedCargoSetMask(accepts[i], hs->cargo_acceptance[i], acceptance, always_accepted);
00639 }
00640 }
00641
00642 static void GetTileDesc_Town(TileIndex tile, TileDesc *td)
00643 {
00644 const HouseID house = GetHouseType(tile);
00645 const HouseSpec *hs = HouseSpec::Get(house);
00646 bool house_completed = IsHouseCompleted(tile);
00647
00648 td->str = hs->building_name;
00649
00650 uint16 callback_res = GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, house_completed ? 1 : 0, 0, house, Town::GetByTile(tile), tile);
00651 if (callback_res != CALLBACK_FAILED) {
00652 StringID new_name = GetGRFStringID(hs->grffile->grfid, 0xD000 + callback_res);
00653 if (new_name != STR_NULL && new_name != STR_UNDEFINED) {
00654 td->str = new_name;
00655 }
00656 }
00657
00658 if (!house_completed) {
00659 SetDParamX(td->dparam, 0, td->str);
00660 td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
00661 }
00662
00663 if (hs->grffile != NULL) {
00664 const GRFConfig *gc = GetGRFConfig(hs->grffile->grfid);
00665 td->grf = gc->name;
00666 }
00667
00668 td->owner[0] = OWNER_TOWN;
00669 }
00670
00671 static TrackStatus GetTileTrackStatus_Town(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
00672 {
00673
00674 return 0;
00675 }
00676
00677 static void ChangeTileOwner_Town(TileIndex tile, Owner old_owner, Owner new_owner)
00678 {
00679
00680 }
00681
00682 static bool GrowTown(Town *t);
00683
00684 static void TownTickHandler(Town *t)
00685 {
00686 if (HasBit(t->flags, TOWN_IS_FUNDED)) {
00687 int i = t->grow_counter - 1;
00688 if (i < 0) {
00689 if (GrowTown(t)) {
00690 i = t->growth_rate;
00691 } else {
00692 i = 0;
00693 }
00694 }
00695 t->grow_counter = i;
00696 }
00697
00698 UpdateTownRadius(t);
00699 }
00700
00701 void OnTick_Town()
00702 {
00703 if (_game_mode == GM_EDITOR) return;
00704
00705 Town *t;
00706 FOR_ALL_TOWNS(t) {
00707
00708 if ((_tick_counter + t->index) % TOWN_GROWTH_FREQUENCY == 0) {
00709 TownTickHandler(t);
00710 }
00711 }
00712 }
00713
00722 static RoadBits GetTownRoadBits(TileIndex tile)
00723 {
00724 if (IsRoadDepotTile(tile) || IsStandardRoadStopTile(tile)) return ROAD_NONE;
00725
00726 return GetAnyRoadBits(tile, ROADTYPE_ROAD, true);
00727 }
00728
00739 static bool IsNeighborRoadTile(TileIndex tile, const DiagDirection dir, uint dist_multi)
00740 {
00741 if (!IsValidTile(tile)) return false;
00742
00743
00744 const TileIndexDiff tid_lt[3] = {
00745 TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT)),
00746 TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT)),
00747 TileOffsByDiagDir(ReverseDiagDir(dir)),
00748 };
00749
00750 dist_multi = (dist_multi + 1) * 4;
00751 for (uint pos = 4; pos < dist_multi; pos++) {
00752
00753 TileIndexDiff cur = tid_lt[(pos & 1) ? 0 : 1] * (pos / 4);
00754
00755
00756 if (pos & 2) cur += tid_lt[2];
00757
00758
00759 if (IsValidTile(tile + cur) &&
00760 GetTownRoadBits(TILE_ADD(tile, cur)) & DiagDirToRoadBits((pos & 2) ? dir : ReverseDiagDir(dir))) return true;
00761 }
00762 return false;
00763 }
00764
00773 static bool IsRoadAllowedHere(Town *t, TileIndex tile, DiagDirection dir)
00774 {
00775 if (DistanceFromEdge(tile) == 0) return false;
00776
00777 Slope cur_slope, desired_slope;
00778
00779 for (;;) {
00780
00781 if (GetTownRoadBits(tile) == ROAD_NONE) {
00782
00783
00784
00785 if (CmdFailed(DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_X : ROAD_Y), 0, DC_AUTO, CMD_BUILD_ROAD)) &&
00786 CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR)))
00787 return false;
00788 }
00789
00790 cur_slope = _settings_game.construction.build_on_slopes ? GetFoundationSlope(tile, NULL) : GetTileSlope(tile, NULL);
00791 bool ret = !IsNeighborRoadTile(tile, dir, t->layout == TL_ORIGINAL ? 1 : 2);
00792 if (cur_slope == SLOPE_FLAT) return ret;
00793
00794
00795
00796 desired_slope = (dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? SLOPE_NW : SLOPE_NE;
00797 if (desired_slope != cur_slope && ComplementSlope(desired_slope) != cur_slope) {
00798 if (Chance16(1, 8)) {
00799 CommandCost res = CMD_ERROR;
00800 if (!_generating_world && Chance16(1, 10)) {
00801
00802 res = DoCommand(tile, Chance16(1, 16) ? cur_slope : cur_slope ^ SLOPE_ELEVATED, 0,
00803 DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
00804 }
00805 if (CmdFailed(res) && Chance16(1, 3)) {
00806
00807 return ret;
00808 }
00809 }
00810 return false;
00811 }
00812 return ret;
00813 }
00814 }
00815
00816 static bool TerraformTownTile(TileIndex tile, int edges, int dir)
00817 {
00818 assert(tile < MapSize());
00819
00820 CommandCost r = DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
00821 if (CmdFailed(r) || r.GetCost() >= (_price[PR_TERRAFORM] + 2) * 8) return false;
00822 DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER | DC_EXEC, CMD_TERRAFORM_LAND);
00823 return true;
00824 }
00825
00826 static void LevelTownLand(TileIndex tile)
00827 {
00828 assert(tile < MapSize());
00829
00830
00831 if (IsTileType(tile, MP_HOUSE)) return;
00832 Slope tileh = GetTileSlope(tile, NULL);
00833 if (tileh == SLOPE_FLAT) return;
00834
00835
00836 if (!TerraformTownTile(tile, ~tileh & SLOPE_ELEVATED, 1)) {
00837 TerraformTownTile(tile, tileh & SLOPE_ELEVATED, 0);
00838 }
00839 }
00840
00850 static RoadBits GetTownRoadGridElement(Town *t, TileIndex tile, DiagDirection dir)
00851 {
00852
00853 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
00854 RoadBits rcmd = ROAD_NONE;
00855
00856 switch (t->layout) {
00857 default: NOT_REACHED();
00858
00859 case TL_2X2_GRID:
00860 if ((grid_pos.x % 3) == 0) rcmd |= ROAD_Y;
00861 if ((grid_pos.y % 3) == 0) rcmd |= ROAD_X;
00862 break;
00863
00864 case TL_3X3_GRID:
00865 if ((grid_pos.x % 4) == 0) rcmd |= ROAD_Y;
00866 if ((grid_pos.y % 4) == 0) rcmd |= ROAD_X;
00867 break;
00868 }
00869
00870
00871 if (rcmd != ROAD_ALL) return rcmd;
00872
00873 RoadBits rb_template;
00874
00875 switch (GetTileSlope(tile, NULL)) {
00876 default: rb_template = ROAD_ALL; break;
00877 case SLOPE_W: rb_template = ROAD_NW | ROAD_SW; break;
00878 case SLOPE_SW: rb_template = ROAD_Y | ROAD_SW; break;
00879 case SLOPE_S: rb_template = ROAD_SW | ROAD_SE; break;
00880 case SLOPE_SE: rb_template = ROAD_X | ROAD_SE; break;
00881 case SLOPE_E: rb_template = ROAD_SE | ROAD_NE; break;
00882 case SLOPE_NE: rb_template = ROAD_Y | ROAD_NE; break;
00883 case SLOPE_N: rb_template = ROAD_NE | ROAD_NW; break;
00884 case SLOPE_NW: rb_template = ROAD_X | ROAD_NW; break;
00885 case SLOPE_STEEP_W:
00886 case SLOPE_STEEP_S:
00887 case SLOPE_STEEP_E:
00888 case SLOPE_STEEP_N:
00889 rb_template = ROAD_NONE;
00890 break;
00891 }
00892
00893
00894 if (DiagDirToRoadBits(ReverseDiagDir(dir)) & rb_template) return rb_template;
00895
00896 return DiagDirToRoadBits(dir) | DiagDirToRoadBits(ReverseDiagDir(dir));
00897 }
00898
00909 static bool GrowTownWithExtraHouse(Town *t, TileIndex tile)
00910 {
00911
00912 if (DistanceFromEdge(tile) == 0) return false;
00913
00914 uint counter = 0;
00915
00916
00917 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
00918
00919
00920
00921 switch (GetTileType(TileAddByDiagDir(tile, dir))) {
00922 case MP_HOUSE:
00923 case MP_VOID:
00924 counter++;
00925 break;
00926
00927 default:
00928 break;
00929 }
00930
00931
00932 if (counter >= 3) {
00933 if (BuildTownHouse(t, tile)) {
00934 _grow_town_result = GROWTH_SUCCEED;
00935 return true;
00936 }
00937 return false;
00938 }
00939 }
00940 return false;
00941 }
00942
00951 static bool GrowTownWithRoad(const Town *t, TileIndex tile, RoadBits rcmd)
00952 {
00953 if (CmdSucceeded(DoCommand(tile, rcmd, t->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD))) {
00954 _grow_town_result = GROWTH_SUCCEED;
00955 return true;
00956 }
00957 return false;
00958 }
00959
00970 static bool GrowTownWithBridge(const Town *t, const TileIndex tile, const DiagDirection bridge_dir)
00971 {
00972 assert(bridge_dir < DIAGDIR_END);
00973
00974 const Slope slope = GetTileSlope(tile, NULL);
00975 if (slope == SLOPE_FLAT) return false;
00976
00977
00978
00979
00980 if (slope & InclinedSlope(bridge_dir)) return false;
00981
00982
00983 if (!(GetTownRoadBits(TileAddByDiagDir(tile, ReverseDiagDir(bridge_dir))) & DiagDirToRoadBits(bridge_dir))) return false;
00984
00985
00986 uint8 bridge_length = 0;
00987 TileIndex bridge_tile = tile;
00988
00989 const int delta = TileOffsByDiagDir(bridge_dir);
00990 do {
00991 if (bridge_length++ >= 11) {
00992
00993 return false;
00994 }
00995 bridge_tile += delta;
00996 } while (TileX(bridge_tile) != 0 && TileY(bridge_tile) != 0 && IsWaterTile(bridge_tile));
00997
00998
00999 if (bridge_length == 1) return false;
01000
01001 for (uint8 times = 0; times <= 22; times++) {
01002 byte bridge_type = RandomRange(MAX_BRIDGES - 1);
01003
01004
01005 if (CmdSucceeded(DoCommand(tile, bridge_tile, bridge_type | ROADTYPES_ROAD << 8 | TRANSPORT_ROAD << 15, DC_AUTO, CMD_BUILD_BRIDGE))) {
01006 DoCommand(tile, bridge_tile, bridge_type | ROADTYPES_ROAD << 8 | TRANSPORT_ROAD << 15, DC_EXEC | DC_AUTO, CMD_BUILD_BRIDGE);
01007 _grow_town_result = GROWTH_SUCCEED;
01008 return true;
01009 }
01010 }
01011
01012 return false;
01013 }
01014
01032 static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection target_dir, Town *t1)
01033 {
01034 RoadBits rcmd = ROAD_NONE;
01035 TileIndex tile = *tile_ptr;
01036
01037 assert(tile < MapSize());
01038
01039 if (cur_rb == ROAD_NONE) {
01040
01041
01042 _grow_town_result = GROWTH_SEARCH_STOPPED;
01043
01044 if (!_settings_game.economy.allow_town_roads && !_generating_world) return;
01045
01046
01047 if (!_settings_game.construction.build_on_slopes || Chance16(1, 6)) LevelTownLand(tile);
01048
01049
01050 switch (t1->layout) {
01051 default: NOT_REACHED();
01052
01053 case TL_3X3_GRID:
01054 case TL_2X2_GRID:
01055 rcmd = GetTownRoadGridElement(t1, tile, target_dir);
01056 if (rcmd == ROAD_NONE) return;
01057 break;
01058
01059 case TL_BETTER_ROADS:
01060 case TL_ORIGINAL:
01061 if (!IsRoadAllowedHere(t1, tile, target_dir)) return;
01062
01063 DiagDirection source_dir = ReverseDiagDir(target_dir);
01064
01065 if (Chance16(1, 4)) {
01066
01067 do target_dir = RandomDiagDir(); while (target_dir == source_dir);
01068 }
01069
01070 if (!IsRoadAllowedHere(t1, TileAddByDiagDir(tile, target_dir), target_dir)) {
01071
01072
01073 if (target_dir != ReverseDiagDir(source_dir)) return;
01074
01075
01076 if (!IsTileType(TileAddByDiagDir(tile, ChangeDiagDir(target_dir, DIAGDIRDIFF_90RIGHT)), MP_HOUSE) &&
01077 !IsTileType(TileAddByDiagDir(tile, ChangeDiagDir(target_dir, DIAGDIRDIFF_90LEFT)), MP_HOUSE)) {
01078 return;
01079 }
01080
01081
01082
01083 }
01084
01085 rcmd = DiagDirToRoadBits(target_dir) | DiagDirToRoadBits(source_dir);
01086 break;
01087 }
01088
01089 } else if (target_dir < DIAGDIR_END && !(cur_rb & DiagDirToRoadBits(ReverseDiagDir(target_dir)))) {
01090
01091
01092
01093 _grow_town_result = GROWTH_SEARCH_STOPPED;
01094
01095 if (!_settings_game.economy.allow_town_roads && !_generating_world) return;
01096
01097 switch (t1->layout) {
01098 default: NOT_REACHED();
01099
01100 case TL_3X3_GRID:
01101 case TL_2X2_GRID:
01102 rcmd = GetTownRoadGridElement(t1, tile, target_dir);
01103 break;
01104
01105 case TL_BETTER_ROADS:
01106 case TL_ORIGINAL:
01107 rcmd = DiagDirToRoadBits(ReverseDiagDir(target_dir));
01108 break;
01109 }
01110 } else {
01111 bool allow_house = true;
01112
01113
01114 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
01115 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
01116 *tile_ptr = GetOtherTunnelBridgeEnd(tile);
01117 }
01118 return;
01119 }
01120
01121
01122
01123 target_dir = RandomDiagDir();
01124 if (cur_rb & DiagDirToRoadBits(target_dir)) return;
01125
01126
01127 TileIndex house_tile = TileAddByDiagDir(tile, target_dir);
01128
01129
01130 if (IsWaterTile(house_tile)) return;
01131
01132 if (!IsValidTile(house_tile)) return;
01133
01134 if (_settings_game.economy.allow_town_roads || _generating_world) {
01135 switch (t1->layout) {
01136 default: NOT_REACHED();
01137
01138 case TL_3X3_GRID:
01139 GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir));
01140
01141
01142 case TL_2X2_GRID:
01143 rcmd = GetTownRoadGridElement(t1, house_tile, target_dir);
01144 allow_house = (rcmd == ROAD_NONE);
01145 break;
01146
01147 case TL_BETTER_ROADS:
01148 GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir));
01149
01150
01151 case TL_ORIGINAL:
01152
01153
01154 rcmd = DiagDirToRoadBits(target_dir);
01155 allow_house = (!IsRoadAllowedHere(t1, house_tile, target_dir) || Chance16(6, 10));
01156 break;
01157 }
01158 }
01159
01160 if (allow_house) {
01161
01162 if (!IsTileType(house_tile, MP_HOUSE)) {
01163
01164 if (Chance16(1, 6)) LevelTownLand(house_tile);
01165
01166
01167
01168 if (BuildTownHouse(t1, house_tile)) {
01169 _grow_town_result = GROWTH_SUCCEED;
01170 }
01171 }
01172 return;
01173 }
01174
01175 _grow_town_result = GROWTH_SEARCH_STOPPED;
01176 }
01177
01178
01179 if (IsWaterTile(tile)) return;
01180
01181
01182 rcmd = CleanUpRoadBits(tile, rcmd);
01183 if (rcmd == ROAD_NONE) return;
01184
01185
01186
01187
01188 if (GrowTownWithBridge(t1, tile, target_dir)) return;
01189
01190 GrowTownWithRoad(t1, tile, rcmd);
01191 }
01192
01198 static int GrowTownAtRoad(Town *t, TileIndex tile)
01199 {
01200
01201
01202
01203 DiagDirection target_dir = DIAGDIR_END;
01204
01205 assert(tile < MapSize());
01206
01207
01208
01209
01210 switch (t->layout) {
01211 case TL_BETTER_ROADS:
01212 _grow_town_result = 10 + t->num_houses * 2 / 9;
01213 break;
01214
01215 case TL_3X3_GRID:
01216 case TL_2X2_GRID:
01217 _grow_town_result = 10 + t->num_houses * 1 / 9;
01218 break;
01219
01220 default:
01221 _grow_town_result = 10 + t->num_houses * 4 / 9;
01222 break;
01223 }
01224
01225 do {
01226 RoadBits cur_rb = GetTownRoadBits(tile);
01227
01228
01229 GrowTownInTile(&tile, cur_rb, target_dir, t);
01230
01231
01232
01233 cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir));
01234 if (cur_rb == ROAD_NONE)
01235 return _grow_town_result;
01236
01237
01238
01239 do target_dir = RandomDiagDir(); while (!(cur_rb & DiagDirToRoadBits(target_dir)));
01240 tile = TileAddByDiagDir(tile, target_dir);
01241
01242 if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, ROADTYPE_ROAD)) {
01243
01244 if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN) && Town::GetByTile(tile) != t) {
01245 _grow_town_result = GROWTH_SUCCEED;
01246 } else if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) {
01247
01248
01249 SetRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN);
01250 SetTownIndex(tile, t->index);
01251 }
01252 }
01253
01254
01255 } while (--_grow_town_result >= 0);
01256
01257 return (_grow_town_result == -2);
01258 }
01259
01267 static RoadBits GenRandomRoadBits()
01268 {
01269 uint32 r = Random();
01270 uint a = GB(r, 0, 2);
01271 uint b = GB(r, 8, 2);
01272 if (a == b) b ^= 2;
01273 return (RoadBits)((ROAD_NW << a) + (ROAD_NW << b));
01274 }
01275
01280 static bool GrowTown(Town *t)
01281 {
01282 static const TileIndexDiffC _town_coord_mod[] = {
01283 {-1, 0},
01284 { 1, 1},
01285 { 1, -1},
01286 {-1, -1},
01287 {-1, 0},
01288 { 0, 2},
01289 { 2, 0},
01290 { 0, -2},
01291 {-1, -1},
01292 {-2, 2},
01293 { 2, 2},
01294 { 2, -2},
01295 { 0, 0}
01296 };
01297
01298
01299 CompanyID old_company = _current_company;
01300 _current_company = OWNER_TOWN;
01301
01302 TileIndex tile = t->xy;
01303
01304
01305 const TileIndexDiffC *ptr;
01306 for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
01307 if (GetTownRoadBits(tile) != ROAD_NONE) {
01308 int r = GrowTownAtRoad(t, tile);
01309 _current_company = old_company;
01310 return r != 0;
01311 }
01312 tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
01313 }
01314
01315
01316
01317 if (_settings_game.economy.allow_town_roads || _generating_world) {
01318 tile = t->xy;
01319 for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
01320
01321 if (!IsTileType(tile, MP_HOUSE) && GetTileSlope(tile, NULL) == SLOPE_FLAT) {
01322 if (CmdSucceeded(DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR))) {
01323 DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD);
01324 _current_company = old_company;
01325 return true;
01326 }
01327 }
01328 tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
01329 }
01330 }
01331
01332 _current_company = old_company;
01333 return false;
01334 }
01335
01336 void UpdateTownRadius(Town *t)
01337 {
01338 static const uint32 _town_squared_town_zone_radius_data[23][5] = {
01339 { 4, 0, 0, 0, 0},
01340 { 16, 0, 0, 0, 0},
01341 { 25, 0, 0, 0, 0},
01342 { 36, 0, 0, 0, 0},
01343 { 49, 0, 4, 0, 0},
01344 { 64, 0, 4, 0, 0},
01345 { 64, 0, 9, 0, 1},
01346 { 64, 0, 9, 0, 4},
01347 { 64, 0, 16, 0, 4},
01348 { 81, 0, 16, 0, 4},
01349 { 81, 0, 16, 0, 4},
01350 { 81, 0, 25, 0, 9},
01351 { 81, 36, 25, 0, 9},
01352 { 81, 36, 25, 16, 9},
01353 { 81, 49, 0, 25, 9},
01354 { 81, 64, 0, 25, 9},
01355 { 81, 64, 0, 36, 9},
01356 { 81, 64, 0, 36, 16},
01357 {100, 81, 0, 49, 16},
01358 {100, 81, 0, 49, 25},
01359 {121, 81, 0, 49, 25},
01360 {121, 81, 0, 49, 25},
01361 {121, 81, 0, 49, 36},
01362 };
01363
01364 if (t->num_houses < 92) {
01365 memcpy(t->squared_town_zone_radius, _town_squared_town_zone_radius_data[t->num_houses / 4], sizeof(t->squared_town_zone_radius));
01366 } else {
01367 int mass = t->num_houses / 8;
01368
01369
01370
01371 t->squared_town_zone_radius[0] = mass * 15 - 40;
01372 t->squared_town_zone_radius[1] = mass * 9 - 15;
01373 t->squared_town_zone_radius[2] = 0;
01374 t->squared_town_zone_radius[3] = mass * 5 - 5;
01375 t->squared_town_zone_radius[4] = mass * 3 + 5;
01376 }
01377 }
01378
01379 void UpdateTownMaxPass(Town *t)
01380 {
01381 t->max_pass = t->population >> 3;
01382 t->max_mail = t->population >> 4;
01383 }
01384
01396 static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSize size, bool city, TownLayout layout, bool manual)
01397 {
01398 t->xy = tile;
01399 t->num_houses = 0;
01400 t->time_until_rebuild = 10;
01401 UpdateTownRadius(t);
01402 t->flags = 0;
01403 t->population = 0;
01404 t->grow_counter = 0;
01405 t->growth_rate = 250;
01406 t->new_max_pass = 0;
01407 t->new_max_mail = 0;
01408 t->new_act_pass = 0;
01409 t->new_act_mail = 0;
01410 t->max_pass = 0;
01411 t->max_mail = 0;
01412 t->act_pass = 0;
01413 t->act_mail = 0;
01414
01415 t->pct_pass_transported = 0;
01416 t->pct_mail_transported = 0;
01417 t->fund_buildings_months = 0;
01418 t->new_act_food = 0;
01419 t->new_act_water = 0;
01420 t->act_food = 0;
01421 t->act_water = 0;
01422
01423 for (uint i = 0; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL;
01424
01425 t->have_ratings = 0;
01426 t->exclusivity = INVALID_COMPANY;
01427 t->exclusive_counter = 0;
01428 t->statues = 0;
01429
01430 extern int _nb_orig_names;
01431 if (_settings_game.game_creation.town_name < _nb_orig_names) {
01432
01433 t->townnamegrfid = 0;
01434 t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name;
01435 } else {
01436
01437 t->townnamegrfid = GetGRFTownNameId(_settings_game.game_creation.town_name - _nb_orig_names);
01438 t->townnametype = GetGRFTownNameType(_settings_game.game_creation.town_name - _nb_orig_names);
01439 }
01440 t->townnameparts = townnameparts;
01441
01442 t->UpdateVirtCoord();
01443 InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0);
01444
01445 t->InitializeLayout(layout);
01446
01447 t->larger_town = city;
01448
01449 int x = (int)size * 16 + 3;
01450 if (size == TS_RANDOM) x = (Random() & 0xF) + 8;
01451
01452 if (city && (!manual || _game_mode == GM_EDITOR)) x *= _settings_game.economy.initial_city_size;
01453
01454 t->num_houses += x;
01455 UpdateTownRadius(t);
01456
01457 int i = x * 4;
01458 do {
01459 GrowTown(t);
01460 } while (--i);
01461
01462 t->num_houses -= x;
01463 UpdateTownRadius(t);
01464 UpdateTownMaxPass(t);
01465 UpdateAirportsNoise();
01466 }
01467
01473 static CommandCost TownCanBePlacedHere(TileIndex tile)
01474 {
01475
01476 if (DistanceFromEdge(tile) < 12) {
01477 return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB);
01478 }
01479
01480
01481 if (IsCloseToTown(tile, 20)) {
01482 return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN);
01483 }
01484
01485
01486 if ((!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) || GetTileSlope(tile, NULL) != SLOPE_FLAT) {
01487 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01488 }
01489
01490 return CommandCost(EXPENSES_OTHER);
01491 }
01492
01498 static bool IsUniqueTownName(const char *name)
01499 {
01500 const Town *t;
01501
01502 FOR_ALL_TOWNS(t) {
01503 if (t->name != NULL && strcmp(t->name, name) == 0) return false;
01504 }
01505
01506 return true;
01507 }
01508
01521 CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01522 {
01523 TownSize size = (TownSize)GB(p1, 0, 2);
01524 bool city = HasBit(p1, 2);
01525 TownLayout layout = (TownLayout)GB(p1, 3, 3);
01526 TownNameParams par(_settings_game.game_creation.town_name);
01527 bool random = HasBit(p1, 6);
01528 uint32 townnameparts = p2;
01529
01530 if (size > TS_RANDOM) return CMD_ERROR;
01531 if (layout > TL_RANDOM) return CMD_ERROR;
01532
01533
01534 if (_game_mode != GM_EDITOR) {
01535 if (_settings_game.economy.found_town == TF_FORBIDDEN) return CMD_ERROR;
01536 if (size == TS_LARGE) return CMD_ERROR;
01537 if (random) return CMD_ERROR;
01538 if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT && layout != _settings_game.economy.town_layout) {
01539 return CMD_ERROR;
01540 }
01541 }
01542
01543 if (StrEmpty(text)) {
01544
01545 if (!VerifyTownName(townnameparts, &par)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
01546 } else {
01547
01548 if (strlen(text) >= MAX_LENGTH_TOWN_NAME_BYTES) return CMD_ERROR;
01549 if (!IsUniqueTownName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
01550 }
01551
01552
01553 if (!Town::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_TOWNS);
01554
01555 if (!random) {
01556 CommandCost ret = TownCanBePlacedHere(tile);
01557 if (CmdFailed(ret)) return ret;
01558 }
01559
01560 static const byte price_mult[][TS_RANDOM + 1] = {{ 15, 25, 40, 25 }, { 20, 35, 55, 35 }};
01561
01562 assert_compile(lengthof(price_mult[0]) == 4);
01563
01564 CommandCost cost(EXPENSES_OTHER, _price[PR_BUILD_TOWN]);
01565 byte mult = price_mult[city][size];
01566
01567 cost.MultiplyCost(mult);
01568
01569
01570 if (flags & DC_EXEC) {
01571 if (cost.GetCost() > GetAvailableMoneyForCommand()) {
01572 _additional_cash_required = cost.GetCost();
01573 return CommandCost(EXPENSES_OTHER);
01574 }
01575
01576 _generating_world = true;
01577 UpdateNearestTownForRoadTiles(true);
01578 Town *t;
01579 if (random) {
01580 t = CreateRandomTown(20, townnameparts, size, city, layout);
01581 if (t == NULL) {
01582 cost = CommandCost(STR_ERROR_NO_SPACE_FOR_TOWN);
01583 } else {
01584 _new_town_id = t->index;
01585 }
01586 } else {
01587 t = new Town(tile);
01588 DoCreateTown(t, tile, townnameparts, size, city, layout, true);
01589 }
01590 UpdateNearestTownForRoadTiles(false);
01591 _generating_world = false;
01592
01593 if (t != NULL && !StrEmpty(text)) {
01594 t->name = strdup(text);
01595 t->UpdateVirtCoord();
01596 }
01597
01598 if (_game_mode != GM_EDITOR) {
01599
01600 assert(!random);
01601 char company_name[MAX_LENGTH_COMPANY_NAME_BYTES];
01602 SetDParam(0, _current_company);
01603 GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
01604
01605 char *cn = strdup(company_name);
01606 SetDParamStr(0, cn);
01607 SetDParam(1, t->index);
01608
01609 AddNewsItem(STR_NEWS_NEW_TOWN, NS_INDUSTRY_OPEN, NR_TILE, tile, NR_NONE, UINT32_MAX, cn);
01610 }
01611 }
01612 return cost;
01613 }
01614
01624 static TileIndex AlignTileToGrid(TileIndex tile, TownLayout layout)
01625 {
01626 switch (layout) {
01627 case TL_2X2_GRID: return TileXY(TileX(tile) - TileX(tile) % 3, TileY(tile) - TileY(tile) % 3);
01628 case TL_3X3_GRID: return TileXY(TileX(tile) & ~3, TileY(tile) & ~3);
01629 default: return tile;
01630 }
01631 }
01632
01642 static bool IsTileAlignedToGrid(TileIndex tile, TownLayout layout)
01643 {
01644 switch (layout) {
01645 case TL_2X2_GRID: return TileX(tile) % 3 == 0 && TileY(tile) % 3 == 0;
01646 case TL_3X3_GRID: return TileX(tile) % 4 == 0 && TileY(tile) % 4 == 0;
01647 default: return true;
01648 }
01649 }
01650
01654 struct SpotData {
01655 TileIndex tile;
01656 uint max_dist;
01657 TownLayout layout;
01658 };
01659
01676 static bool FindFurthestFromWater(TileIndex tile, void *user_data)
01677 {
01678 SpotData *sp = (SpotData*)user_data;
01679 uint dist = GetClosestWaterDistance(tile, true);
01680
01681 if (IsTileType(tile, MP_CLEAR) &&
01682 GetTileSlope(tile, NULL) == SLOPE_FLAT &&
01683 IsTileAlignedToGrid(tile, sp->layout) &&
01684 dist > sp->max_dist) {
01685 sp->tile = tile;
01686 sp->max_dist = dist;
01687 }
01688
01689 return false;
01690 }
01691
01698 static bool FindNearestEmptyLand(TileIndex tile, void *user_data)
01699 {
01700 return IsTileType(tile, MP_CLEAR);
01701 }
01702
01715 static TileIndex FindNearestGoodCoastalTownSpot(TileIndex tile, TownLayout layout)
01716 {
01717 SpotData sp = { INVALID_TILE, 0, layout };
01718
01719 TileIndex coast = tile;
01720 if (CircularTileSearch(&coast, 40, FindNearestEmptyLand, NULL)) {
01721 CircularTileSearch(&coast, 10, FindFurthestFromWater, &sp);
01722 return sp.tile;
01723 }
01724
01725
01726 return INVALID_TILE;
01727 }
01728
01729 static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size, bool city, TownLayout layout)
01730 {
01731 if (!Town::CanAllocateItem()) return NULL;
01732
01733 do {
01734
01735 TileIndex tile = AlignTileToGrid(RandomTile(), layout);
01736
01737
01738
01739 if (IsTileType(tile, MP_WATER)) {
01740 tile = FindNearestGoodCoastalTownSpot(tile, layout);
01741 if (tile == INVALID_TILE) continue;
01742 }
01743
01744
01745 if (CmdFailed(TownCanBePlacedHere(tile))) continue;
01746
01747
01748 Town *t = new Town(tile);
01749
01750 DoCreateTown(t, tile, townnameparts, size, city, layout, false);
01751
01752
01753
01754 if (t->population > 0) return t;
01755 delete t;
01756 } while (--attempts != 0);
01757
01758 return NULL;
01759 }
01760
01761 static const byte _num_initial_towns[4] = {5, 11, 23, 46};
01762
01769 bool GenerateTowns(TownLayout layout)
01770 {
01771 uint num = 0;
01772 uint difficulty = _settings_game.difficulty.number_towns;
01773 uint n = (difficulty == (uint)CUSTOM_TOWN_NUMBER_DIFFICULTY) ? _settings_game.game_creation.custom_town_number : ScaleByMapSize(_num_initial_towns[difficulty] + (Random() & 7));
01774 uint32 townnameparts;
01775
01776 SetGeneratingWorldProgress(GWP_TOWN, n);
01777
01778
01779
01780
01781 do {
01782 bool city = (_settings_game.economy.larger_towns != 0 && Chance16(1, _settings_game.economy.larger_towns));
01783 IncreaseGeneratingWorldProgress(GWP_TOWN);
01784
01785 if (!GenerateTownName(&townnameparts)) continue;
01786
01787 if (CreateRandomTown(20, townnameparts, TS_RANDOM, city, layout) != NULL) num++;
01788 } while (--n);
01789
01790 if (num != 0) return true;
01791
01792
01793
01794 if (GenerateTownName(&townnameparts) &&
01795 CreateRandomTown(10000, townnameparts, TS_RANDOM, _settings_game.economy.larger_towns != 0, layout) != NULL) {
01796 return true;
01797 }
01798
01799
01800 if (Town::GetNumItems() == 0 && _game_mode != GM_EDITOR) {
01801 extern StringID _switch_mode_errorstr;
01802 _switch_mode_errorstr = STR_ERROR_COULD_NOT_CREATE_TOWN;
01803 }
01804
01805 return false;
01806 }
01807
01808
01814 HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile)
01815 {
01816 uint dist = DistanceSquare(tile, t->xy);
01817
01818 if (t->fund_buildings_months && dist <= 25) return HZB_TOWN_CENTRE;
01819
01820 HouseZonesBits smallest = HZB_TOWN_EDGE;
01821 for (HouseZonesBits i = HZB_BEGIN; i < HZB_END; i++) {
01822 if (dist < t->squared_town_zone_radius[i]) smallest = i;
01823 }
01824
01825 return smallest;
01826 }
01827
01838 static inline void ClearMakeHouseTile(TileIndex tile, Town *t, byte counter, byte stage, HouseID type, byte random_bits)
01839 {
01840 CommandCost cc = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
01841
01842 assert(CmdSucceeded(cc));
01843
01844 IncreaseBuildingCount(t, type);
01845 MakeHouseTile(tile, t->index, counter, stage, type, random_bits);
01846 if (HouseSpec::Get(type)->building_flags & BUILDING_IS_ANIMATED) AddAnimatedTile(tile);
01847
01848 MarkTileDirtyByTile(tile);
01849 }
01850
01851
01862 static void MakeTownHouse(TileIndex t, Town *town, byte counter, byte stage, HouseID type, byte random_bits)
01863 {
01864 BuildingFlags size = HouseSpec::Get(type)->building_flags;
01865
01866 ClearMakeHouseTile(t, town, counter, stage, type, random_bits);
01867 if (size & BUILDING_2_TILES_Y) ClearMakeHouseTile(t + TileDiffXY(0, 1), town, counter, stage, ++type, random_bits);
01868 if (size & BUILDING_2_TILES_X) ClearMakeHouseTile(t + TileDiffXY(1, 0), town, counter, stage, ++type, random_bits);
01869 if (size & BUILDING_HAS_4_TILES) ClearMakeHouseTile(t + TileDiffXY(1, 1), town, counter, stage, ++type, random_bits);
01870 }
01871
01872
01881 static inline bool CanBuildHouseHere(TileIndex tile, TownID town, bool noslope)
01882 {
01883
01884 Slope slope = GetTileSlope(tile, NULL);
01885 if ((noslope && slope != SLOPE_FLAT) || IsSteepSlope(slope)) return false;
01886
01887
01888 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
01889
01890
01891 if (IsTileType(tile, MP_HOUSE) && GetTownIndex(tile) != town) return false;
01892
01893
01894 return CmdSucceeded(DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR));
01895 }
01896
01897
01907 static inline bool CheckBuildHouseSameZ(TileIndex tile, TownID town, uint z, bool noslope)
01908 {
01909 if (!CanBuildHouseHere(tile, town, noslope)) return false;
01910
01911
01912 if (GetTileMaxZ(tile) != z) return false;
01913
01914 return true;
01915 }
01916
01917
01927 static bool CheckFree2x2Area(TileIndex tile, TownID town, uint z, bool noslope)
01928 {
01929
01930 if (!CheckBuildHouseSameZ(tile, town, z, noslope)) return false;
01931
01932 for (DiagDirection d = DIAGDIR_SE; d < DIAGDIR_END; d++) {
01933 tile += TileOffsByDiagDir(d);
01934 if (!CheckBuildHouseSameZ(tile, town, z, noslope)) return false;
01935 }
01936
01937 return true;
01938 }
01939
01940
01948 static inline bool TownLayoutAllowsHouseHere(Town *t, TileIndex tile)
01949 {
01950
01951 if (!_settings_game.economy.allow_town_roads && !_generating_world) return true;
01952
01953 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
01954
01955 switch (t->layout) {
01956 case TL_2X2_GRID:
01957 if ((grid_pos.x % 3) == 0 || (grid_pos.y % 3) == 0) return false;
01958 break;
01959
01960 case TL_3X3_GRID:
01961 if ((grid_pos.x % 4) == 0 || (grid_pos.y % 4) == 0) return false;
01962 break;
01963
01964 default:
01965 break;
01966 }
01967
01968 return true;
01969 }
01970
01971
01979 static inline bool TownLayoutAllows2x2HouseHere(Town *t, TileIndex tile)
01980 {
01981
01982 if (!_settings_game.economy.allow_town_roads && !_generating_world) return true;
01983
01984
01985
01986 uint dx = MapSize() + TileX(t->xy) - TileX(tile);
01987 uint dy = MapSize() + TileY(t->xy) - TileY(tile);
01988
01989 switch (t->layout) {
01990 case TL_2X2_GRID:
01991 if ((dx % 3) != 0 || (dy % 3) != 0) return false;
01992 break;
01993
01994 case TL_3X3_GRID:
01995 if ((dx % 4) < 2 || (dy % 4) < 2) return false;
01996 break;
01997
01998 default:
01999 break;
02000 }
02001
02002 return true;
02003 }
02004
02005
02015 static bool CheckTownBuild2House(TileIndex *tile, Town *t, uint maxz, bool noslope, DiagDirection second)
02016 {
02017
02018
02019 TileIndex tile2 = *tile + TileOffsByDiagDir(second);
02020 if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope)) return true;
02021
02022 tile2 = *tile + TileOffsByDiagDir(ReverseDiagDir(second));
02023 if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope)) {
02024 *tile = tile2;
02025 return true;
02026 }
02027
02028 return false;
02029 }
02030
02031
02040 static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, uint maxz, bool noslope)
02041 {
02042 TileIndex tile2 = *tile;
02043
02044 for (DiagDirection d = DIAGDIR_SE;;d++) {
02045 if (TownLayoutAllows2x2HouseHere(t, tile2) && CheckFree2x2Area(tile2, t->index, maxz, noslope)) {
02046 *tile = tile2;
02047 return true;
02048 }
02049 if (d == DIAGDIR_END) break;
02050 tile2 += TileOffsByDiagDir(ReverseDiagDir(d));
02051 }
02052
02053 return false;
02054 }
02055
02056
02063 static bool BuildTownHouse(Town *t, TileIndex tile)
02064 {
02065
02066 if (!TownLayoutAllowsHouseHere(t, tile)) return false;
02067
02068
02069 if (!CanBuildHouseHere(tile, t->index, false)) return false;
02070
02071 uint z;
02072 Slope slope = GetTileSlope(tile, &z);
02073
02074
02075
02076 HouseZonesBits rad = GetTownRadiusGroup(t, tile);
02077
02078
02079 int land = _settings_game.game_creation.landscape;
02080 if (land == LT_ARCTIC && z >= _settings_game.game_creation.snow_line) land = -1;
02081
02082 uint bitmask = (1 << rad) + (1 << (land + 12));
02083
02084
02085
02086
02087 HouseID houses[HOUSE_MAX];
02088 uint num = 0;
02089 uint probs[HOUSE_MAX];
02090 uint probability_max = 0;
02091
02092
02093 for (uint i = 0; i < HOUSE_MAX; i++) {
02094 const HouseSpec *hs = HouseSpec::Get(i);
02095
02096
02097 if ((~hs->building_availability & bitmask) != 0 || !hs->enabled || hs->override != INVALID_HOUSE_ID) continue;
02098
02099
02100 if (hs->class_id != HOUSE_NO_CLASS) {
02101
02102 if (t->building_counts.class_count[hs->class_id] == UINT16_MAX) continue;
02103 } else {
02104
02105 if (t->building_counts.id_count[i] == UINT16_MAX) continue;
02106 }
02107
02108
02109 uint cur_prob = (_loaded_newgrf_features.has_newhouses ? hs->probability : 1);
02110 probability_max += cur_prob;
02111 probs[num] = cur_prob;
02112 houses[num++] = (HouseID)i;
02113 }
02114
02115 uint maxz = GetTileMaxZ(tile);
02116
02117 while (probability_max > 0) {
02118 uint r = RandomRange(probability_max);
02119 uint i;
02120 for (i = 0; i < num; i++) {
02121 if (probs[i] > r) break;
02122 r -= probs[i];
02123 }
02124
02125 HouseID house = houses[i];
02126 probability_max -= probs[i];
02127
02128
02129 num--;
02130 houses[i] = houses[num];
02131 probs[i] = probs[num];
02132
02133 const HouseSpec *hs = HouseSpec::Get(house);
02134
02135 if (_loaded_newgrf_features.has_newhouses && !_generating_world &&
02136 _game_mode != GM_EDITOR && (hs->extra_flags & BUILDING_IS_HISTORICAL) != 0) {
02137 continue;
02138 }
02139
02140 if (_cur_year < hs->min_year || _cur_year > hs->max_year) continue;
02141
02142
02143 uint oneof = 0;
02144
02145 if (hs->building_flags & BUILDING_IS_CHURCH) {
02146 SetBit(oneof, TOWN_HAS_CHURCH);
02147 } else if (hs->building_flags & BUILDING_IS_STADIUM) {
02148 SetBit(oneof, TOWN_HAS_STADIUM);
02149 }
02150
02151 if (t->flags & oneof) continue;
02152
02153
02154 bool noslope = (hs->building_flags & TILE_NOT_SLOPED) != 0;
02155 if (noslope && slope != SLOPE_FLAT) continue;
02156
02157 if (hs->building_flags & TILE_SIZE_2x2) {
02158 if (!CheckTownBuild2x2House(&tile, t, maxz, noslope)) continue;
02159 } else if (hs->building_flags & TILE_SIZE_2x1) {
02160 if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SW)) continue;
02161 } else if (hs->building_flags & TILE_SIZE_1x2) {
02162 if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SE)) continue;
02163 } else {
02164
02165 }
02166
02167 if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
02168 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile);
02169 if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) == 0) continue;
02170 }
02171
02172
02173 t->num_houses++;
02174
02175
02176 t->flags |= oneof;
02177
02178 byte construction_counter = 0;
02179 byte construction_stage = 0;
02180
02181 if (_generating_world || _game_mode == GM_EDITOR) {
02182 uint32 r = Random();
02183
02184 construction_stage = TOWN_HOUSE_COMPLETED;
02185 if (Chance16(1, 7)) construction_stage = GB(r, 0, 2);
02186
02187 if (construction_stage == TOWN_HOUSE_COMPLETED) {
02188 ChangePopulation(t, hs->population);
02189 } else {
02190 construction_counter = GB(r, 2, 2);
02191 }
02192 }
02193
02194 MakeTownHouse(tile, t, construction_counter, construction_stage, house, Random());
02195
02196 return true;
02197 }
02198
02199 return false;
02200 }
02201
02208 static void DoClearTownHouseHelper(TileIndex tile, Town *t, HouseID house)
02209 {
02210 assert(IsTileType(tile, MP_HOUSE));
02211 DecreaseBuildingCount(t, house);
02212 DoClearSquare(tile);
02213 DeleteAnimatedTile(tile);
02214 }
02215
02223 TileIndexDiff GetHouseNorthPart(HouseID &house)
02224 {
02225 if (house >= 3) {
02226 if (HouseSpec::Get(house - 1)->building_flags & TILE_SIZE_2x1) {
02227 house--;
02228 return TileDiffXY(-1, 0);
02229 } else if (HouseSpec::Get(house - 1)->building_flags & BUILDING_2_TILES_Y) {
02230 house--;
02231 return TileDiffXY(0, -1);
02232 } else if (HouseSpec::Get(house - 2)->building_flags & BUILDING_HAS_4_TILES) {
02233 house -= 2;
02234 return TileDiffXY(-1, 0);
02235 } else if (HouseSpec::Get(house - 3)->building_flags & BUILDING_HAS_4_TILES) {
02236 house -= 3;
02237 return TileDiffXY(-1, -1);
02238 }
02239 }
02240 return 0;
02241 }
02242
02243 void ClearTownHouse(Town *t, TileIndex tile)
02244 {
02245 assert(IsTileType(tile, MP_HOUSE));
02246
02247 HouseID house = GetHouseType(tile);
02248
02249
02250 tile += GetHouseNorthPart(house);
02251
02252 const HouseSpec *hs = HouseSpec::Get(house);
02253
02254
02255 if (IsHouseCompleted(tile)) {
02256 ChangePopulation(t, -hs->population);
02257 }
02258
02259 t->num_houses--;
02260
02261
02262 if (hs->building_flags & BUILDING_IS_CHURCH) {
02263 ClrBit(t->flags, TOWN_HAS_CHURCH);
02264 } else if (hs->building_flags & BUILDING_IS_STADIUM) {
02265 ClrBit(t->flags, TOWN_HAS_STADIUM);
02266 }
02267
02268
02269 uint eflags = hs->building_flags;
02270 DoClearTownHouseHelper(tile, t, house);
02271 if (eflags & BUILDING_2_TILES_Y) DoClearTownHouseHelper(tile + TileDiffXY(0, 1), t, ++house);
02272 if (eflags & BUILDING_2_TILES_X) DoClearTownHouseHelper(tile + TileDiffXY(1, 0), t, ++house);
02273 if (eflags & BUILDING_HAS_4_TILES) DoClearTownHouseHelper(tile + TileDiffXY(1, 1), t, ++house);
02274 }
02275
02284 CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
02285 {
02286 Town *t = Town::GetIfValid(p1);
02287 if (t == NULL) return CMD_ERROR;
02288
02289 bool reset = StrEmpty(text);
02290
02291 if (!reset) {
02292 if (strlen(text) >= MAX_LENGTH_TOWN_NAME_BYTES) return CMD_ERROR;
02293 if (!IsUniqueTownName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
02294 }
02295
02296 if (flags & DC_EXEC) {
02297 free(t->name);
02298 t->name = reset ? NULL : strdup(text);
02299
02300 t->UpdateVirtCoord();
02301 InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1);
02302 UpdateAllStationVirtCoords();
02303 }
02304 return CommandCost();
02305 }
02306
02308 void ExpandTown(Town *t)
02309 {
02310
02311
02312 static bool warned_no_roads = false;
02313 if (!_settings_game.economy.allow_town_roads && !warned_no_roads) {
02314 ShowErrorMessage(STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS, INVALID_STRING_ID, 0, 0);
02315 warned_no_roads = true;
02316 }
02317
02318
02319 uint amount = RandomRange(ClampToU16(t->num_houses / 10)) + 3;
02320 t->num_houses += amount;
02321 UpdateTownRadius(t);
02322
02323 uint n = amount * 10;
02324 do GrowTown(t); while (--n);
02325
02326 t->num_houses -= amount;
02327 UpdateTownRadius(t);
02328
02329 UpdateTownMaxPass(t);
02330 }
02331
02335 const byte _town_action_costs[TACT_COUNT] = {
02336 2, 4, 9, 35, 48, 53, 117, 175
02337 };
02338
02339 static void TownActionAdvertiseSmall(Town *t)
02340 {
02341 ModifyStationRatingAround(t->xy, _current_company, 0x40, 10);
02342 }
02343
02344 static void TownActionAdvertiseMedium(Town *t)
02345 {
02346 ModifyStationRatingAround(t->xy, _current_company, 0x70, 15);
02347 }
02348
02349 static void TownActionAdvertiseLarge(Town *t)
02350 {
02351 ModifyStationRatingAround(t->xy, _current_company, 0xA0, 20);
02352 }
02353
02354 static void TownActionRoadRebuild(Town *t)
02355 {
02356 t->road_build_months = 6;
02357
02358 char company_name[MAX_LENGTH_COMPANY_NAME_BYTES];
02359 SetDParam(0, _current_company);
02360 GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
02361
02362 char *cn = strdup(company_name);
02363 SetDParam(0, t->index);
02364 SetDParamStr(1, cn);
02365
02366 AddNewsItem(STR_NEWS_ROAD_REBUILDING, NS_GENERAL, NR_TOWN, t->index, NR_NONE, UINT32_MAX, cn);
02367 }
02368
02369 static bool DoBuildStatueOfCompany(TileIndex tile, TownID town_id)
02370 {
02371
02372 if (IsSteepSlope(GetTileSlope(tile, NULL))) return false;
02373
02374 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
02375
02376 if (!IsTileType(tile, MP_HOUSE) &&
02377 !IsTileType(tile, MP_CLEAR) &&
02378 !IsTileType(tile, MP_TREES)) {
02379 return false;
02380 }
02381
02382 CompanyID old = _current_company;
02383 _current_company = OWNER_NONE;
02384 CommandCost r = DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
02385 _current_company = old;
02386
02387 if (CmdFailed(r)) return false;
02388
02389 MakeStatue(tile, _current_company, town_id);
02390 MarkTileDirtyByTile(tile);
02391
02392 return true;
02393 }
02394
02401 static bool SearchTileForStatue(TileIndex tile, void *user_data)
02402 {
02403 TownID *town_id = (TownID *)user_data;
02404 return DoBuildStatueOfCompany(tile, *town_id);
02405 }
02406
02412 static void TownActionBuildStatue(Town *t)
02413 {
02414 TileIndex tile = t->xy;
02415
02416 if (CircularTileSearch(&tile, 9, SearchTileForStatue, &t->index)) {
02417 SetBit(t->statues, _current_company);
02418 }
02419 }
02420
02421 static void TownActionFundBuildings(Town *t)
02422 {
02423
02424 t->grow_counter = 1;
02425
02426 SetBit(t->flags, TOWN_IS_FUNDED);
02427
02428 t->fund_buildings_months = 3;
02429 }
02430
02431 static void TownActionBuyRights(Town *t)
02432 {
02433
02434 if (!_settings_game.economy.exclusive_rights) return;
02435
02436 t->exclusive_counter = 12;
02437 t->exclusivity = _current_company;
02438
02439 ModifyStationRatingAround(t->xy, _current_company, 130, 17);
02440 }
02441
02442 static void TownActionBribe(Town *t)
02443 {
02444 if (Chance16(1, 14)) {
02445
02446 t->unwanted[_current_company] = 6;
02447
02448
02449 Station *st;
02450 FOR_ALL_STATIONS(st) {
02451 if (st->town == t && st->owner == _current_company) {
02452 for (CargoID i = 0; i < NUM_CARGO; i++) st->goods[i].rating = 0;
02453 }
02454 }
02455
02456
02457
02458 if (IsLocalCompany()) ShowErrorMessage(STR_ERROR_BRIBE_FAILED, STR_ERROR_BRIBE_FAILED_2, 0, 0);
02459
02460
02461
02462
02463
02464 if (t->ratings[_current_company] > RATING_BRIBE_DOWN_TO) {
02465 t->ratings[_current_company] = RATING_BRIBE_DOWN_TO;
02466 SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
02467 }
02468 } else {
02469 ChangeTownRating(t, RATING_BRIBE_UP_STEP, RATING_BRIBE_MAXIMUM, DC_EXEC);
02470 }
02471 }
02472
02473 typedef void TownActionProc(Town *t);
02474 static TownActionProc * const _town_action_proc[] = {
02475 TownActionAdvertiseSmall,
02476 TownActionAdvertiseMedium,
02477 TownActionAdvertiseLarge,
02478 TownActionRoadRebuild,
02479 TownActionBuildStatue,
02480 TownActionFundBuildings,
02481 TownActionBuyRights,
02482 TownActionBribe
02483 };
02484
02491 uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t)
02492 {
02493 int num = 0;
02494 TownActions buttons = TACT_NONE;
02495
02496
02497 if (cid != COMPANY_SPECTATOR && !(_settings_game.economy.bribe && t->unwanted[cid])) {
02498
02499
02500 Money avail = Company::Get(cid)->money + _price[PR_STATION_VALUE] * 200;
02501
02502
02503
02504 for (uint i = 0; i != lengthof(_town_action_costs); i++) {
02505 const TownActions cur = (TownActions)(1 << i);
02506
02507
02508 if (cur == TACT_BRIBE && (!_settings_game.economy.bribe || t->ratings[cid] >= RATING_BRIBE_MAXIMUM))
02509 continue;
02510
02511
02512 if (cur == TACT_BUY_RIGHTS && !_settings_game.economy.exclusive_rights)
02513 continue;
02514
02515
02516 if (cur == TACT_BUILD_STATUE && HasBit(t->statues, cid))
02517 continue;
02518
02519 if (avail >= _town_action_costs[i] * _price[PR_TOWN_ACTION] >> 8) {
02520 buttons |= cur;
02521 num++;
02522 }
02523 }
02524 }
02525
02526 if (nump != NULL) *nump = num;
02527 return buttons;
02528 }
02529
02540 CommandCost CmdDoTownAction(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
02541 {
02542 Town *t = Town::GetIfValid(p1);
02543 if (t == NULL || p2 >= lengthof(_town_action_proc)) return CMD_ERROR;
02544
02545 if (!HasBit(GetMaskOfTownActions(NULL, _current_company, t), p2)) return CMD_ERROR;
02546
02547 CommandCost cost(EXPENSES_OTHER, _price[PR_TOWN_ACTION] * _town_action_costs[p2] >> 8);
02548
02549 if (flags & DC_EXEC) {
02550 _town_action_proc[p2](t);
02551 SetWindowDirty(WC_TOWN_AUTHORITY, p1);
02552 }
02553
02554 return cost;
02555 }
02556
02557 static void UpdateTownGrowRate(Town *t)
02558 {
02559
02560 const Company *c;
02561 FOR_ALL_COMPANIES(c) {
02562 if (t->ratings[c->index] < RATING_GROWTH_MAXIMUM) {
02563 t->ratings[c->index] = min((int)RATING_GROWTH_MAXIMUM, t->ratings[c->index] + RATING_GROWTH_UP_STEP);
02564 }
02565 }
02566
02567 int n = 0;
02568
02569 const Station *st;
02570 FOR_ALL_STATIONS(st) {
02571 if (DistanceSquare(st->xy, t->xy) <= t->squared_town_zone_radius[0]) {
02572 if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
02573 n++;
02574 if (Company::IsValidID(st->owner)) {
02575 int new_rating = t->ratings[st->owner] + RATING_STATION_UP_STEP;
02576 t->ratings[st->owner] = min(new_rating, INT16_MAX);
02577 }
02578 } else {
02579 if (Company::IsValidID(st->owner)) {
02580 int new_rating = t->ratings[st->owner] + RATING_STATION_DOWN_STEP;
02581 t->ratings[st->owner] = max(new_rating, INT16_MIN);
02582 }
02583 }
02584 }
02585 }
02586
02587
02588 for (uint i = 0; i < MAX_COMPANIES; i++) {
02589 t->ratings[i] = Clamp(t->ratings[i], RATING_MINIMUM, RATING_MAXIMUM);
02590 }
02591
02592 SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
02593
02594 ClrBit(t->flags, TOWN_IS_FUNDED);
02595 if (_settings_game.economy.town_growth_rate == 0 && t->fund_buildings_months == 0) return;
02596
02599 static const uint16 _grow_count_values[2][6] = {
02600 { 120, 120, 120, 100, 80, 60 },
02601 { 320, 420, 300, 220, 160, 100 }
02602 };
02603
02604 uint16 m;
02605
02606 if (t->fund_buildings_months != 0) {
02607 m = _grow_count_values[0][min(n, 5)];
02608 t->fund_buildings_months--;
02609 } else {
02610 m = _grow_count_values[1][min(n, 5)];
02611 if (n == 0 && !Chance16(1, 12)) return;
02612 }
02613
02614 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
02615 if (TilePixelHeight(t->xy) >= GetSnowLine() && t->act_food == 0 && t->population > 90)
02616 return;
02617 } else if (_settings_game.game_creation.landscape == LT_TROPIC) {
02618 if (GetTropicZone(t->xy) == TROPICZONE_DESERT && (t->act_food == 0 || t->act_water == 0) && t->population > 60)
02619 return;
02620 }
02621
02622
02623
02624 uint growth_multiplier = _settings_game.economy.town_growth_rate != 0 ? _settings_game.economy.town_growth_rate - 1 : 1;
02625
02626 m >>= growth_multiplier;
02627 if (t->larger_town) m /= 2;
02628
02629 t->growth_rate = m / (t->num_houses / 50 + 1);
02630 if (m <= t->grow_counter)
02631 t->grow_counter = m;
02632
02633 SetBit(t->flags, TOWN_IS_FUNDED);
02634 }
02635
02636 static void UpdateTownAmounts(Town *t)
02637 {
02638
02639 t->pct_pass_transported = t->new_act_pass * 256 / (t->new_max_pass + 1);
02640
02641 t->max_pass = t->new_max_pass; t->new_max_pass = 0;
02642 t->act_pass = t->new_act_pass; t->new_act_pass = 0;
02643 t->act_food = t->new_act_food; t->new_act_food = 0;
02644 t->act_water = t->new_act_water; t->new_act_water = 0;
02645
02646
02647 t->pct_mail_transported = t->new_act_mail * 256 / (t->new_max_mail + 1);
02648 t->max_mail = t->new_max_mail; t->new_max_mail = 0;
02649 t->act_mail = t->new_act_mail; t->new_act_mail = 0;
02650
02651 SetWindowDirty(WC_TOWN_VIEW, t->index);
02652 }
02653
02654 static void UpdateTownUnwanted(Town *t)
02655 {
02656 const Company *c;
02657
02658 FOR_ALL_COMPANIES(c) {
02659 if (t->unwanted[c->index] > 0) t->unwanted[c->index]--;
02660 }
02661 }
02662
02668 bool CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags)
02669 {
02670 if (!Company::IsValidID(_current_company) || (flags & DC_NO_TEST_TOWN_RATING)) return true;
02671
02672 Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority);
02673 if (t == NULL) return true;
02674
02675 if (t->ratings[_current_company] > RATING_VERYPOOR) return true;
02676
02677 _error_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS;
02678 SetDParam(0, t->index);
02679
02680 return false;
02681 }
02682
02683
02684 Town *CalcClosestTownFromTile(TileIndex tile, uint threshold)
02685 {
02686 Town *t;
02687 uint best = threshold;
02688 Town *best_town = NULL;
02689
02690 FOR_ALL_TOWNS(t) {
02691 uint dist = DistanceManhattan(tile, t->xy);
02692 if (dist < best) {
02693 best = dist;
02694 best_town = t;
02695 }
02696 }
02697
02698 return best_town;
02699 }
02700
02701
02702 Town *ClosestTownFromTile(TileIndex tile, uint threshold)
02703 {
02704 switch (GetTileType(tile)) {
02705 case MP_ROAD:
02706 if (IsRoadDepot(tile)) return CalcClosestTownFromTile(tile, threshold);
02707
02708 if (!HasTownOwnedRoad(tile)) {
02709 TownID tid = GetTownIndex(tile);
02710
02711 if (tid == (TownID)INVALID_TOWN) {
02712
02713 if (_generating_world) return CalcClosestTownFromTile(tile, threshold);
02714 assert(Town::GetNumItems() == 0);
02715 return NULL;
02716 }
02717
02718 assert(Town::IsValidID(tid));
02719 Town *town = Town::Get(tid);
02720
02721 if (DistanceManhattan(tile, town->xy) >= threshold) town = NULL;
02722
02723 return town;
02724 }
02725
02726
02727 case MP_HOUSE:
02728 return Town::GetByTile(tile);
02729
02730 default:
02731 return CalcClosestTownFromTile(tile, threshold);
02732 }
02733 }
02734
02735 static bool _town_rating_test = false;
02736 static SmallMap<const Town *, int, 4> _town_test_ratings;
02737
02738 void SetTownRatingTestMode(bool mode)
02739 {
02740 static int ref_count = 0;
02741 if (mode) {
02742 if (ref_count == 0) {
02743 _town_test_ratings.Clear();
02744 }
02745 ref_count++;
02746 } else {
02747 assert(ref_count > 0);
02748 ref_count--;
02749 }
02750 _town_rating_test = !(ref_count == 0);
02751 }
02752
02753 static int GetRating(const Town *t)
02754 {
02755 if (_town_rating_test) {
02756 SmallMap<const Town *, int>::iterator it = _town_test_ratings.Find(t);
02757 if (it != _town_test_ratings.End()) {
02758 return it->second;
02759 }
02760 }
02761 return t->ratings[_current_company];
02762 }
02763
02771 void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags)
02772 {
02773
02774 if (t == NULL || (flags & DC_NO_MODIFY_TOWN_RATING) ||
02775 !Company::IsValidID(_current_company) ||
02776 (_cheats.magic_bulldozer.value && add < 0)) {
02777 return;
02778 }
02779
02780 int rating = GetRating(t);
02781 if (add < 0) {
02782 if (rating > max) {
02783 rating += add;
02784 if (rating < max) rating = max;
02785 }
02786 } else {
02787 if (rating < max) {
02788 rating += add;
02789 if (rating > max) rating = max;
02790 }
02791 }
02792 if (_town_rating_test) {
02793 _town_test_ratings[t] = rating;
02794 } else {
02795 SetBit(t->have_ratings, _current_company);
02796 t->ratings[_current_company] = rating;
02797 SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
02798 }
02799 }
02800
02801 bool CheckforTownRating(DoCommandFlag flags, Town *t, TownRatingCheckType type)
02802 {
02803
02804 if (t == NULL || !Company::IsValidID(_current_company) ||
02805 _cheats.magic_bulldozer.value || (flags & DC_NO_TEST_TOWN_RATING)) {
02806 return true;
02807 }
02808
02809
02810 static const int needed_rating[][TOWN_RATING_CHECK_TYPE_COUNT] = {
02811
02812 { RATING_ROAD_NEEDED_PERMISSIVE, RATING_TUNNEL_BRIDGE_NEEDED_PERMISSIVE},
02813 { RATING_ROAD_NEEDED_NEUTRAL, RATING_TUNNEL_BRIDGE_NEEDED_NEUTRAL},
02814 { RATING_ROAD_NEEDED_HOSTILE, RATING_TUNNEL_BRIDGE_NEEDED_HOSTILE},
02815 };
02816
02817
02818
02819
02820
02821 int needed = needed_rating[_settings_game.difficulty.town_council_tolerance][type];
02822
02823 if (GetRating(t) < needed) {
02824 SetDParam(0, t->index);
02825 _error_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS;
02826 return false;
02827 }
02828
02829 return true;
02830 }
02831
02832 void TownsMonthlyLoop()
02833 {
02834 Town *t;
02835
02836 FOR_ALL_TOWNS(t) {
02837 if (t->road_build_months != 0) t->road_build_months--;
02838
02839 if (t->exclusive_counter != 0)
02840 if (--t->exclusive_counter == 0) t->exclusivity = INVALID_COMPANY;
02841
02842 UpdateTownGrowRate(t);
02843 UpdateTownAmounts(t);
02844 UpdateTownUnwanted(t);
02845 }
02846 }
02847
02848 void TownsYearlyLoop()
02849 {
02850
02851 for (TileIndex t = 0; t < MapSize(); t++) {
02852 if (!IsTileType(t, MP_HOUSE)) continue;
02853 IncrementHouseAge(t);
02854 }
02855 }
02856
02857 void InitializeTowns()
02858 {
02859 _town_pool.CleanPool();
02860 }
02861
02862 static CommandCost TerraformTile_Town(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02863 {
02864 if (AutoslopeEnabled()) {
02865 HouseID house = GetHouseType(tile);
02866 GetHouseNorthPart(house);
02867 const HouseSpec *hs = HouseSpec::Get(house);
02868
02869
02870 if (((hs->building_flags & TILE_NOT_SLOPED) == 0) && !IsSteepSlope(tileh_new) &&
02871 (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
02872 bool allow_terraform = true;
02873
02874
02875 house = GetHouseType(tile);
02876 hs = HouseSpec::Get(house);
02877 if (HasBit(hs->callback_mask, CBM_HOUSE_AUTOSLOPE)) {
02878
02879 uint16 res = GetHouseCallback(CBID_HOUSE_AUTOSLOPE, 0, 0, house, Town::GetByTile(tile), tile);
02880 if ((res != 0) && (res != CALLBACK_FAILED)) allow_terraform = false;
02881 }
02882
02883 if (allow_terraform) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02884 }
02885 }
02886
02887 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02888 }
02889
02891 extern const TileTypeProcs _tile_type_town_procs = {
02892 DrawTile_Town,
02893 GetSlopeZ_Town,
02894 ClearTile_Town,
02895 AddAcceptedCargo_Town,
02896 GetTileDesc_Town,
02897 GetTileTrackStatus_Town,
02898 NULL,
02899 AnimateTile_Town,
02900 TileLoop_Town,
02901 ChangeTileOwner_Town,
02902 AddProducedCargo_Town,
02903 NULL,
02904 GetFoundation_Town,
02905 TerraformTile_Town,
02906 };
02907
02908
02909 HouseSpec _house_specs[HOUSE_MAX];
02910
02911 void ResetHouses()
02912 {
02913 memset(&_house_specs, 0, sizeof(_house_specs));
02914 memcpy(&_house_specs, &_original_house_specs, sizeof(_original_house_specs));
02915
02916
02917 _house_mngr.ResetOverride();
02918 }