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