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 "landscape.h"
00012 #include "town_map.h"
00013 #include "tunnel_map.h"
00014 #include "viewport_func.h"
00015 #include "town.h"
00016 #include "command_func.h"
00017 #include "industry.h"
00018 #include "station.h"
00019 #include "player_base.h"
00020 #include "news.h"
00021 #include "saveload.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
00042 #include "table/strings.h"
00043 #include "table/sprites.h"
00044 #include "table/town_land.h"
00045
00046 #include <map>
00047
00048 uint _total_towns;
00049 HouseSpec _house_specs[HOUSE_MAX];
00050
00051 bool _town_sort_dirty;
00052 byte _town_sort_order;
00053 const Town **_town_sort;
00054
00055 Town *_cleared_town;
00056 int _cleared_town_rating;
00057
00058
00059 DEFINE_OLD_POOL_GENERIC(Town, Town)
00060
00061 Town::Town(TileIndex tile)
00062 {
00063 if (tile != 0) _total_towns++;
00064 this->xy = tile;
00065 }
00066
00067 Town::~Town()
00068 {
00069 free(this->name);
00070
00071 if (CleaningPool()) return;
00072
00073 Industry *i;
00074
00075
00076
00077 DeleteWindowById(WC_TOWN_VIEW, this->index);
00078 _town_sort_dirty = true;
00079 _total_towns--;
00080
00081
00082 FOR_ALL_INDUSTRIES(i) if (i->town == this) delete i;
00083
00084
00085 for (TileIndex tile = 0; tile < MapSize(); ++tile) {
00086 switch (GetTileType(tile)) {
00087 case MP_HOUSE:
00088 if (GetTownByTile(tile) == this) DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
00089 break;
00090
00091 case MP_ROAD:
00092 case MP_TUNNELBRIDGE:
00093 if (IsTileOwner(tile, OWNER_TOWN) &&
00094 ClosestTownFromTile(tile, (uint)-1) == this)
00095 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
00096 break;
00097
00098 default:
00099 break;
00100 }
00101 }
00102
00103 DeleteSubsidyWithTown(this->index);
00104
00105 MarkWholeScreenDirty();
00106
00107 this->xy = 0;
00108 }
00109
00110
00111 static int _grow_town_result;
00112
00113
00114 enum TownGrowthResult {
00115 GROWTH_SUCCEED = -1,
00116 GROWTH_SEARCH_STOPPED = 0
00117
00118 };
00119
00120 static bool BuildTownHouse(Town *t, TileIndex tile);
00121
00122 static void TownDrawHouseLift(const TileInfo *ti)
00123 {
00124 AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile));
00125 }
00126
00127 typedef void TownDrawTileProc(const TileInfo *ti);
00128 static TownDrawTileProc * const _town_draw_tile_procs[1] = {
00129 TownDrawHouseLift
00130 };
00131
00132 uint OriginalTileRandomiser(uint x, uint y)
00133 {
00134 uint variant;
00135 variant = x >> 4;
00136 variant ^= x >> 6;
00137 variant ^= y >> 4;
00138 variant -= y >> 6;
00139 variant &= 3;
00140 return variant;
00141 }
00142
00148 static inline DiagDirection RandomDiagDir()
00149 {
00150 return (DiagDirection)(3 & Random());
00151 }
00152
00158 static void DrawTile_Town(TileInfo *ti)
00159 {
00160 const DrawBuildingsTileStruct *dcts;
00161 SpriteID image;
00162 SpriteID pal;
00163 HouseID house_id = GetHouseType(ti->tile);
00164
00165 if (house_id >= NEW_HOUSE_OFFSET) {
00166
00167
00168
00169 if (GetHouseSpecs(house_id)->spritegroup != NULL) {
00170 DrawNewHouseTile(ti, house_id);
00171 return;
00172 } else {
00173 house_id = GetHouseSpecs(house_id)->substitute_id;
00174 }
00175 }
00176
00177
00178 dcts = &_town_draw_tile_data[house_id << 4 | OriginalTileRandomiser(ti->x, ti->y) << 2 | GetHouseBuildingStage(ti->tile)];
00179
00180 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
00181
00182 image = dcts->ground.sprite;
00183 pal = dcts->ground.pal;
00184 DrawGroundSprite(image, pal);
00185
00186
00187 image = dcts->building.sprite;
00188 if (image != 0) {
00189 AddSortableSpriteToDraw(image, dcts->building.pal,
00190 ti->x + dcts->subtile_x,
00191 ti->y + dcts->subtile_y,
00192 dcts->width,
00193 dcts->height,
00194 dcts->dz,
00195 ti->z,
00196 IsTransparencySet(TO_HOUSES)
00197 );
00198
00199 if (IsTransparencySet(TO_HOUSES)) return;
00200 }
00201
00202 {
00203 int proc = dcts->draw_proc - 1;
00204
00205 if (proc >= 0) _town_draw_tile_procs[proc](ti);
00206 }
00207 }
00208
00209 static uint GetSlopeZ_Town(TileIndex tile, uint x, uint y)
00210 {
00211 return GetTileMaxZ(tile);
00212 }
00213
00214 static Foundation GetFoundation_Town(TileIndex tile, Slope tileh)
00215 {
00216 return FlatteningFoundation(tileh);
00217 }
00218
00225 static void AnimateTile_Town(TileIndex tile)
00226 {
00227 int pos, dest;
00228
00229 if (GetHouseType(tile) >= NEW_HOUSE_OFFSET) {
00230 AnimateNewHouseTile(tile);
00231 return;
00232 }
00233
00234 if (_tick_counter & 3) return;
00235
00236
00237
00238
00239
00240 if (!(GetHouseSpecs(GetHouseType(tile))->building_flags & BUILDING_IS_ANIMATED)) {
00241 DeleteAnimatedTile(tile);
00242 return;
00243 }
00244
00245 if (!LiftHasDestination(tile)) {
00246 int i;
00247
00248
00249
00250
00251
00252 do {
00253 i = (Random() & 7) - 1;
00254 } while (i < 0 || i == 1 || i * 6 == GetLiftPosition(tile));
00255
00256 SetLiftDestination(tile, i);
00257 }
00258
00259 pos = GetLiftPosition(tile);
00260 dest = GetLiftDestination(tile) * 6;
00261 pos += (pos < dest) ? 1 : -1;
00262 SetLiftPosition(tile, pos);
00263
00264 if (pos == dest) HaltLift(tile);
00265
00266 MarkTileDirtyByTile(tile);
00267 }
00268
00275 static bool IsCloseToTown(TileIndex tile, uint dist)
00276 {
00277 const Town* t;
00278
00279 FOR_ALL_TOWNS(t) {
00280 if (DistanceManhattan(tile, t->xy) < dist) return true;
00281 }
00282 return false;
00283 }
00284
00293 static void MarkTownSignDirty(Town *t)
00294 {
00295 MarkAllViewportsDirty(
00296 t->sign.left - 6,
00297 t->sign.top - 3,
00298 t->sign.left + t->sign.width_1 * 4 + 12,
00299 t->sign.top + 45
00300 );
00301 }
00302
00308 void UpdateTownVirtCoord(Town *t)
00309 {
00310 Point pt;
00311
00312 MarkTownSignDirty(t);
00313 pt = RemapCoords2(TileX(t->xy) * TILE_SIZE, TileY(t->xy) * TILE_SIZE);
00314 SetDParam(0, t->index);
00315 SetDParam(1, t->population);
00316 UpdateViewportSignPos(&t->sign, pt.x, pt.y - 24,
00317 _patches.population_in_label ? STR_TOWN_LABEL_POP : STR_TOWN_LABEL);
00318 MarkTownSignDirty(t);
00319 }
00320
00322 void UpdateAllTownVirtCoords()
00323 {
00324 Town *t;
00325 FOR_ALL_TOWNS(t) {
00326 UpdateTownVirtCoord(t);
00327 }
00328 }
00329
00335 static void ChangePopulation(Town *t, int mod)
00336 {
00337 t->population += mod;
00338 InvalidateWindow(WC_TOWN_VIEW, t->index);
00339 UpdateTownVirtCoord(t);
00340
00341 if (_town_sort_order & 2) _town_sort_dirty = true;
00342 }
00343
00349 uint32 GetWorldPopulation()
00350 {
00351 uint32 pop;
00352 const Town* t;
00353
00354 pop = 0;
00355 FOR_ALL_TOWNS(t) pop += t->population;
00356 return pop;
00357 }
00358
00363 static void MakeSingleHouseBigger(TileIndex tile)
00364 {
00365 assert(IsTileType(tile, MP_HOUSE));
00366
00367
00368 if (LiftHasDestination(tile)) return;
00369
00370
00371 IncHouseConstructionTick(tile);
00372 if (GetHouseConstructionTick(tile) != 0) return;
00373
00374
00375 if (HasBit(GetHouseSpecs(GetHouseType(tile))->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) {
00376 uint16 callback_res = GetHouseCallback(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00377 if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res);
00378 }
00379
00380 if (IsHouseCompleted(tile)) {
00381
00382
00383 ChangePopulation(GetTownByTile(tile), GetHouseSpecs(GetHouseType(tile))->population);
00384 }
00385 MarkTileDirtyByTile(tile);
00386 }
00387
00391 static void MakeTownHouseBigger(TileIndex tile)
00392 {
00393 uint flags = GetHouseSpecs(GetHouseType(tile))->building_flags;
00394 if (flags & BUILDING_HAS_1_TILE) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 0));
00395 if (flags & BUILDING_2_TILES_Y) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 1));
00396 if (flags & BUILDING_2_TILES_X) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 0));
00397 if (flags & BUILDING_HAS_4_TILES) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 1));
00398 }
00399
00404 static void TileLoop_Town(TileIndex tile)
00405 {
00406 Town *t;
00407 uint32 r;
00408 HouseID house_id = GetHouseType(tile);
00409 HouseSpec *hs = GetHouseSpecs(house_id);
00410
00411
00412
00413 if (house_id >= NEW_HOUSE_OFFSET && !NewHouseTileLoop(tile)) return;
00414
00415 if (!IsHouseCompleted(tile)) {
00416
00417 MakeTownHouseBigger(tile);
00418 return;
00419 }
00420
00421
00422 if ((hs->building_flags & BUILDING_IS_ANIMATED) &&
00423 house_id < NEW_HOUSE_OFFSET &&
00424 !LiftHasDestination(tile) &&
00425 Chance16(1, 2))
00426 AddAnimatedTile(tile);
00427
00428 t = GetTownByTile(tile);
00429
00430 r = Random();
00431
00432 if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
00433 for (uint i = 0; i < 256; i++) {
00434 uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, r, house_id, t, tile);
00435
00436 if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
00437
00438 CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grffile);
00439 if (cargo == CT_INVALID) continue;
00440
00441 uint amt = GB(callback, 0, 8);
00442 uint moved = MoveGoodsToStation(tile, 1, 1, cargo, amt);
00443
00444 const CargoSpec *cs = GetCargo(cargo);
00445 switch (cs->town_effect) {
00446 case TE_PASSENGERS:
00447 t->new_max_pass += amt;
00448 t->new_act_pass += moved;
00449 break;
00450
00451 case TE_MAIL:
00452 t->new_max_mail += amt;
00453 t->new_act_mail += moved;
00454 break;
00455
00456 default:
00457 break;
00458 }
00459 }
00460 } else {
00461 if (GB(r, 0, 8) < hs->population) {
00462 uint amt = GB(r, 0, 8) / 8 + 1;
00463 uint moved;
00464
00465 if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
00466 t->new_max_pass += amt;
00467 moved = MoveGoodsToStation(tile, 1, 1, CT_PASSENGERS, amt);
00468 t->new_act_pass += moved;
00469 }
00470
00471 if (GB(r, 8, 8) < hs->mail_generation) {
00472 uint amt = GB(r, 8, 8) / 8 + 1;
00473 uint moved;
00474
00475 if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
00476 t->new_max_mail += amt;
00477 moved = MoveGoodsToStation(tile, 1, 1, CT_MAIL, amt);
00478 t->new_act_mail += moved;
00479 }
00480 }
00481
00482 _current_player = OWNER_TOWN;
00483
00484 if (hs->building_flags & BUILDING_HAS_1_TILE &&
00485 HasBit(t->flags12, TOWN_IS_FUNDED) &&
00486 CanDeleteHouse(tile) &&
00487 max(_cur_year - GetHouseConstructionYear(tile), 0) >= hs->minimum_life &&
00488 --t->time_until_rebuild == 0) {
00489 t->time_until_rebuild = GB(r, 16, 8) + 192;
00490
00491 ClearTownHouse(t, tile);
00492
00493
00494 if (GB(r, 24, 8) >= 12) BuildTownHouse(t, tile);
00495 }
00496
00497 _current_player = OWNER_NONE;
00498 }
00499
00504 static void ClickTile_Town(TileIndex tile)
00505 {
00506
00507 }
00508
00509 static CommandCost ClearTile_Town(TileIndex tile, byte flags)
00510 {
00511 int rating;
00512 CommandCost cost(EXPENSES_CONSTRUCTION);
00513 Town *t;
00514 HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
00515
00516 if (flags&DC_AUTO && !(flags&DC_AI_BUILDING)) return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
00517 if (!CanDeleteHouse(tile)) return CMD_ERROR;
00518
00519 cost.AddCost(_price.remove_house * hs->removal_cost >> 8);
00520
00521 rating = hs->remove_rating_decrease;
00522 _cleared_town_rating += rating;
00523 _cleared_town = t = GetTownByTile(tile);
00524
00525 if (IsValidPlayer(_current_player)) {
00526 if (rating > t->ratings[_current_player] && !(flags & DC_NO_TOWN_RATING) && !_cheats.magic_bulldozer.value) {
00527 SetDParam(0, t->index);
00528 return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES);
00529 }
00530 }
00531
00532 ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM);
00533 if (flags & DC_EXEC) {
00534 ClearTownHouse(t, tile);
00535 }
00536
00537 return cost;
00538 }
00539
00540 static void GetAcceptedCargo_Town(TileIndex tile, AcceptedCargo ac)
00541 {
00542 HouseSpec *hs = GetHouseSpecs(GetHouseType(tile));
00543 CargoID accepts[3];
00544
00545
00546 for (uint8 i = 0; i < lengthof(accepts); i++) {
00547 accepts[i] = hs->accepts_cargo[i];
00548 }
00549
00550
00551 if (HasBit(hs->callback_mask, CBM_HOUSE_ACCEPT_CARGO)) {
00552 uint16 callback = GetHouseCallback(CBID_HOUSE_ACCEPT_CARGO, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00553 if (callback != CALLBACK_FAILED) {
00554
00555 accepts[0] = GetCargoTranslation(GB(callback, 0, 5), hs->grffile);
00556 accepts[1] = GetCargoTranslation(GB(callback, 5, 5), hs->grffile);
00557 accepts[2] = GetCargoTranslation(GB(callback, 10, 5), hs->grffile);
00558 }
00559 }
00560
00561
00562 if (HasBit(hs->callback_mask, CBM_HOUSE_CARGO_ACCEPTANCE)) {
00563 uint16 callback = GetHouseCallback(CBID_HOUSE_CARGO_ACCEPTANCE, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile);
00564 if (callback != CALLBACK_FAILED) {
00565 if (accepts[0] != CT_INVALID) ac[accepts[0]] = GB(callback, 0, 4);
00566 if (accepts[1] != CT_INVALID) ac[accepts[1]] = GB(callback, 4, 4);
00567 if (_opt.landscape != LT_TEMPERATE && HasBit(callback, 12)) {
00568
00569 ac[CT_FOOD] = GB(callback, 8, 4);
00570 } else {
00571 if (accepts[2] != CT_INVALID) ac[accepts[2]] = GB(callback, 8, 4);
00572 }
00573 return;
00574 }
00575 }
00576
00577
00578 for (uint8 i = 0; i < lengthof(accepts); i++) {
00579 if (accepts[i] != CT_INVALID) ac[accepts[i]] = hs->cargo_acceptance[i];
00580 }
00581 }
00582
00583 static void GetTileDesc_Town(TileIndex tile, TileDesc *td)
00584 {
00585 td->str = GetHouseSpecs(GetHouseType(tile))->building_name;
00586 if (!IsHouseCompleted(tile)) {
00587 SetDParamX(td->dparam, 0, td->str);
00588 td->str = STR_2058_UNDER_CONSTRUCTION;
00589 }
00590
00591 td->owner = OWNER_TOWN;
00592 }
00593
00594 static TrackStatus GetTileTrackStatus_Town(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
00595 {
00596
00597 return 0;
00598 }
00599
00600 static void ChangeTileOwner_Town(TileIndex tile, PlayerID old_player, PlayerID new_player)
00601 {
00602
00603 }
00604
00605 static bool GrowTown(Town *t);
00606
00607 static void TownTickHandler(Town *t)
00608 {
00609 if (HasBit(t->flags12, TOWN_IS_FUNDED)) {
00610 int i = t->grow_counter - 1;
00611 if (i < 0) {
00612 if (GrowTown(t)) {
00613 i = t->growth_rate;
00614 } else {
00615 i = 0;
00616 }
00617 }
00618 t->grow_counter = i;
00619 }
00620
00621 UpdateTownRadius(t);
00622 }
00623
00624 void OnTick_Town()
00625 {
00626 if (_game_mode == GM_EDITOR) return;
00627
00628
00629
00630 for (_cur_town_iter += GetMaxTownIndex() + 1;
00631 _cur_town_iter >= TOWN_GROWTH_FREQUENCY;
00632 _cur_town_iter -= TOWN_GROWTH_FREQUENCY) {
00633 uint32 i = _cur_town_ctr;
00634
00635 if (++_cur_town_ctr > GetMaxTownIndex())
00636 _cur_town_ctr = 0;
00637
00638 if (IsValidTownID(i)) TownTickHandler(GetTown(i));
00639 }
00640 }
00641
00650 static RoadBits GetTownRoadBits(TileIndex tile)
00651 {
00652 TrackBits b = GetAnyRoadTrackBits(tile, ROADTYPE_ROAD);
00653 RoadBits r = ROAD_NONE;
00654
00655 if (b == TRACK_BIT_NONE) return r;
00656 if (b & TRACK_BIT_X) r |= ROAD_X;
00657 if (b & TRACK_BIT_Y) r |= ROAD_Y;
00658 if (b & TRACK_BIT_UPPER) r |= ROAD_NE | ROAD_NW;
00659 if (b & TRACK_BIT_LOWER) r |= ROAD_SE | ROAD_SW;
00660 if (b & TRACK_BIT_LEFT) r |= ROAD_NW | ROAD_SW;
00661 if (b & TRACK_BIT_RIGHT) r |= ROAD_NE | ROAD_SE;
00662 return r;
00663 }
00664
00674 static bool IsNeighborRoadTile(TileIndex tile, const DiagDirection dir, uint dist_multi)
00675 {
00676
00677 const TileIndexDiff tid_lt[3] = {
00678 TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT)),
00679 TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT)),
00680 TileOffsByDiagDir(ReverseDiagDir(dir)),
00681 };
00682
00683
00684
00685
00686
00687 dist_multi = (dist_multi + 1) * 4;
00688 for (uint pos = 4; pos < dist_multi; pos++) {
00689 TileIndexDiff cur = 0;
00690
00691
00692
00693 cur += tid_lt[(pos & 1) ? 0 : 1];
00694 if (pos & 2) cur += tid_lt[2];
00695
00696 cur = (uint)(pos / 4) * cur;
00697 if (GetTownRoadBits(TILE_ADD(tile, cur)) & DiagDirToRoadBits((pos & 2) ? dir : ReverseDiagDir(dir))) return true;
00698 }
00699 return false;
00700 }
00701
00709 static bool IsRoadAllowedHere(TileIndex tile, DiagDirection dir)
00710 {
00711 if (TileX(tile) < 2 || TileX(tile) >= MapMaxX() || TileY(tile) < 2 || TileY(tile) >= MapMaxY()) return false;
00712
00713 Slope cur_slope, desired_slope;
00714
00715 for (;;) {
00716
00717 if (GetTownRoadBits(tile) == ROAD_NONE) {
00718
00719
00720
00721 if (CmdFailed(DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_X : ROAD_Y), 0, DC_AUTO, CMD_BUILD_ROAD)) &&
00722 CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR)))
00723 return false;
00724 }
00725
00726 cur_slope = GetTileSlope(tile, NULL);
00727 if (cur_slope == SLOPE_FLAT) {
00728 no_slope:
00729
00730 switch (_patches.town_layout) {
00731 default: NOT_REACHED();
00732
00733 case TL_ORIGINAL:
00734 return !IsNeighborRoadTile(tile, dir, 1);
00735
00736 case TL_BETTER_ROADS:
00737 return !IsNeighborRoadTile(tile, dir, 2);
00738 }
00739 }
00740
00741
00742
00743 desired_slope = (dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? SLOPE_NW : SLOPE_NE;
00744 if (desired_slope != cur_slope && ComplementSlope(desired_slope) != cur_slope) {
00745 if (Chance16(1, 8)) {
00746 CommandCost res = CMD_ERROR;
00747 if (!_generating_world && Chance16(1, 10)) {
00748
00749 res = DoCommand(tile, Chance16(1, 16) ? cur_slope : cur_slope ^ SLOPE_ELEVATED, 0,
00750 DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
00751 }
00752 if (CmdFailed(res) && Chance16(1, 3)) {
00753
00754 goto no_slope;
00755 }
00756 }
00757 return false;
00758 }
00759 return true;
00760 }
00761 }
00762
00763 static bool TerraformTownTile(TileIndex tile, int edges, int dir)
00764 {
00765 CommandCost r;
00766
00767 TILE_ASSERT(tile);
00768
00769 r = DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
00770 if (CmdFailed(r) || r.GetCost() >= (_price.terraform + 2) * 8) return false;
00771 DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER | DC_EXEC, CMD_TERRAFORM_LAND);
00772 return true;
00773 }
00774
00775 static void LevelTownLand(TileIndex tile)
00776 {
00777 Slope tileh;
00778
00779 TILE_ASSERT(tile);
00780
00781
00782 if (IsTileType(tile, MP_HOUSE)) return;
00783 tileh = GetTileSlope(tile, NULL);
00784 if (tileh == SLOPE_FLAT) return;
00785
00786
00787 if (!TerraformTownTile(tile, ~tileh & SLOPE_ELEVATED, 1)) {
00788 TerraformTownTile(tile, tileh & SLOPE_ELEVATED, 0);
00789 }
00790 }
00791
00801 static RoadBits GetTownRoadGridElement(Town* t, TileIndex tile, DiagDirection dir)
00802 {
00803
00804 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
00805 RoadBits rcmd = ROAD_NONE;
00806
00807 switch (_patches.town_layout) {
00808 default: NOT_REACHED();
00809
00810 case TL_2X2_GRID:
00811 if ((grid_pos.x % 3) == 0) rcmd |= ROAD_Y;
00812 if ((grid_pos.y % 3) == 0) rcmd |= ROAD_X;
00813 break;
00814
00815 case TL_3X3_GRID:
00816 if ((grid_pos.x % 4) == 0) rcmd |= ROAD_Y;
00817 if ((grid_pos.y % 4) == 0) rcmd |= ROAD_X;
00818 break;
00819 }
00820
00821
00822 if (rcmd != ROAD_ALL) return rcmd;
00823
00824 RoadBits rb_template;
00825
00826 switch (GetTileSlope(tile, NULL)) {
00827 default: rb_template = ROAD_ALL; break;
00828 case SLOPE_W: rb_template = ROAD_NW | ROAD_SW; break;
00829 case SLOPE_SW: rb_template = ROAD_Y | ROAD_SW; break;
00830 case SLOPE_S: rb_template = ROAD_SW | ROAD_SE; break;
00831 case SLOPE_SE: rb_template = ROAD_X | ROAD_SE; break;
00832 case SLOPE_E: rb_template = ROAD_SE | ROAD_NE; break;
00833 case SLOPE_NE: rb_template = ROAD_Y | ROAD_NE; break;
00834 case SLOPE_N: rb_template = ROAD_NE | ROAD_NW; break;
00835 case SLOPE_NW: rb_template = ROAD_X | ROAD_NW; break;
00836 case SLOPE_STEEP_W:
00837 case SLOPE_STEEP_S:
00838 case SLOPE_STEEP_E:
00839 case SLOPE_STEEP_N:
00840 rb_template = ROAD_NONE;
00841 break;
00842 }
00843
00844
00845 if (DiagDirToRoadBits(ReverseDiagDir(dir)) & rb_template) return rb_template;
00846
00847 return DiagDirToRoadBits(dir) | DiagDirToRoadBits(ReverseDiagDir(dir));
00848 }
00849
00860 static bool GrowTownWithExtraHouse(Town *t, TileIndex tile)
00861 {
00862
00863 if (TileX(tile) < 2 || TileY(tile) < 2 || MapMaxX() <= TileX(tile) || MapMaxY() <= TileY(tile)) return false;
00864
00865 uint counter = 0;
00866
00867
00868 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
00869
00870 if (IsTileType(TileAddByDiagDir(tile, dir), MP_HOUSE)) counter++;
00871
00872
00873 if (counter >= 3) {
00874 if (BuildTownHouse(t, tile)) {
00875 _grow_town_result = GROWTH_SUCCEED;
00876 return true;
00877 }
00878 return false;
00879 }
00880 }
00881 return false;
00882 }
00883
00892 static bool GrowTownWithRoad(const Town *t, TileIndex tile, RoadBits rcmd)
00893 {
00894 if (CmdSucceeded(DoCommand(tile, rcmd, t->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD))) {
00895 _grow_town_result = GROWTH_SUCCEED;
00896 return true;
00897 }
00898 return false;
00899 }
00900
00911 static bool GrowTownWithBridge(const Town *t, const TileIndex tile, const DiagDirection bridge_dir)
00912 {
00913 assert(bridge_dir < DIAGDIR_END);
00914
00915 const Slope slope = GetTileSlope(tile, NULL);
00916 if (slope == SLOPE_FLAT) return false;
00917
00918
00919
00920
00921 if (HASBITS(slope, InclinedSlope(bridge_dir))) return false;
00922
00923
00924 if (!(GetTownRoadBits(TileAddByDiagDir(tile, ReverseDiagDir(bridge_dir))) & DiagDirToRoadBits(bridge_dir))) return false;
00925
00926
00927 uint8 bridge_length = 0;
00928 TileIndex bridge_tile = tile;
00929
00930 const int delta = TileOffsByDiagDir(bridge_dir);
00931 do {
00932 if (bridge_length++ >= 11) {
00933
00934 return false;
00935 }
00936 bridge_tile += delta;
00937 } while (TileX(bridge_tile) != 0 && TileY(bridge_tile) != 0 && IsWaterTile(bridge_tile));
00938
00939
00940 if (bridge_length == 1) return false;
00941
00942 for (uint8 times = 0; times <= 22; times++) {
00943 byte bridge_type = RandomRange(MAX_BRIDGES - 1);
00944
00945
00946 if (CmdSucceeded(DoCommand(tile, bridge_tile, bridge_type | ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO, CMD_BUILD_BRIDGE))) {
00947 DoCommand(tile, bridge_tile, bridge_type | ((0x80 | ROADTYPES_ROAD) << 8), DC_EXEC | DC_AUTO, CMD_BUILD_BRIDGE);
00948 _grow_town_result = GROWTH_SUCCEED;
00949 return true;
00950 }
00951 }
00952
00953 return false;
00954 }
00955
00974 static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection target_dir, Town *t1)
00975 {
00976 RoadBits rcmd = ROAD_NONE;
00977 TileIndex tile = *tile_ptr;
00978
00979 TILE_ASSERT(tile);
00980
00981 if (cur_rb == ROAD_NONE) {
00982
00983
00984 _grow_town_result = GROWTH_SEARCH_STOPPED;
00985
00986
00987 LevelTownLand(tile);
00988
00989
00990 switch (_patches.town_layout) {
00991 default: NOT_REACHED();
00992
00993 case TL_NO_ROADS:
00994 return;
00995
00996 case TL_3X3_GRID:
00997 case TL_2X2_GRID:
00998 rcmd = GetTownRoadGridElement(t1, tile, target_dir);
00999 if (rcmd == ROAD_NONE) return;
01000 break;
01001
01002 case TL_BETTER_ROADS:
01003 case TL_ORIGINAL:
01004 if (!IsRoadAllowedHere(tile, target_dir)) return;
01005
01006 DiagDirection source_dir = ReverseDiagDir(target_dir);
01007
01008 if (Chance16(1, 4)) {
01009
01010 do target_dir = RandomDiagDir(); while (target_dir == source_dir);
01011 }
01012
01013 if (!IsRoadAllowedHere(TileAddByDiagDir(tile, target_dir), target_dir)) {
01014
01015
01016 if (target_dir != ReverseDiagDir(source_dir)) return;
01017
01018
01019 if (!IsTileType(TileAddByDiagDir(tile, ChangeDiagDir(target_dir, DIAGDIRDIFF_90RIGHT)), MP_HOUSE) &&
01020 !IsTileType(TileAddByDiagDir(tile, ChangeDiagDir(target_dir, DIAGDIRDIFF_90LEFT)), MP_HOUSE)) {
01021 return;
01022 }
01023
01024
01025
01026 }
01027
01028 rcmd = DiagDirToRoadBits(target_dir) | DiagDirToRoadBits(source_dir);
01029 break;
01030 }
01031
01032 } else if (target_dir < DIAGDIR_END && !(cur_rb & DiagDirToRoadBits(ReverseDiagDir(target_dir)))) {
01033
01034
01035
01036 _grow_town_result = GROWTH_SEARCH_STOPPED;
01037
01038 switch (_patches.town_layout) {
01039 default: NOT_REACHED();
01040
01041 case TL_NO_ROADS:
01042 return;
01043
01044 case TL_3X3_GRID:
01045 case TL_2X2_GRID:
01046 rcmd = GetTownRoadGridElement(t1, tile, target_dir);
01047 break;
01048
01049 case TL_BETTER_ROADS:
01050 case TL_ORIGINAL:
01051 rcmd = DiagDirToRoadBits(ReverseDiagDir(target_dir));
01052 break;
01053 }
01054 } else {
01055 bool allow_house = false;
01056
01057
01058 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
01059 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
01060 *tile_ptr = GetOtherTunnelBridgeEnd(tile);
01061 }
01062 return;
01063 }
01064
01065
01066
01067 target_dir = RandomDiagDir();
01068 if (cur_rb & DiagDirToRoadBits(target_dir)) return;
01069
01070
01071 TileIndex house_tile = TileAddByDiagDir(tile, target_dir);
01072
01073
01074 if (IsWaterTile(house_tile)) return;
01075
01076 switch (_patches.town_layout) {
01077 default: NOT_REACHED();
01078
01079 case TL_NO_ROADS:
01080 allow_house = true;
01081 break;
01082
01083 case TL_3X3_GRID:
01084 GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir));
01085
01086
01087 case TL_2X2_GRID:
01088 rcmd = GetTownRoadGridElement(t1, house_tile, target_dir);
01089 allow_house = (rcmd == ROAD_NONE);
01090 break;
01091
01092 case TL_BETTER_ROADS:
01093 GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir));
01094
01095
01096 case TL_ORIGINAL:
01097
01098
01099 rcmd = DiagDirToRoadBits(target_dir);
01100 allow_house = (!IsRoadAllowedHere(house_tile, target_dir) || Chance16(6, 10));
01101 break;
01102 }
01103
01104 if (allow_house) {
01105
01106 if (!IsTileType(house_tile, MP_HOUSE)) {
01107
01108 if (Chance16(1, 6)) LevelTownLand(house_tile);
01109
01110
01111
01112 if (BuildTownHouse(t1, house_tile)) {
01113 _grow_town_result = GROWTH_SUCCEED;
01114 }
01115 }
01116 return;
01117 }
01118
01119 _grow_town_result = GROWTH_SEARCH_STOPPED;
01120 }
01121
01122
01123 if (IsWaterTile(tile)) return;
01124
01125
01126 rcmd = CleanUpRoadBits(tile, rcmd);
01127 if (rcmd == ROAD_NONE) return;
01128
01129
01130
01131
01132 if (GrowTownWithBridge(t1, tile, target_dir)) return;
01133
01134 GrowTownWithRoad(t1, tile, rcmd);
01135 }
01136
01142 static int GrowTownAtRoad(Town *t, TileIndex tile)
01143 {
01144
01145
01146
01147 DiagDirection target_dir = DIAGDIR_END;
01148
01149 TILE_ASSERT(tile);
01150
01151
01152
01153
01154 switch (_patches.town_layout) {
01155 case TL_BETTER_ROADS:
01156 _grow_town_result = 10 + t->num_houses * 2 / 9;
01157 break;
01158
01159 case TL_3X3_GRID:
01160 case TL_2X2_GRID:
01161 _grow_town_result = 10 + t->num_houses * 1 / 9;
01162 break;
01163
01164 default:
01165 _grow_town_result = 10 + t->num_houses * 4 / 9;
01166 break;
01167 }
01168
01169 do {
01170 RoadBits cur_rb = GetTownRoadBits(tile);
01171
01172
01173 GrowTownInTile(&tile, cur_rb, target_dir, t);
01174
01175
01176
01177 cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir));
01178 if (cur_rb == ROAD_NONE)
01179 return _grow_town_result;
01180
01181
01182
01183 do target_dir = RandomDiagDir(); while (!(cur_rb & DiagDirToRoadBits(target_dir)));
01184 tile = TileAddByDiagDir(tile, target_dir);
01185
01186 if (IsTileType(tile, MP_ROAD)) {
01187
01188 if (IsTileOwner(tile, OWNER_TOWN) && GetTownByTile(tile) != t) {
01189 _grow_town_result = GROWTH_SUCCEED;
01190 } else if (IsTileOwner(tile, OWNER_NONE) && _game_mode == GM_EDITOR) {
01191
01192
01193 SetTileOwner(tile, OWNER_TOWN);
01194 SetTownIndex(tile, t->index);
01195 }
01196 }
01197
01198
01199 } while (--_grow_town_result >= 0);
01200
01201 return (_grow_town_result == -2);
01202 }
01203
01211 static RoadBits GenRandomRoadBits()
01212 {
01213 uint32 r = Random();
01214 uint a = GB(r, 0, 2);
01215 uint b = GB(r, 8, 2);
01216 if (a == b) b ^= 2;
01217 return (RoadBits)((ROAD_NW << a) + (ROAD_NW << b));
01218 }
01219
01222 static bool GrowTown(Town *t)
01223 {
01224
01225
01226
01227
01228 if (_patches.town_layout == TL_NO_ROADS && _generating_world) {
01229 return false;
01230 }
01231
01232 static const TileIndexDiffC _town_coord_mod[] = {
01233 {-1, 0},
01234 { 1, 1},
01235 { 1, -1},
01236 {-1, -1},
01237 {-1, 0},
01238 { 0, 2},
01239 { 2, 0},
01240 { 0, -2},
01241 {-1, -1},
01242 {-2, 2},
01243 { 2, 2},
01244 { 2, -2},
01245 { 0, 0}
01246 };
01247 const TileIndexDiffC *ptr;
01248
01249
01250 PlayerID old_player = _current_player;
01251 _current_player = OWNER_TOWN;
01252
01253 TileIndex tile = t->xy;
01254
01255
01256 for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
01257 if (GetTownRoadBits(tile) != ROAD_NONE) {
01258 int r = GrowTownAtRoad(t, tile);
01259 _current_player = old_player;
01260 return r != 0;
01261 }
01262 tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
01263 }
01264
01265
01266
01267 tile = t->xy;
01268 for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
01269
01270 if (!IsTileType(tile, MP_HOUSE) && GetTileSlope(tile, NULL) == SLOPE_FLAT) {
01271 if (CmdSucceeded(DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR))) {
01272 DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD);
01273 _current_player = old_player;
01274 return true;
01275 }
01276 }
01277 tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
01278 }
01279
01280 _current_player = old_player;
01281 return false;
01282 }
01283
01284 void UpdateTownRadius(Town *t)
01285 {
01286 static const uint16 _town_radius_data[23][5] = {
01287 { 4, 0, 0, 0, 0},
01288 { 16, 0, 0, 0, 0},
01289 { 25, 0, 0, 0, 0},
01290 { 36, 0, 0, 0, 0},
01291 { 49, 0, 4, 0, 0},
01292 { 64, 0, 4, 0, 0},
01293 { 64, 0, 9, 0, 1},
01294 { 64, 0, 9, 0, 4},
01295 { 64, 0, 16, 0, 4},
01296 { 81, 0, 16, 0, 4},
01297 { 81, 0, 16, 0, 4},
01298 { 81, 0, 25, 0, 9},
01299 { 81, 36, 25, 0, 9},
01300 { 81, 36, 25, 16, 9},
01301 { 81, 49, 0, 25, 9},
01302 { 81, 64, 0, 25, 9},
01303 { 81, 64, 0, 36, 9},
01304 { 81, 64, 0, 36, 16},
01305 {100, 81, 0, 49, 16},
01306 {100, 81, 0, 49, 25},
01307 {121, 81, 0, 49, 25},
01308 {121, 81, 0, 49, 25},
01309 {121, 81, 0, 49, 36},
01310 };
01311
01312 if (t->num_houses < 92) {
01313 memcpy(t->radius, _town_radius_data[t->num_houses / 4], sizeof(t->radius));
01314 } else {
01315 int mass = t->num_houses / 8;
01316
01317
01318 t->radius[0] = mass * mass;
01319
01320
01321 t->radius[1] = mass * 7;
01322 t->radius[2] = 0;
01323 t->radius[3] = mass * 4;
01324 t->radius[4] = mass * 3;
01325
01326 }
01327 }
01328
01329 static bool CreateTownName(uint32 *townnameparts)
01330 {
01331 extern int _nb_orig_names;
01332 Town *t2;
01333 char buf1[64];
01334 char buf2[64];
01335 uint32 r;
01336
01337
01338
01339
01340
01341 int tries = 1000;
01342 bool grf = (_opt.town_name >= _nb_orig_names);
01343 uint32 grfid = grf ? GetGRFTownNameId(_opt.town_name - _nb_orig_names) : 0;
01344 uint16 townnametype = grf ? GetGRFTownNameType(_opt.town_name - _nb_orig_names) : SPECSTR_TOWNNAME_START + _opt.town_name;
01345
01346 assert(townnameparts);
01347
01348 for (;;) {
01349 restart:
01350 r = Random();
01351
01352 SetDParam(0, r);
01353 if (grf && grfid != 0) {
01354 GRFTownNameGenerate(buf1, grfid, townnametype, r, lastof(buf1));
01355 } else {
01356 GetString(buf1, townnametype, lastof(buf1));
01357 }
01358
01359
01360 if (strlen(buf1) >= 31 || GetStringBoundingBox(buf1).width > 130) continue;
01361
01362 FOR_ALL_TOWNS(t2) {
01363
01364
01365 SetDParam(0, t2->index);
01366 GetString(buf2, STR_TOWN, lastof(buf2));
01367 if (strcmp(buf1, buf2) == 0) {
01368 if (tries-- < 0) return false;
01369 goto restart;
01370 }
01371 }
01372 *townnameparts = r;
01373 return true;
01374 }
01375 }
01376
01377 void UpdateTownMaxPass(Town *t)
01378 {
01379 t->max_pass = t->population >> 3;
01380 t->max_mail = t->population >> 4;
01381 }
01382
01392 static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSizeMode size_mode, uint size)
01393 {
01394 extern int _nb_orig_names;
01395 int x, i;
01396
01397 t->xy = tile;
01398 t->num_houses = 0;
01399 t->time_until_rebuild = 10;
01400 UpdateTownRadius(t);
01401 t->flags12 = 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 (i = 0; i != MAX_PLAYERS; i++)
01423 t->ratings[i] = 500;
01424
01425 t->have_ratings = 0;
01426 t->exclusivity = INVALID_PLAYER;
01427 t->exclusive_counter = 0;
01428 t->statues = 0;
01429
01430 if (_opt.town_name < _nb_orig_names) {
01431
01432 t->townnamegrfid = 0;
01433 t->townnametype = SPECSTR_TOWNNAME_START + _opt.town_name;
01434 } else {
01435
01436 t->townnamegrfid = GetGRFTownNameId(_opt.town_name - _nb_orig_names);
01437 t->townnametype = GetGRFTownNameType(_opt.town_name - _nb_orig_names);
01438 }
01439 t->townnameparts = townnameparts;
01440
01441 UpdateTownVirtCoord(t);
01442 _town_sort_dirty = true;
01443
01444
01445 x = (Random() & 0xF) + 8;
01446
01447 switch (size_mode) {
01448 default: NOT_REACHED();
01449
01450 case TSM_RANDOM:
01451 t->larger_town = false;
01452 break;
01453
01454 case TSM_FIXED:
01455 x = size * 16 + 3;
01456 t->larger_town = false;
01457 break;
01458
01459 case TSM_CITY:
01460 x *= _patches.initial_city_size;
01461 t->larger_town = true;
01462 break;
01463 }
01464
01465 t->num_houses += x;
01466 UpdateTownRadius(t);
01467
01468 i = x * 4;
01469 do {
01470 GrowTown(t);
01471 } while (--i);
01472
01473 t->num_houses -= x;
01474 UpdateTownRadius(t);
01475 UpdateTownMaxPass(t);
01476 }
01477
01486 CommandCost CmdBuildTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
01487 {
01488 uint32 townnameparts;
01489
01490
01491 if (_game_mode != GM_EDITOR) return CMD_ERROR;
01492 if (p2 > TSM_CITY) return CMD_ERROR;
01493
01494
01495 if (DistanceFromEdge(tile) < 12)
01496 return_cmd_error(STR_0237_TOO_CLOSE_TO_EDGE_OF_MAP);
01497
01498
01499 if ((!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) || GetTileSlope(tile, NULL) != SLOPE_FLAT) {
01500 return_cmd_error(STR_0239_SITE_UNSUITABLE);
01501 }
01502
01503
01504 if (IsCloseToTown(tile, 20))
01505 return_cmd_error(STR_0238_TOO_CLOSE_TO_ANOTHER_TOWN);
01506
01507
01508 if (!CreateTownName(&townnameparts))
01509 return_cmd_error(STR_023A_TOO_MANY_TOWNS);
01510
01511
01512 if (!Town::CanAllocateItem()) return_cmd_error(STR_023A_TOO_MANY_TOWNS);
01513
01514
01515 if (flags & DC_EXEC) {
01516 Town *t = new Town(tile);
01517 _generating_world = true;
01518 DoCreateTown(t, tile, townnameparts, (TownSizeMode)p2, p1);
01519 _generating_world = false;
01520 }
01521 return CommandCost();
01522 }
01523
01524 Town *CreateRandomTown(uint attempts, TownSizeMode mode, uint size)
01525 {
01526 TileIndex tile;
01527 Town *t;
01528 uint32 townnameparts;
01529
01530 do {
01531
01532 tile = RandomTile();
01533 if (DistanceFromEdge(tile) < 20) continue;
01534
01535
01536 if (!IsTileType(tile, MP_CLEAR) || GetTileSlope(tile, NULL) != SLOPE_FLAT) continue;
01537
01538
01539 if (IsCloseToTown(tile, 20)) continue;
01540
01541
01542 if (!CreateTownName(&townnameparts)) break;
01543
01544
01545 t = new Town(tile);
01546 if (t == NULL) break;
01547
01548 DoCreateTown(t, tile, townnameparts, mode, size);
01549 return t;
01550 } while (--attempts);
01551 return NULL;
01552 }
01553
01554 static const byte _num_initial_towns[4] = {5, 11, 23, 46};
01555
01556 bool GenerateTowns()
01557 {
01558 uint num = 0;
01559 uint n = ScaleByMapSize(_num_initial_towns[_opt.diff.number_towns] + (Random() & 7));
01560 uint num_cities = _patches.larger_towns == 0 ? 0 : n / _patches.larger_towns;
01561
01562 SetGeneratingWorldProgress(GWP_TOWN, n);
01563
01564 do {
01565 IncreaseGeneratingWorldProgress(GWP_TOWN);
01566
01567 TownSizeMode mode = num_cities > 0 ? TSM_CITY : TSM_RANDOM;
01568 if (CreateRandomTown(20, mode, _patches.initial_city_size) != NULL) num++;
01569 if (num_cities > 0) num_cities--;
01570 } while (--n);
01571
01572
01573 if (num == 0 && CreateRandomTown(10000, TSM_RANDOM, 0) == NULL) {
01574 if (GetNumTowns() == 0) {
01575
01576 if (_game_mode != GM_EDITOR) error("Could not generate any town");
01577
01578 return false;
01579 }
01580 }
01581
01582 return true;
01583 }
01584
01585
01591 HouseZonesBits GetTownRadiusGroup(const Town* t, TileIndex tile)
01592 {
01593 uint dist = DistanceSquare(tile, t->xy);
01594 HouseZonesBits smallest;
01595 uint i;
01596
01597 if (t->fund_buildings_months && dist <= 25) return HZB_TOWN_CENTRE;
01598
01599 smallest = HZB_TOWN_EDGE;
01600 for (i = 0; i != lengthof(t->radius); i++) {
01601 if (dist < t->radius[i]) smallest = (HouseZonesBits)i;
01602 }
01603
01604 return smallest;
01605 }
01606
01617 static inline void ClearMakeHouseTile(TileIndex tile, Town *t, byte counter, byte stage, HouseID type, byte random_bits)
01618 {
01619 #if !defined(NDEBUG) || defined(WITH_ASSERT)
01620 CommandCost cc =
01621 #endif
01622
01623 DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
01624
01625 assert(CmdSucceeded(cc));
01626
01627 IncreaseBuildingCount(t, type);
01628 MakeHouseTile(tile, t->index, counter, stage, type, random_bits);
01629 }
01630
01631
01642 static void MakeTownHouse(TileIndex t, Town *town, byte counter, byte stage, HouseID type, byte random_bits)
01643 {
01644 BuildingFlags size = GetHouseSpecs(type)->building_flags;
01645
01646 ClearMakeHouseTile(t, town, counter, stage, type, random_bits);
01647 if (size & BUILDING_2_TILES_Y) ClearMakeHouseTile(t + TileDiffXY(0, 1), town, counter, stage, ++type, random_bits);
01648 if (size & BUILDING_2_TILES_X) ClearMakeHouseTile(t + TileDiffXY(1, 0), town, counter, stage, ++type, random_bits);
01649 if (size & BUILDING_HAS_4_TILES) ClearMakeHouseTile(t + TileDiffXY(1, 1), town, counter, stage, ++type, random_bits);
01650 }
01651
01652
01661 static inline bool CanBuildHouseHere(TileIndex tile, TownID town, bool noslope)
01662 {
01663
01664 Slope slope = GetTileSlope(tile, NULL);
01665 if ((noslope && slope != SLOPE_FLAT) || IsSteepSlope(slope)) return false;
01666
01667
01668 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
01669
01670
01671 if (IsTileType(tile, MP_HOUSE) && GetTownIndex(tile) != town) return false;
01672
01673
01674 return CmdSucceeded(DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR));
01675 }
01676
01677
01687 static inline bool CheckBuildHouseSameZ(TileIndex tile, TownID town, uint z, bool noslope)
01688 {
01689 if (!CanBuildHouseHere(tile, town, noslope)) return false;
01690
01691
01692 if (GetTileMaxZ(tile) != z) return false;
01693
01694 return true;
01695 }
01696
01697
01707 static bool CheckFree2x2Area(TileIndex tile, TownID town, uint z, bool noslope)
01708 {
01709
01710 if (!CheckBuildHouseSameZ(tile, town, z, noslope)) return false;
01711
01712 for (DiagDirection d = DIAGDIR_SE; d < DIAGDIR_END; d++) {
01713 tile += TileOffsByDiagDir(d);
01714 if (!CheckBuildHouseSameZ(tile, town, z, noslope)) return false;
01715 }
01716
01717 return true;
01718 }
01719
01720
01728 static inline bool TownLayoutAllowsHouseHere(Town *t, TileIndex tile)
01729 {
01730 TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
01731
01732 switch (_patches.town_layout) {
01733 case TL_2X2_GRID:
01734 if ((grid_pos.x % 3) == 0 || (grid_pos.y % 3) == 0) return false;
01735 break;
01736
01737 case TL_3X3_GRID:
01738 if ((grid_pos.x % 4) == 0 || (grid_pos.y % 4) == 0) return false;
01739 break;
01740
01741 default:
01742 break;
01743 }
01744
01745 return true;
01746 }
01747
01748
01756 static inline bool TownLayoutAllows2x2HouseHere(Town *t, TileIndex tile)
01757 {
01758
01759
01760 uint dx = MapSize() + TileX(t->xy) - TileX(tile);
01761 uint dy = MapSize() + TileY(t->xy) - TileY(tile);
01762
01763 switch (_patches.town_layout) {
01764 case TL_2X2_GRID:
01765 if ((dx % 3) != 0 || (dy % 3) != 0) return false;
01766 break;
01767
01768 case TL_3X3_GRID:
01769 if ((dx % 4) < 2 || (dy % 4) < 2) return false;
01770 break;
01771
01772 default:
01773 break;
01774 }
01775
01776 return true;
01777 }
01778
01779
01789 static bool CheckTownBuild2House(TileIndex *tile, Town *t, uint maxz, bool noslope, DiagDirection second)
01790 {
01791
01792
01793 TileIndex tile2 = *tile + TileOffsByDiagDir(second);
01794 if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope)) return true;
01795
01796 tile2 = *tile + TileOffsByDiagDir(ReverseDiagDir(second));
01797 if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope)) {
01798 *tile = tile2;
01799 return true;
01800 }
01801
01802 return false;
01803 }
01804
01805
01814 static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, uint maxz, bool noslope)
01815 {
01816 TileIndex tile2 = *tile;
01817
01818 for (DiagDirection d = DIAGDIR_SE;;d++) {
01819 if (TownLayoutAllows2x2HouseHere(t, tile2) && CheckFree2x2Area(tile2, t->index, maxz, noslope)) {
01820 *tile = tile2;
01821 return true;
01822 }
01823 if (d == DIAGDIR_END) break;
01824 tile2 += TileOffsByDiagDir(ReverseDiagDir(d));
01825 }
01826
01827 return false;
01828 }
01829
01830
01837 static bool BuildTownHouse(Town *t, TileIndex tile)
01838 {
01839
01840 if (!TownLayoutAllowsHouseHere(t, tile)) return false;
01841
01842
01843 if (!CanBuildHouseHere(tile, t->index, false)) return false;
01844
01845 uint z;
01846 Slope slope = GetTileSlope(tile, &z);
01847
01848
01849
01850 HouseZonesBits rad = GetTownRadiusGroup(t, tile);
01851
01852
01853 int land = _opt.landscape;
01854 if (land == LT_ARCTIC && z >= _opt.snow_line) land = -1;
01855
01856 uint bitmask = (1 << rad) + (1 << (land + 12));
01857
01858
01859
01860
01861 HouseID houses[HOUSE_MAX];
01862 uint num = 0;
01863 uint probs[HOUSE_MAX];
01864 uint probability_max = 0;
01865
01866
01867 for (uint i = 0; i < HOUSE_MAX; i++) {
01868 HouseSpec *hs = GetHouseSpecs(i);
01869
01870 if ((~hs->building_availability & bitmask) == 0 && hs->enabled) {
01871
01872 uint cur_prob = (_loaded_newgrf_features.has_newhouses ? hs->probability : 1);
01873 probability_max += cur_prob;
01874 probs[num] = cur_prob;
01875 houses[num++] = (HouseID)i;
01876 }
01877 }
01878
01879 uint maxz = GetTileMaxZ(tile);
01880
01881 while (probability_max > 0) {
01882 uint r = RandomRange(probability_max);
01883 uint i;
01884 for (i = 0; i < num; i++) {
01885 if (probs[i] > r) break;
01886 r -= probs[i];
01887 }
01888
01889 HouseID house = houses[i];
01890 probability_max -= probs[i];
01891
01892
01893 num--;
01894 houses[i] = houses[num];
01895 probs[i] = probs[num];
01896
01897 HouseSpec *hs = GetHouseSpecs(house);
01898
01899 if (_loaded_newgrf_features.has_newhouses) {
01900 if (hs->override != 0) {
01901 house = hs->override;
01902 hs = GetHouseSpecs(house);
01903 }
01904
01905 if ((hs->extra_flags & BUILDING_IS_HISTORICAL) && !_generating_world) continue;
01906 }
01907
01908 if (_cur_year < hs->min_date || _cur_year > hs->max_date) continue;
01909
01910
01911 uint oneof = 0;
01912
01913 if (hs->building_flags & BUILDING_IS_CHURCH) {
01914 SetBit(oneof, TOWN_HAS_CHURCH);
01915 } else if (hs->building_flags & BUILDING_IS_STADIUM) {
01916 SetBit(oneof, TOWN_HAS_STADIUM);
01917 }
01918
01919 if (HASBITS(t->flags12, oneof)) continue;
01920
01921
01922 bool noslope = (hs->building_flags & TILE_NOT_SLOPED) != 0;
01923 if (noslope && slope != SLOPE_FLAT) continue;
01924
01925 if (hs->building_flags & TILE_SIZE_2x2) {
01926 if (!CheckTownBuild2x2House(&tile, t, maxz, noslope)) continue;
01927 } else if (hs->building_flags & TILE_SIZE_2x1) {
01928 if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SW)) continue;
01929 } else if (hs->building_flags & TILE_SIZE_1x2) {
01930 if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SE)) continue;
01931 } else {
01932
01933 }
01934
01935 if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
01936 uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile);
01937 if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) == 0) continue;
01938 }
01939
01940
01941 t->num_houses++;
01942
01943
01944 t->flags12 |= oneof;
01945
01946 byte construction_counter = 0;
01947 byte construction_stage = 0;
01948
01949 if (_generating_world) {
01950 uint32 r = Random();
01951
01952 construction_stage = TOWN_HOUSE_COMPLETED;
01953 if (Chance16(1, 7)) construction_stage = GB(r, 0, 2);
01954
01955 if (construction_stage == TOWN_HOUSE_COMPLETED) {
01956 ChangePopulation(t, hs->population);
01957 } else {
01958 construction_counter = GB(r, 2, 2);
01959 }
01960 }
01961
01962 MakeTownHouse(tile, t, construction_counter, construction_stage, house, Random());
01963
01964 return true;
01965 }
01966
01967 return false;
01968 }
01969
01970
01971 static void DoClearTownHouseHelper(TileIndex tile, Town *t, HouseID house)
01972 {
01973 assert(IsTileType(tile, MP_HOUSE));
01974 DecreaseBuildingCount(t, house);
01975 DoClearSquare(tile);
01976 DeleteAnimatedTile(tile);
01977 }
01978
01986 TileIndex GetHouseNorthPart(HouseID &house)
01987 {
01988 if (house >= 3) {
01989 if (GetHouseSpecs(house - 1)->building_flags & TILE_SIZE_2x1) {
01990 house--;
01991 return TileDiffXY(-1, 0);
01992 } else if (GetHouseSpecs(house - 1)->building_flags & BUILDING_2_TILES_Y) {
01993 house--;
01994 return TileDiffXY(0, -1);
01995 } else if (GetHouseSpecs(house - 2)->building_flags & BUILDING_HAS_4_TILES) {
01996 house -= 2;
01997 return TileDiffXY(-1, 0);
01998 } else if (GetHouseSpecs(house - 3)->building_flags & BUILDING_HAS_4_TILES) {
01999 house -= 3;
02000 return TileDiffXY(-1, -1);
02001 }
02002 }
02003 return 0;
02004 }
02005
02006 void ClearTownHouse(Town *t, TileIndex tile)
02007 {
02008 HouseID house = GetHouseType(tile);
02009 uint eflags;
02010 HouseSpec *hs;
02011
02012 assert(IsTileType(tile, MP_HOUSE));
02013
02014
02015 tile += GetHouseNorthPart(house);
02016
02017 hs = GetHouseSpecs(house);
02018
02019
02020 if (IsHouseCompleted(tile)) {
02021 ChangePopulation(t, -hs->population);
02022 }
02023
02024 t->num_houses--;
02025
02026
02027 if (hs->building_flags & BUILDING_IS_CHURCH) {
02028 ClrBit(t->flags12, TOWN_HAS_CHURCH);
02029 } else if (hs->building_flags & BUILDING_IS_STADIUM) {
02030 ClrBit(t->flags12, TOWN_HAS_STADIUM);
02031 }
02032
02033
02034 eflags = hs->building_flags;
02035 DoClearTownHouseHelper(tile, t, house);
02036 if (eflags & BUILDING_2_TILES_Y) DoClearTownHouseHelper(tile + TileDiffXY(0, 1), t, ++house);
02037 if (eflags & BUILDING_2_TILES_X) DoClearTownHouseHelper(tile + TileDiffXY(1, 0), t, ++house);
02038 if (eflags & BUILDING_HAS_4_TILES) DoClearTownHouseHelper(tile + TileDiffXY(1, 1), t, ++house);
02039 }
02040
02041 static bool IsUniqueTownName(const char *name)
02042 {
02043 const Town *t;
02044 char buf[512];
02045
02046 FOR_ALL_TOWNS(t) {
02047 SetDParam(0, t->index);
02048 GetString(buf, STR_TOWN, lastof(buf));
02049 if (strcmp(buf, name) == 0) return false;
02050 }
02051
02052 return true;
02053 }
02054
02061 CommandCost CmdRenameTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
02062 {
02063 Town *t;
02064
02065 if (!IsValidTownID(p1) || StrEmpty(_cmd_text)) return CMD_ERROR;
02066
02067 t = GetTown(p1);
02068
02069 if (!IsUniqueTownName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
02070
02071 if (flags & DC_EXEC) {
02072 free(t->name);
02073 t->name = strdup(_cmd_text);
02074
02075 UpdateTownVirtCoord(t);
02076 _town_sort_dirty = true;
02077 UpdateAllStationVirtCoord();
02078 UpdateAllWaypointSigns();
02079 MarkWholeScreenDirty();
02080 }
02081 return CommandCost();
02082 }
02083
02085 void ExpandTown(Town *t)
02086 {
02087 uint amount, n;
02088
02089 _generating_world = true;
02090
02091
02092 amount = RandomRange(ClampToU16(t->num_houses / 10)) + 3;
02093 t->num_houses += amount;
02094 UpdateTownRadius(t);
02095
02096 n = amount * 10;
02097 do GrowTown(t); while (--n);
02098
02099 t->num_houses -= amount;
02100 UpdateTownRadius(t);
02101
02102 UpdateTownMaxPass(t);
02103 _generating_world = false;
02104 }
02105
02106 extern const byte _town_action_costs[8] = {
02107 2, 4, 9, 35, 48, 53, 117, 175
02108 };
02109
02110 static void TownActionAdvertiseSmall(Town* t)
02111 {
02112 ModifyStationRatingAround(t->xy, _current_player, 0x40, 10);
02113 }
02114
02115 static void TownActionAdvertiseMedium(Town* t)
02116 {
02117 ModifyStationRatingAround(t->xy, _current_player, 0x70, 15);
02118 }
02119
02120 static void TownActionAdvertiseLarge(Town* t)
02121 {
02122 ModifyStationRatingAround(t->xy, _current_player, 0xA0, 20);
02123 }
02124
02125 static void TownActionRoadRebuild(Town* t)
02126 {
02127 t->road_build_months = 6;
02128
02129 SetDParam(0, t->index);
02130 SetDParam(1, _current_player);
02131
02132 AddNewsItem(STR_2055_TRAFFIC_CHAOS_IN_ROAD_REBUILDING,
02133 NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_GENERAL, 0), t->xy, 0);
02134 }
02135
02136 static bool DoBuildStatueOfCompany(TileIndex tile, TownID town_id)
02137 {
02138 PlayerID old;
02139 CommandCost r;
02140
02141
02142 if (IsSteepSlope(GetTileSlope(tile, NULL))) return false;
02143
02144 if (!IsTileType(tile, MP_HOUSE) &&
02145 !IsTileType(tile, MP_CLEAR) &&
02146 !IsTileType(tile, MP_TREES)) {
02147 return false;
02148 }
02149
02150 old = _current_player;
02151 _current_player = OWNER_NONE;
02152 r = DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
02153 _current_player = old;
02154
02155 if (CmdFailed(r)) return false;
02156
02157 MakeStatue(tile, _current_player, town_id);
02158 MarkTileDirtyByTile(tile);
02159
02160 return true;
02161 }
02162
02169 static bool SearchTileForStatue(TileIndex tile, uint32 town_id)
02170 {
02171 return DoBuildStatueOfCompany(tile, town_id);
02172 }
02173
02179 static void TownActionBuildStatue(Town* t)
02180 {
02181 TileIndex tile = t->xy;
02182
02183 if (CircularTileSearch(tile, 9, SearchTileForStatue, t->index))
02184 SetBit(t->statues, _current_player);
02185 }
02186
02187 static void TownActionFundBuildings(Town* t)
02188 {
02189
02190 t->grow_counter = 1;
02191
02192 SetBit(t->flags12, TOWN_IS_FUNDED);
02193
02194 t->fund_buildings_months = 3;
02195 }
02196
02197 static void TownActionBuyRights(Town* t)
02198 {
02199
02200 if (!_patches.exclusive_rights) return;
02201
02202 t->exclusive_counter = 12;
02203 t->exclusivity = _current_player;
02204
02205 ModifyStationRatingAround(t->xy, _current_player, 130, 17);
02206 }
02207
02208 static void TownActionBribe(Town* t)
02209 {
02210 if (!RandomRange(15)) {
02211 Station *st;
02212
02213
02214 t->unwanted[_current_player] = 6;
02215
02216
02217 FOR_ALL_STATIONS(st) {
02218 if (st->town == t && st->owner == _current_player) {
02219 for (CargoID i = 0; i < NUM_CARGO; i++) st->goods[i].rating = 0;
02220 }
02221 }
02222
02223
02224
02225 if (IsLocalPlayer()) ShowErrorMessage(STR_BRIBE_FAILED_2, STR_BRIBE_FAILED, 0, 0);
02226
02227
02228
02229
02230
02231 if (t->ratings[_current_player] > RATING_BRIBE_DOWN_TO) {
02232 t->ratings[_current_player] = RATING_BRIBE_DOWN_TO;
02233 }
02234 } else {
02235 ChangeTownRating(t, RATING_BRIBE_UP_STEP, RATING_BRIBE_MAXIMUM);
02236 }
02237 }
02238
02239 typedef void TownActionProc(Town* t);
02240 static TownActionProc * const _town_action_proc[] = {
02241 TownActionAdvertiseSmall,
02242 TownActionAdvertiseMedium,
02243 TownActionAdvertiseLarge,
02244 TownActionRoadRebuild,
02245 TownActionBuildStatue,
02246 TownActionFundBuildings,
02247 TownActionBuyRights,
02248 TownActionBribe
02249 };
02250
02251 extern uint GetMaskOfTownActions(int *nump, PlayerID pid, const Town *t);
02252
02261 CommandCost CmdDoTownAction(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
02262 {
02263 Town *t;
02264
02265 if (!IsValidTownID(p1) || p2 > lengthof(_town_action_proc)) return CMD_ERROR;
02266
02267 t = GetTown(p1);
02268
02269 if (!HasBit(GetMaskOfTownActions(NULL, _current_player, t), p2)) return CMD_ERROR;
02270
02271 CommandCost cost(EXPENSES_OTHER, (_price.build_industry >> 8) * _town_action_costs[p2]);
02272
02273 if (flags & DC_EXEC) {
02274 _town_action_proc[p2](t);
02275 InvalidateWindow(WC_TOWN_AUTHORITY, p1);
02276 }
02277
02278 return cost;
02279 }
02280
02281 static void UpdateTownGrowRate(Town *t)
02282 {
02283 int n;
02284 Station *st;
02285 uint16 m;
02286 Player *p;
02287
02288
02289 FOR_ALL_PLAYERS(p) {
02290 if (p->is_active && t->ratings[p->index] <= 200) {
02291 t->ratings[p->index] += 5;
02292 }
02293 }
02294
02295 n = 0;
02296 FOR_ALL_STATIONS(st) {
02297 if (DistanceSquare(st->xy, t->xy) <= t->radius[0]) {
02298 if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
02299 n++;
02300 if (IsValidPlayer(st->owner)) {
02301 int new_rating = t->ratings[st->owner] + 12;
02302 t->ratings[st->owner] = min(new_rating, INT16_MAX);
02303 }
02304 } else {
02305 if (IsValidPlayer(st->owner)) {
02306 int new_rating = t->ratings[st->owner] - 15;
02307 t->ratings[st->owner] = max(new_rating, INT16_MIN);
02308 }
02309 }
02310 }
02311 }
02312
02313
02314 for (uint i = 0; i < MAX_PLAYERS; i++) {
02315 t->ratings[i] = Clamp(t->ratings[i], -1000, 1000);
02316 }
02317
02318 ClrBit(t->flags12, TOWN_IS_FUNDED);
02319 if (_patches.town_growth_rate == 0 && t->fund_buildings_months == 0) return;
02320
02323 static const uint16 _grow_count_values[2][6] = {
02324 { 120, 120, 120, 100, 80, 60 },
02325 { 320, 420, 300, 220, 160, 100 }
02326 };
02327
02328 if (t->fund_buildings_months != 0) {
02329 m = _grow_count_values[0][min(n, 5)];
02330 t->fund_buildings_months--;
02331 } else {
02332 m = _grow_count_values[1][min(n, 5)];
02333 if (n == 0 && !Chance16(1, 12)) return;
02334 }
02335
02336 if (_opt.landscape == LT_ARCTIC) {
02337 if (TilePixelHeight(t->xy) >= GetSnowLine() && t->act_food == 0 && t->population > 90)
02338 return;
02339 } else if (_opt.landscape == LT_TROPIC) {
02340 if (GetTropicZone(t->xy) == TROPICZONE_DESERT && (t->act_food==0 || t->act_water==0) && t->population > 60)
02341 return;
02342 }
02343
02344
02345
02346 uint growth_multiplier = _patches.town_growth_rate != 0 ? _patches.town_growth_rate - 1 : 1;
02347
02348 m >>= growth_multiplier;
02349 if (t->larger_town) m /= 2;
02350
02351 t->growth_rate = m / (t->num_houses / 50 + 1);
02352 if (m <= t->grow_counter)
02353 t->grow_counter = m;
02354
02355 SetBit(t->flags12, TOWN_IS_FUNDED);
02356 }
02357
02358 static void UpdateTownAmounts(Town *t)
02359 {
02360
02361 t->pct_pass_transported = t->new_act_pass * 256 / (t->new_max_pass + 1);
02362
02363 t->max_pass = t->new_max_pass; t->new_max_pass = 0;
02364 t->act_pass = t->new_act_pass; t->new_act_pass = 0;
02365 t->act_food = t->new_act_food; t->new_act_food = 0;
02366 t->act_water = t->new_act_water; t->new_act_water = 0;
02367
02368
02369 t->pct_mail_transported = t->new_act_mail * 256 / (t->new_max_mail + 1);
02370 t->max_mail = t->new_max_mail; t->new_max_mail = 0;
02371 t->act_mail = t->new_act_mail; t->new_act_mail = 0;
02372
02373 InvalidateWindow(WC_TOWN_VIEW, t->index);
02374 }
02375
02376 static void UpdateTownUnwanted(Town *t)
02377 {
02378 const Player* p;
02379
02380 FOR_ALL_PLAYERS(p) {
02381 if (t->unwanted[p->index] > 0) t->unwanted[p->index]--;
02382 }
02383 }
02384
02385 bool CheckIfAuthorityAllows(TileIndex tile)
02386 {
02387 Town *t;
02388
02389 if (!IsValidPlayer(_current_player)) return true;
02390
02391 t = ClosestTownFromTile(tile, _patches.dist_local_authority);
02392 if (t == NULL) return true;
02393
02394 if (t->ratings[_current_player] > -200) return true;
02395
02396 _error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
02397 SetDParam(0, t->index);
02398
02399 return false;
02400 }
02401
02402
02403 Town* CalcClosestTownFromTile(TileIndex tile, uint threshold)
02404 {
02405 Town *t;
02406 uint dist, best = threshold;
02407 Town *best_town = NULL;
02408
02409 FOR_ALL_TOWNS(t) {
02410 dist = DistanceManhattan(tile, t->xy);
02411 if (dist < best) {
02412 best = dist;
02413 best_town = t;
02414 }
02415 }
02416
02417 return best_town;
02418 }
02419
02420
02421 Town *ClosestTownFromTile(TileIndex tile, uint threshold)
02422 {
02423 if (IsTileType(tile, MP_HOUSE) || (
02424 IsTileType(tile, MP_ROAD) &&
02425 GetRoadOwner(tile, ROADTYPE_ROAD) == OWNER_TOWN
02426 )) {
02427 return GetTownByTile(tile);
02428 } else {
02429 return CalcClosestTownFromTile(tile, threshold);
02430 }
02431 }
02432
02433 static bool _town_rating_test = false;
02434 std::map<const Town *, int> _town_test_ratings;
02435
02436 void SetTownRatingTestMode(bool mode)
02437 {
02438 static int ref_count = 0;
02439 if (mode) {
02440 if (ref_count == 0) {
02441 _town_test_ratings.clear();
02442 }
02443 ref_count++;
02444 } else {
02445 assert(ref_count > 0);
02446 ref_count--;
02447 }
02448 _town_rating_test = !(ref_count == 0);
02449 }
02450
02451 static int GetRating(const Town *t)
02452 {
02453 if (_town_rating_test) {
02454 std::map<const Town *, int>::iterator it = _town_test_ratings.find(t);
02455 if (it != _town_test_ratings.end()) {
02456 return (*it).second;
02457 }
02458 }
02459 return t->ratings[_current_player];
02460 }
02461
02462 void ChangeTownRating(Town *t, int add, int max)
02463 {
02464
02465 if (t == NULL ||
02466 !IsValidPlayer(_current_player) ||
02467 (_cheats.magic_bulldozer.value && add < 0)) {
02468 return;
02469 }
02470
02471 SetBit(t->have_ratings, _current_player);
02472
02473 int rating = GetRating(t);
02474 if (add < 0) {
02475 if (rating > max) {
02476 rating += add;
02477 if (rating < max) rating = max;
02478 }
02479 } else {
02480 if (rating < max) {
02481 rating += add;
02482 if (rating > max) rating = max;
02483 }
02484 }
02485 if (_town_rating_test) {
02486 _town_test_ratings[t] = rating;
02487 } else {
02488 t->ratings[_current_player] = rating;
02489 }
02490 }
02491
02492
02493 static const int _default_rating_settings [3][3] = {
02494
02495 { 0, 128, 384},
02496 { 48, 192, 480},
02497 { 96, 384, 768},
02498 };
02499
02500 bool CheckforTownRating(uint32 flags, Town *t, byte type)
02501 {
02502 int modemod;
02503
02504
02505 if (t == NULL || !IsValidPlayer(_current_player) || _cheats.magic_bulldozer.value)
02506 return true;
02507
02508
02509
02510
02511
02512 modemod = _default_rating_settings[_opt.diff.town_council_tolerance][type];
02513
02514 if (GetRating(t) < 16 + modemod && !(flags & DC_NO_TOWN_RATING)) {
02515 SetDParam(0, t->index);
02516 _error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
02517 return false;
02518 }
02519
02520 return true;
02521 }
02522
02523 void TownsMonthlyLoop()
02524 {
02525 Town *t;
02526
02527 FOR_ALL_TOWNS(t) {
02528 if (t->road_build_months != 0) t->road_build_months--;
02529
02530 if (t->exclusive_counter != 0)
02531 if (--t->exclusive_counter == 0) t->exclusivity = INVALID_PLAYER;
02532
02533 UpdateTownGrowRate(t);
02534 UpdateTownAmounts(t);
02535 UpdateTownUnwanted(t);
02536 }
02537 }
02538
02539 void InitializeTowns()
02540 {
02541 Subsidy *s;
02542
02543
02544 _Town_pool.CleanPool();
02545 _Town_pool.AddBlockToPool();
02546
02547 memset(_subsidies, 0, sizeof(_subsidies));
02548 for (s=_subsidies; s != endof(_subsidies); s++)
02549 s->cargo_type = CT_INVALID;
02550
02551 _cur_town_ctr = 0;
02552 _cur_town_iter = 0;
02553 _total_towns = 0;
02554 _town_sort_dirty = true;
02555 }
02556
02557 static CommandCost TerraformTile_Town(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
02558 {
02559 if (AutoslopeEnabled()) {
02560 HouseID house = GetHouseType(tile);
02561 GetHouseNorthPart(house);
02562 const HouseSpec *hs = GetHouseSpecs(house);
02563
02564
02565 if (((hs->building_flags & TILE_NOT_SLOPED) == 0) && !IsSteepSlope(tileh_new) &&
02566 (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
02567 }
02568
02569 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02570 }
02571
02572 extern const TileTypeProcs _tile_type_town_procs = {
02573 DrawTile_Town,
02574 GetSlopeZ_Town,
02575 ClearTile_Town,
02576 GetAcceptedCargo_Town,
02577 GetTileDesc_Town,
02578 GetTileTrackStatus_Town,
02579 ClickTile_Town,
02580 AnimateTile_Town,
02581 TileLoop_Town,
02582 ChangeTileOwner_Town,
02583 NULL,
02584 NULL,
02585 GetFoundation_Town,
02586 TerraformTile_Town,
02587 };
02588
02589
02591 static const SaveLoad _town_desc[] = {
02592 SLE_CONDVAR(Town, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
02593 SLE_CONDVAR(Town, xy, SLE_UINT32, 6, SL_MAX_VERSION),
02594
02595 SLE_CONDNULL(2, 0, 2),
02596 SLE_CONDNULL(4, 3, 84),
02597 SLE_CONDNULL(2, 0, 91),
02598
02599 SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, 66, SL_MAX_VERSION),
02600 SLE_VAR(Town, townnametype, SLE_UINT16),
02601 SLE_VAR(Town, townnameparts, SLE_UINT32),
02602 SLE_CONDSTR(Town, name, SLE_STR, 0, 84, SL_MAX_VERSION),
02603
02604 SLE_VAR(Town, flags12, SLE_UINT8),
02605 SLE_VAR(Town, statues, SLE_UINT8),
02606
02607 SLE_CONDNULL(1, 0, 1),
02608
02609 SLE_VAR(Town, have_ratings, SLE_UINT8),
02610 SLE_ARR(Town, ratings, SLE_INT16, 8),
02611
02612 SLE_CONDARR(Town, unwanted, SLE_INT8, 8, 4, SL_MAX_VERSION),
02613
02614 SLE_CONDVAR(Town, max_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
02615 SLE_CONDVAR(Town, max_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
02616 SLE_CONDVAR(Town, new_max_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
02617 SLE_CONDVAR(Town, new_max_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
02618 SLE_CONDVAR(Town, act_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
02619 SLE_CONDVAR(Town, act_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
02620 SLE_CONDVAR(Town, new_act_pass, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
02621 SLE_CONDVAR(Town, new_act_mail, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
02622
02623 SLE_CONDVAR(Town, max_pass, SLE_UINT32, 9, SL_MAX_VERSION),
02624 SLE_CONDVAR(Town, max_mail, SLE_UINT32, 9, SL_MAX_VERSION),
02625 SLE_CONDVAR(Town, new_max_pass, SLE_UINT32, 9, SL_MAX_VERSION),
02626 SLE_CONDVAR(Town, new_max_mail, SLE_UINT32, 9, SL_MAX_VERSION),
02627 SLE_CONDVAR(Town, act_pass, SLE_UINT32, 9, SL_MAX_VERSION),
02628 SLE_CONDVAR(Town, act_mail, SLE_UINT32, 9, SL_MAX_VERSION),
02629 SLE_CONDVAR(Town, new_act_pass, SLE_UINT32, 9, SL_MAX_VERSION),
02630 SLE_CONDVAR(Town, new_act_mail, SLE_UINT32, 9, SL_MAX_VERSION),
02631
02632 SLE_VAR(Town, pct_pass_transported, SLE_UINT8),
02633 SLE_VAR(Town, pct_mail_transported, SLE_UINT8),
02634
02635 SLE_VAR(Town, act_food, SLE_UINT16),
02636 SLE_VAR(Town, act_water, SLE_UINT16),
02637 SLE_VAR(Town, new_act_food, SLE_UINT16),
02638 SLE_VAR(Town, new_act_water, SLE_UINT16),
02639
02640 SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT8, 0, 53),
02641 SLE_CONDVAR(Town, grow_counter, SLE_UINT8, 0, 53),
02642 SLE_CONDVAR(Town, growth_rate, SLE_UINT8, 0, 53),
02643
02644 SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT16, 54, SL_MAX_VERSION),
02645 SLE_CONDVAR(Town, grow_counter, SLE_UINT16, 54, SL_MAX_VERSION),
02646 SLE_CONDVAR(Town, growth_rate, SLE_INT16, 54, SL_MAX_VERSION),
02647
02648 SLE_VAR(Town, fund_buildings_months, SLE_UINT8),
02649 SLE_VAR(Town, road_build_months, SLE_UINT8),
02650
02651 SLE_CONDVAR(Town, exclusivity, SLE_UINT8, 2, SL_MAX_VERSION),
02652 SLE_CONDVAR(Town, exclusive_counter, SLE_UINT8, 2, SL_MAX_VERSION),
02653
02654 SLE_CONDVAR(Town, larger_town, SLE_BOOL, 56, SL_MAX_VERSION),
02655
02656
02657 SLE_CONDNULL(30, 2, SL_MAX_VERSION),
02658
02659 SLE_END()
02660 };
02661
02662
02663
02664 static const SaveLoad _house_id_mapping_desc[] = {
02665 SLE_VAR(EntityIDMapping, grfid, SLE_UINT32),
02666 SLE_VAR(EntityIDMapping, entity_id, SLE_UINT8),
02667 SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8),
02668 SLE_END()
02669 };
02670
02671 static void Save_HOUSEIDS()
02672 {
02673 uint j = _house_mngr.GetMaxMapping();
02674
02675 for (uint i = 0; i < j; i++) {
02676 SlSetArrayIndex(i);
02677 SlObject(&_house_mngr.mapping_ID[i], _house_id_mapping_desc);
02678 }
02679 }
02680
02681 static void Load_HOUSEIDS()
02682 {
02683 int index;
02684
02685 _house_mngr.ResetMapping();
02686 uint max_id = _house_mngr.GetMaxMapping();
02687
02688 while ((index = SlIterateArray()) != -1) {
02689 if ((uint)index >= max_id) break;
02690 SlObject(&_house_mngr.mapping_ID[index], _house_id_mapping_desc);
02691 }
02692 }
02693
02694 static void Save_TOWN()
02695 {
02696 Town *t;
02697
02698 FOR_ALL_TOWNS(t) {
02699 SlSetArrayIndex(t->index);
02700 SlObject(t, _town_desc);
02701 }
02702 }
02703
02704 static void Load_TOWN()
02705 {
02706 int index;
02707
02708 _total_towns = 0;
02709
02710 while ((index = SlIterateArray()) != -1) {
02711 Town *t = new (index) Town();
02712 SlObject(t, _town_desc);
02713
02714 _total_towns++;
02715 }
02716
02717
02718
02719 if (_cur_town_ctr > GetMaxTownIndex())
02720 _cur_town_ctr = 0;
02721 }
02722
02723 void AfterLoadTown()
02724 {
02725 _town_sort_dirty = true;
02726 }
02727
02728 extern const ChunkHandler _town_chunk_handlers[] = {
02729 { 'HIDS', Save_HOUSEIDS, Load_HOUSEIDS, CH_ARRAY },
02730 { 'CITY', Save_TOWN, Load_TOWN, CH_ARRAY | CH_LAST},
02731 };
02732
02733 void ResetHouses()
02734 {
02735 memset(&_house_specs, 0, sizeof(_house_specs));
02736 memcpy(&_house_specs, &_original_house_specs, sizeof(_original_house_specs));
02737
02738
02739 _house_mngr.ResetOverride();
02740 }