00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "tile_cmd.h"
00008 #include "debug.h"
00009 #include "road_map.h"
00010 #include "road_internal.h"
00011 #include "road_cmd.h"
00012 #include "landscape.h"
00013 #include "town_map.h"
00014 #include "tunnel_map.h"
00015 #include "viewport_func.h"
00016 #include "town.h"
00017 #include "command_func.h"
00018 #include "industry.h"
00019 #include "station_base.h"
00020 #include "company_base.h"
00021 #include "news_func.h"
00022 #include "gui.h"
00023 #include "unmovable_map.h"
00024 #include "water_map.h"
00025 #include "variables.h"
00026 #include "bridge.h"
00027 #include "bridge_map.h"
00028 #include "genworld.h"
00029 #include "newgrf.h"
00030 #include "newgrf_callbacks.h"
00031 #include "newgrf_house.h"
00032 #include "newgrf_commons.h"
00033 #include "newgrf_townname.h"
00034 #include "autoslope.h"
00035 #include "waypoint.h"
00036 #include "transparency.h"
00037 #include "tunnelbridge_map.h"
00038 #include "strings_func.h"
00039 #include "window_func.h"
00040 #include "string_func.h"
00041 #include "newgrf_cargo.h"
00042 #include "oldpool_func.h"
00043 #include "sprite.h"
00044 #include "economy_func.h"
00045 #include "station_func.h"
00046 #include "cheat_func.h"
00047 #include "functions.h"
00048 #include "animated_tile_func.h"
00049 #include "date_func.h"
00050 #include "core/smallmap_type.hpp"
00051
00052 #include "table/strings.h"
00053 #include "table/sprites.h"
00054 #include "table/town_land.h"
00055
00056 uint _total_towns;
00057 HouseSpec _house_specs[HOUSE_MAX];
00058
00059 Town *_cleared_town;
00060 int _cleared_town_rating;
00061
00062
00063 DEFINE_OLD_POOL_GENERIC(Town, Town)
00064
00065 Town::Town(TileIndex tile)
00066 {
00067 if (tile != INVALID_TILE) _total_towns++;
00068 this->xy = tile;
00069 }
00070
00071 Town::~Town()
00072 {
00073 free(this->name);
00074
00075 if (CleaningPool()) return;
00076
00077 Industry *i;
00078
00079
00080
00081 DeleteWindowById(WC_TOWN_VIEW, this->index);
00082 InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0);
00083 _total_towns--;
00084
00085
00086 FOR_ALL_INDUSTRIES(i) if (i->town == this) delete i;
00087
00088
00089 for (TileIndex tile = 0; tile < MapSize(); ++tile) {
00090 switch (GetTileType(tile)) {
00091 case MP_HOUSE:
00092 if (GetTownByTile(tile) == this) DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
00093 break;
00094
00095 case MP_ROAD:
00096
00097 if (HasTownOwnedRoad(tile) && GetTownIndex(tile) == this->index) {
00098 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
00099 }
00100 break;
00101
00102 case MP_TUNNELBRIDGE:
00103 if (IsTileOwner(tile, OWNER_TOWN) &&
00104 ClosestTownFromTile(tile, UINT_MAX) == this)
00105 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
00106 break;
00107
00108 default:
00109 break;
00110 }
00111 }
00112
00113 DeleteSubsidyWithTown(this->index);
00114
00115 MarkWholeScreenDirty();
00116
00117 this->xy = INVALID_TILE;
00118
00119 UpdateNearestTownForRoadTiles(false);
00120 }
00121
00127 void Town::InitializeLayout()
00128 {
00129 this->layout = (TownLayout)(TileHash(TileX(this->xy), TileY(this->xy)) % NUM_TLS);
00130
00131
00132 switch (this->layout) {
00133 default: break;
00134 case TL_RANDOM: this->layout = TL_ORIGINAL; break;
00135 case TL_NO_ROADS: this->layout = TL_BETTER_ROADS; break;
00136 }
00137 }
00138
00139 Money HouseSpec::GetRemovalCost() const
00140 {
00141 return (_price.remove_house * this->removal_cost) >> 8;
00142 }
00143
00144
00145 static int _grow_town_result;
00146
00147
00148 enum TownGrowthResult {
00149 GROWTH_SUCCEED = -1,
00150 GROWTH_SEARCH_STOPPED = 0
00151
00152 };
00153
00154 static bool BuildTownHouse(Town *t, TileIndex tile);
00155
00156 static void TownDrawHouseLift(const TileInfo *ti)
00157 {
00158 AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile));
00159 }
00160
00161 typedef void TownDrawTileProc(const TileInfo *ti);
00162 static TownDrawTileProc *const _town_draw_tile_procs[1] = {
00163 TownDrawHouseLift
00164 };
00165
00171 static inline DiagDirection RandomDiagDir()
00172 {
00173 return (DiagDirection)(3 & Random());
00174 }
00175
00181 static void DrawTile_Town(TileInfo *ti)
00182 {
00183 HouseID house_id = GetHouseType(ti->tile);
00184
00185 if (house_id >= NEW_HOUSE_OFFSET) {
00186
00187
00188
00189 if (GetHouseSpecs(house_id)->spritegroup != NULL) {
00190 DrawNewHouseTile(ti, house_id);
00191 return;
00192 } else {
00193 house_id = GetHouseSpecs(house_id)->substitute_id;
00194 }
00195 }
00196
00197
00198 const DrawBuildingsTileStruct *dcts = &_town_draw_tile_data[house_id << 4 | TileHash2Bit(ti->x, ti->y) << 2 | GetHouseBuildingStage(ti->tile)];
00199
00200 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
00201
00202 DrawGroundSprite(dcts->ground.sprite, dcts->ground.pal);
00203
00204
00205 if (IsInvisibilitySet(TO_HOUSES)) return;
00206
00207
00208 SpriteID image = dcts->building.sprite;
00209 if (image != 0) {
00210 AddSortableSpriteToDraw(image, dcts->building.pal,
00211 ti->x + dcts->subtile_x,
00212 ti->y + dcts->subtile_y,
00213 dcts->width,
00214 dcts->height,
00215 dcts->dz,
00216 ti->z,
00217 IsTransparencySet(TO_HOUSES)
00218 );
00219
00220 if (IsTransparencySet(TO_HOUSES)) return;
00221 }
00222
00223 {
00224 int proc = dcts->draw_proc - 1;
00225
00226 if (proc >= 0) _town_draw_tile_procs[proc](ti);
00227 }
00228 }
00229
00230 static uint GetSlopeZ_Town(TileIndex tile, uint x, uint y)
00231 {
00232 return GetTileMaxZ(tile);
00233 }
00234
00236 static Foundation GetFoundation_Town(TileIndex tile, Slope tileh)
00237 {
00238 return FlatteningFoundation(tileh);
00239 }
00240
00247 static void AnimateTile_Town(TileIndex tile)
00248 {
00249 if (GetHouseType(tile) >= NEW_HOUSE_OFFSET) {
00250 AnimateNewHouseTile(tile);
00251 return;
00252 }
00253
00254 if (_tick_counter & 3) return;
00255
00256
00257
00258
00259
00260 if (!(GetHouseSpecs(GetHouseType(tile))->building_flags & BUILDING_IS_ANIMATED)) {
00261 DeleteAnimatedTile(tile);
00262 return;
00263 }
00264
00265 if (!LiftHasDestination(tile)) {
00266 uint i;
00267
00268
00269
00270
00271
00272 do {
00273 i = RandomRange(7);
00274 } while (i == 1 || i * 6 == GetLiftPosition(tile));
00275
00276 SetLiftDestination(tile, i);
00277 }
00278
00279 int pos = GetLiftPosition(tile);
00280 int dest = GetLiftDestination(tile) * 6;
00281 pos += (pos < dest) ? 1 : -1;
00282 SetLiftPosition(tile, pos);
00283
00284 if (pos == dest) {
00285 HaltLift(tile);
00286 DeleteAnimatedTile(tile);
00287 }
00288
00289 MarkTileDirtyByTile(tile);
00290 }
00291
00298 static bool IsCloseToTown(TileIndex tile, uint dist)
00299 {
00300 const Town *t;
00301
00302 FOR_ALL_TOWNS(t) {
00303 if (DistanceManhattan(tile, t->xy) < dist) return true;
00304 }
00305 return false;
00306 }
00307
00316 static void MarkTownSignDirty(Town *t)
00317 {
00318 MarkAllViewportsDirty(
00319 t->sign.left - 6,
00320 t->sign.top - 3,
00321 t->sign.left + t->sign.width_1 * 4 + 12,
00322 t->sign.top + 45
00323 );
00324 }
00325
00331 void UpdateTownVirtCoord(Town *t)
00332 {
00333 MarkTownSignDirty(t);
00334 Point pt = RemapCoords2(TileX(t->xy) * TILE_SIZE, TileY(t->xy) * TILE_SIZE);
00335 SetDParam(0, t->index);
00336 SetDParam(1, t->population);
00337 UpdateViewportSignPos(&t->sign, pt.x, pt.y - 24,
00338 _settings_client.gui.population_in_label ? STR_TOWN_LABEL_POP : STR_TOWN_LABEL);
00339 MarkTownSignDirty(t);
00340 }
00341
00343 void UpdateAllTownVirtCoords()
00344 {
00345 Town *t;
00346 FOR_ALL_TOWNS(t) {
00347 UpdateTownVirtCoord(t);
00348 }
00349 }
00350
00356 static void ChangePopulation(Town *t, int mod)
00357 {
00358 t->population += mod;
00359 InvalidateWindow(WC_TOWN_VIEW, t->index);
00360 UpdateTownVirtCoord(t);
00361
00362 InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1);
00363 }
00364
00370 uint32 GetWorldPopulation()
00371 {
00372 uint32 pop = 0;
00373 const Town *t;
00374
00375 FOR_ALL_TOWNS(t) pop += t->population;
00376 return pop;
00377 }
00378
00383 static void MakeSingleHouseBigger(TileIndex tile)
00384 {
00385 assert(IsTileType(tile, MP_HOUSE));
00386
00387
00388 if (LiftHasDestination(tile)) return;
00389
00390
00391 IncHouseConstructionTick(tile);
00392 if (GetHouseConstructionTick(tile) != 0) return;
00393
00394 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
00395
00396
00397 if (HasBit(hs->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) {
00398 uint16 callback_res = GetHouseCallback(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00399 if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(hs->grffile, tile, callback_res);
00400 }
00401
00402 if (IsHouseCompleted(tile)) {
00403
00404
00405 ChangePopulation(GetTownByTile(tile), hs->population);
00406 ResetHouseAge(tile);
00407 }
00408 MarkTileDirtyByTile(tile);
00409 }
00410
00414 static void MakeTownHouseBigger(TileIndex tile)
00415 {
00416 uint flags = GetHouseSpecs(GetHouseType(tile))->building_flags;
00417 if (flags & BUILDING_HAS_1_TILE) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 0));
00418 if (flags & BUILDING_2_TILES_Y) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 1));
00419 if (flags & BUILDING_2_TILES_X) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 0));
00420 if (flags & BUILDING_HAS_4_TILES) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 1));
00421 }
00422
00429 static void TileLoop_Town(TileIndex tile)
00430 {
00431 HouseID house_id = GetHouseType(tile);
00432
00433
00434
00435 if (house_id >= NEW_HOUSE_OFFSET && !NewHouseTileLoop(tile)) return;
00436
00437 if (!IsHouseCompleted(tile)) {
00438
00439 MakeTownHouseBigger(tile);
00440 return;
00441 }
00442
00443 const HouseSpec *hs = GetHouseSpecs(house_id);
00444
00445
00446 if ((hs->building_flags & BUILDING_IS_ANIMATED) &&
00447 house_id < NEW_HOUSE_OFFSET &&
00448 !LiftHasDestination(tile) &&
00449 Chance16(1, 2)) {
00450 AddAnimatedTile(tile);
00451 }
00452
00453 Town *t = GetTownByTile(tile);
00454 uint32 r = Random();
00455
00456 if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
00457 for (uint i = 0; i < 256; i++) {
00458 uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, r, house_id, t, tile);
00459
00460 if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
00461
00462 CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grffile);
00463 if (cargo == CT_INVALID) continue;
00464
00465 uint amt = GB(callback, 0, 8);
00466 uint moved = MoveGoodsToStation(tile, 1, 1, cargo, amt);
00467
00468 const CargoSpec *cs = GetCargo(cargo);
00469 switch (cs->town_effect) {
00470 case TE_PASSENGERS:
00471 t->new_max_pass += amt;
00472 t->new_act_pass += moved;
00473 break;
00474
00475 case TE_MAIL:
00476 t->new_max_mail += amt;
00477 t->new_act_mail += moved;
00478 break;
00479
00480 default:
00481 break;
00482 }
00483 }
00484 } else {
00485 if (GB(r, 0, 8) < hs->population) {
00486 uint amt = GB(r, 0, 8) / 8 + 1;
00487
00488 if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
00489 t->new_max_pass += amt;
00490 t->new_act_pass += MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt);
00491 }
00492
00493 if (GB(r, 8, 8) < hs->mail_generation) {
00494 uint amt = GB(r, 8, 8) / 8 + 1;
00495
00496 if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
00497 t->new_max_mail += amt;
00498 t->new_act_mail += MoveGoodsToStation(tile, 1, 1, CT_MAIL, amt);
00499 }
00500 }
00501
00502 _current_company = OWNER_TOWN;
00503
00504 if (hs->building_flags & BUILDING_HAS_1_TILE &&
00505 HasBit(t->flags12, TOWN_IS_FUNDED) &&
00506 CanDeleteHouse(tile) &&
00507 GetHouseAge(tile) >= hs->minimum_life &&
00508 --t->time_until_rebuild == 0) {
00509 t->time_until_rebuild = GB(r, 16, 8) + 192;
00510
00511 ClearTownHouse(t, tile);
00512
00513
00514 if (GB(r, 24, 8) >= 12) BuildTownHouse(t, tile);
00515 }
00516
00517 _current_company = OWNER_NONE;
00518 }
00519
00524 static bool ClickTile_Town(TileIndex tile)
00525 {
00526
00527 return false;
00528 }
00529
00530 static CommandCost ClearTile_Town(TileIndex tile, byte flags)
00531 {
00532 if ((flags & DC_AUTO) && !(flags & DC_AI_BUILDING)) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
00533 if (!CanDeleteHouse(tile)) return CMD_ERROR;
00534
00535 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
00536
00537 CommandCost cost(EXPENSES_CONSTRUCTION);
00538 cost.AddCost(hs->GetRemovalCost());
00539
00540 int rating = hs->remove_rating_decrease;
00541 _cleared_town_rating += rating;
00542 Town *t = _cleared_town = GetTownByTile(tile);
00543
00544 if (IsValidCompanyID(_current_company)) {
00545 if (rating > t->ratings[_current_company] && !(flags & DC_NO_TOWN_RATING) && !_cheats.magic_bulldozer.value) {
00546 SetDParam(0, t->index);
00547 return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
00548 }
00549 }
00550
00551 ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM);
00552 if (flags & DC_EXEC) {
00553 ClearTownHouse(t, tile);
00554 }
00555
00556 return cost;
00557 }
00558
00559 static void GetProducedCargo_Town(TileIndex tile, CargoID *b)
00560 {
00561 HouseID house_id = GetHouseType(tile);
00562 const HouseSpec *hs = GetHouseSpecs(house_id);
00563 Town *t = GetTownByTile(tile);
00564
00565 if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
00566 for (uint i = 0; i < 256; i++) {
00567 uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, house_id, t, tile);
00568
00569 if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
00570
00571 CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grffile);
00572
00573 if (cargo == CT_INVALID) continue;
00574 *(b++) = cargo;
00575 }
00576 } else {
00577 if (hs->population > 0) {
00578 *(b++) = CT_PASSENGERS;
00579 }
00580 if (hs->mail_generation > 0) {
00581 *(b++) = CT_MAIL;
00582 }
00583 }
00584 }
00585
00586 static void GetAcceptedCargo_Town(TileIndex tile, AcceptedCargo ac)
00587 {
00588 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
00589 CargoID accepts[3];
00590
00591
00592 for (uint8 i = 0; i < lengthof(accepts); i++) {
00593 accepts[i] = hs->accepts_cargo[i];
00594 }
00595
00596
00597 if (HasBit(hs->callback_mask, CBM_HOUSE_ACCEPT_CARGO)) {
00598 uint16 callback = GetHouseCallback(CBID_HOUSE_ACCEPT_CARGO, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00599 if (callback != CALLBACK_FAILED) {
00600
00601 accepts[0] = GetCargoTranslation(GB(callback, 0, 5), hs->grffile);
00602 accepts[1] = GetCargoTranslation(GB(callback, 5, 5), hs->grffile);
00603 accepts[2] = GetCargoTranslation(GB(callback, 10, 5), hs->grffile);
00604 }
00605 }
00606
00607
00608 if (HasBit(hs->callback_mask, CBM_HOUSE_CARGO_ACCEPTANCE)) {
00609 uint16 callback = GetHouseCallback(CBID_HOUSE_CARGO_ACCEPTANCE, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00610 if (callback != CALLBACK_FAILED) {
00611 if (accepts[0] != CT_INVALID) ac[accepts[0]] = GB(callback, 0, 4);
00612 if (accepts[1] != CT_INVALID) ac[accepts[1]] = GB(callback, 4, 4);
00613 if (_settings_game.game_creation.landscape != LT_TEMPERATE && HasBit(callback, 12)) {
00614
00615 ac[CT_FOOD] = GB(callback, 8, 4);
00616 } else {
00617 if (accepts[2] != CT_INVALID) ac[accepts[2]] = GB(callback, 8, 4);
00618 }
00619 return;
00620 }
00621 }
00622
00623
00624 for (uint8 i = 0; i < lengthof(accepts); i++) {
00625 if (accepts[i] != CT_INVALID) ac[accepts[i]] = hs->cargo_acceptance[i];
00626 }
00627 }
00628
00629 static void GetTileDesc_Town(TileIndex tile, TileDesc *td)
00630 {
00631 const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
00632
00633 td->str = hs->building_name;
00634 if (!IsHouseCompleted(tile)) {
00635 SetDParamX(td->dparam, 0, td->str);
00636 td->str = STR_2058_UNDER_CONSTRUCTION;
00637 }
00638
00639 if (hs->grffile != NULL) {
00640 const GRFConfig *gc = GetGRFConfig(hs->grffile->grfid);
00641 td->grf = gc->name;
00642 }
00643
00644 td->owner[0] = OWNER_TOWN;
00645 }
00646
00647 static TrackStatus GetTileTrackStatus_Town(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
00648 {
00649
00650 return 0;
00651 }
00652
00653 static void ChangeTileOwner_Town(TileIndex tile, Owner old_owner, Owner new_owner)
00654 {
00655
00656 }
00657
00658 static bool GrowTown(Town *t);
00659
00660 static void TownTickHandler(Town *t)
00661 {
00662 if (HasBit(t->flags12, TOWN_IS_FUNDED)) {
00663 int i = t->grow_counter - 1;
00664 if (i < 0) {
00665 if (GrowTown(t)) {
00666 i = t->growth_rate;
00667 } else {
00668 i = 0;
00669 }
00670 }
00671 t->grow_counter = i;
00672 }
00673
00674 UpdateTownRadius(t);
00675 }
00676
00677 void OnTick_Town()
00678 {
00679 if (_game_mode == GM_EDITOR) return;
00680
00681
00682
00683 for (_cur_town_iter += GetMaxTownIndex() + 1;
00684 _cur_town_iter >= TOWN_GROWTH_FREQUENCY;
00685 _cur_town_iter -= TOWN_GROWTH_FREQUENCY) {
00686 uint32 i = _cur_town_ctr;
00687
00688 if (++_cur_town_ctr > GetMaxTownIndex())
00689 _cur_town_ctr = 0;
00690
00691 if (IsValidTownID(i)) TownTickHandler(GetTown(i));
00692 }
00693 }
00694
00703 static RoadBits GetTownRoadBits(TileIndex tile)
00704 {
00705 TrackBits b = GetAnyRoadTrackBits(tile, ROADTYPE_ROAD);
00706 RoadBits r = ROAD_NONE;
00707
00708 if (b == TRACK_BIT_NONE) return r;
00709 if (b & TRACK_BIT_X) r |= ROAD_X;
00710 if (b & TRACK_BIT_Y) r |= ROAD_Y;
00711 if (b & TRACK_BIT_UPPER) r |= ROAD_NE | ROAD_NW;
00712 if (b & TRACK_BIT_LOWER) r |= ROAD_SE | ROAD_SW;
00713 if (b & TRACK_BIT_LEFT) r |= ROAD_NW | ROAD_SW;
00714 if (b & TRACK_BIT_RIGHT) r |= ROAD_NE | ROAD_SE;
00715 return r;
00716 }
00717
00727 static bool IsNeighborRoadTile(TileIndex tile, const DiagDirection dir, uint dist_multi)
00728 {
00729
00730 const TileIndexDiff tid_lt[3] = {
00731 TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT)),
00732 TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT)),
00733 TileOffsByDiagDir(ReverseDiagDir(dir)),
00734 };
00735
00736
00737
00738
00739
00740 dist_multi = (dist_multi + 1) * 4;
00741 for (uint pos = 4; pos < dist_multi; pos++) {
00742 TileIndexDiff cur = 0;
00743
00744
00745
00746 cur += tid_lt[(pos & 1) ? 0 : 1];
00747 if (pos & 2) cur += tid_lt[2];
00748
00749 cur = (uint)(pos / 4) * cur;
00750 if (GetTownRoadBits(TILE_ADD(tile, cur)) & DiagDirToRoadBits((pos & 2) ? dir : ReverseDiagDir(dir))) return true;
00751 }
00752 return false;
00753 }
00754
00763 static bool IsRoadAllowedHere(Town *t, TileIndex tile, DiagDirection dir)
00764 {
00765 if (TileX(tile) < 2 || TileX(tile) >= MapMaxX() || TileY(tile) < 2 || TileY(tile) >= MapMaxY()) return false;
00766
00767 Slope cur_slope, desired_slope;
00768
00769 for (;;) {
00770
00771 if (GetTownRoadBits(tile) == ROAD_NONE) {
00772
00773
00774
00775 if (CmdFailed(DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_X : ROAD_Y), 0, DC_AUTO, CMD_BUILD_ROAD)) &&
00776 CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR)))
00777 return false;
00778 }
00779
00780 cur_slope = GetTileSlope(tile, NULL);
00781 if (cur_slope == SLOPE_FLAT) {
00782 no_slope:
00783
00784 switch (t->GetActiveLayout()) {
00785 default: NOT_REACHED();
00786
00787 case TL_ORIGINAL:
00788 return !IsNeighborRoadTile(tile, dir, 1);
00789
00790 case TL_BETTER_ROADS:
00791 return !IsNeighborRoadTile(tile, dir, 2);
00792 }
00793 }
00794
00795
00796
00797 desired_slope = (dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? SLOPE_NW : SLOPE_NE;
00798 if (desired_slope != cur_slope && ComplementSlope(desired_slope) != cur_slope) {
00799 if (Chance16(1, 8)) {
00800 CommandCost res = CMD_ERROR;
00801 if (!_generating_world && Chance16(1, 10)) {
00802
00803 res = DoCommand(tile, Chance16(1, 16) ? cur_slope : cur_slope ^ SLOPE_ELEVATED, 0,
00804 DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
00805 }
00806 if (CmdFailed(res) && Chance16(1, 3)) {
00807
00808 goto no_slope;
00809 }
00810 }
00811 return false;
00812 }
00813 return true;
00814 }
00815 }
00816
00817 static bool TerraformTownTile(TileIndex tile, int edges, int dir)
00818 {
00819 TILE_ASSERT(tile);
00820
00821 CommandCost r = DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
00822 if (CmdFailed(r) || r.GetCost() >= (_price.terraform + 2) * 8) return false;
00823 DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER | DC_EXEC, CMD_TERRAFORM_LAND);
00824 return true;
00825 }
00826
00827 static void LevelTownLand(TileIndex tile)
00828 {
00829 TILE_ASSERT(tile);
00830
00831
00832 if (IsTileType(tile, MP_HOUSE)) return;
00833 Slope tileh = GetTileSlope(tile, NULL);
00834 if (tileh == SLOPE_FLAT) return;
00835
00836
00837 if (!TerraformTownTile(tile, ~tileh & SLOPE_ELEVATED, 1)) {
00838 TerraformTownTile(tile, tileh & SLOPE_ELEVATED, 0);
00839 }
00840 }
00841
00851 static RoadBits GetTownRoadGridElement(Town *t, TileIndex tile, DiagDirection dir)
00852 {
00853
00854 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
00855 RoadBits rcmd = ROAD_NONE;
00856
00857 switch (t->GetActiveLayout()) {
00858 default: NOT_REACHED();
00859
00860 case TL_2X2_GRID:
00861 if ((grid_pos.x % 3) == 0) rcmd |= ROAD_Y;
00862 if ((grid_pos.y % 3) == 0) rcmd |= ROAD_X;
00863 break;
00864
00865 case TL_3X3_GRID:
00866 if ((grid_pos.x % 4) == 0) rcmd |= ROAD_Y;
00867 if ((grid_pos.y % 4) == 0) rcmd |= ROAD_X;
00868 break;
00869 }
00870
00871
00872 if (rcmd != ROAD_ALL) return rcmd;
00873
00874 RoadBits rb_template;
00875
00876 switch (GetTileSlope(tile, NULL)) {
00877 default: rb_template = ROAD_ALL; break;
00878 case SLOPE_W: rb_template = ROAD_NW | ROAD_SW; break;
00879 case SLOPE_SW: rb_template = ROAD_Y | ROAD_SW; break;
00880 case SLOPE_S: rb_template = ROAD_SW | ROAD_SE; break;
00881 case SLOPE_SE: rb_template = ROAD_X | ROAD_SE; break;
00882 case SLOPE_E: rb_template = ROAD_SE | ROAD_NE; break;
00883 case SLOPE_NE: rb_template = ROAD_Y | ROAD_NE; break;
00884 case SLOPE_N: rb_template = ROAD_NE | ROAD_NW; break;
00885 case SLOPE_NW: rb_template = ROAD_X | ROAD_NW; break;
00886 case SLOPE_STEEP_W:
00887 case SLOPE_STEEP_S:
00888 case SLOPE_STEEP_E:
00889 case SLOPE_STEEP_N:
00890 rb_template = ROAD_NONE;
00891 break;
00892 }
00893
00894
00895 if (DiagDirToRoadBits(ReverseDiagDir(dir)) & rb_template) return rb_template;
00896
00897 return DiagDirToRoadBits(dir) | DiagDirToRoadBits(ReverseDiagDir(dir));
00898 }
00899
00910 static bool GrowTownWithExtraHouse(Town *t, TileIndex tile)
00911 {
00912
00913 if (TileX(tile) < 2 || TileY(tile) < 2 || MapMaxX() <= TileX(tile) || MapMaxY() <= TileY(tile)) return false;
00914
00915 uint counter = 0;
00916
00917
00918 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
00919
00920 if (IsTileType(TileAddByDiagDir(tile, dir), MP_HOUSE)) counter++;
00921
00922
00923 if (counter >= 3) {
00924 if (BuildTownHouse(t, tile)) {
00925 _grow_town_result = GROWTH_SUCCEED;
00926 return true;
00927 }
00928 return false;
00929 }
00930 }
00931 return false;
00932 }
00933
00942 static bool GrowTownWithRoad(const Town *t, TileIndex tile, RoadBits rcmd)
00943 {
00944 if (CmdSucceeded(DoCommand(tile, rcmd, t->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD))) {
00945 _grow_town_result = GROWTH_SUCCEED;
00946 return true;
00947 }
00948 return false;
00949 }
00950
00961