# unmovable_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: unmovable_cmd.cpp 12199 2008-02-20 17:49:50Z frosch $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "tile_cmd.h"
    00008 #include "landscape.h"
    00009 #include "command_func.h"
    00010 #include "viewport_func.h"
    00011 #include "player_func.h"
    00012 #include "player_base.h"
    00013 #include "gui.h"
    00014 #include "station.h"
    00015 #include "town.h"
    00016 #include "sprite.h"
    00017 #include "bridge_map.h"
    00018 #include "unmovable_map.h"
    00019 #include "variables.h"
    00020 #include "genworld.h"
    00021 #include "bridge.h"
    00022 #include "autoslope.h"
    00023 #include "transparency.h"
    00024 #include "functions.h"
    00025 #include "window_func.h"
    00026 #include "vehicle_func.h"
    00027 #include "player_gui.h"
    00028
    00029 #include "table/strings.h"
    00030 #include "table/sprites.h"
    00031 #include "table/unmovable_land.h"
    00032
    00040 static CommandCost DestroyCompanyHQ(PlayerID pid, uint32 flags)
    00041 {
    00042   Player* p = GetPlayer(pid);
    00043
    00044   if (flags & DC_EXEC) {
    00045     TileIndex t = p->location_of_house;
    00046
    00047     DoClearSquare(t + TileDiffXY(0, 0));
    00048     DoClearSquare(t + TileDiffXY(0, 1));
    00049     DoClearSquare(t + TileDiffXY(1, 0));
    00050     DoClearSquare(t + TileDiffXY(1, 1));
    00051     p->location_of_house = 0; // reset HQ position
    00052     InvalidateWindow(WC_COMPANY, pid);
    00053   }
    00054
    00055   /* cost of relocating company is 1% of company value */
    00056   return CommandCost(EXPENSES_PROPERTY, CalculateCompanyValue(p) / 100);
    00057 }
    00058
    00059 void UpdateCompanyHQ(Player *p, uint score)
    00060 {
    00061   byte val;
    00062   TileIndex tile = p->location_of_house;
    00063
    00064   if (tile == 0) return;
    00065
    00066   (val = 0, score < 170) ||
    00067   (val++, score < 350) ||
    00068   (val++, score < 520) ||
    00069   (val++, score < 720) ||
    00070   (val++, true);
    00071
    00072   EnlargeCompanyHQ(tile, val);
    00073
    00074   MarkTileDirtyByTile(tile + TileDiffXY(0, 0));
    00075   MarkTileDirtyByTile(tile + TileDiffXY(0, 1));
    00076   MarkTileDirtyByTile(tile + TileDiffXY(1, 0));
    00077   MarkTileDirtyByTile(tile + TileDiffXY(1, 1));
    00078 }
    00079
    00080 extern CommandCost CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID *station, bool check_clear = true);
    00081
    00088 CommandCost CmdBuildCompanyHQ(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00089 {
    00090   Player *p = GetPlayer(_current_player);
    00091   CommandCost cost(EXPENSES_PROPERTY);
    00092
    00093   cost = CheckFlatLandBelow(tile, 2, 2, flags, 0, NULL);
    00094   if (CmdFailed(cost)) return cost;
    00095
    00096   if (p->location_of_house != 0) { // Moving HQ
    00097     cost.AddCost(DestroyCompanyHQ(_current_player, flags));
    00098   }
    00099
    00100   if (flags & DC_EXEC) {
    00101     int score = UpdateCompanyRatingAndValue(p, false);
    00102
    00103     p->location_of_house = tile;
    00104
    00105     MakeCompanyHQ(tile, _current_player);
    00106
    00107     UpdateCompanyHQ(p, score);
    00108     InvalidateWindow(WC_COMPANY, p->index);
    00109   }
    00110
    00111   return cost;
    00112 }
    00113
    00122 CommandCost CmdPurchaseLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00123 {
    00124   CommandCost cost(EXPENSES_CONSTRUCTION);
    00125
    00126   if (IsOwnedLandTile(tile) && IsTileOwner(tile, _current_player)) {
    00127     return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
    00128   }
    00129
    00130   cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00131   if (CmdFailed(cost)) return CMD_ERROR;
    00132
    00133   if (flags & DC_EXEC) {
    00134     MakeOwnedLand(tile, _current_player);
    00135     MarkTileDirtyByTile(tile);
    00136   }
    00137
    00138   return cost.AddCost(_price.clear_roughland * 10);
    00139 }
    00140
    00149 CommandCost CmdSellLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00150 {
    00151   if (!IsOwnedLandTile(tile)) return CMD_ERROR;
    00152   if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) return CMD_ERROR;
    00153
    00154
    00155   if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
    00156
    00157   if (flags & DC_EXEC) DoClearSquare(tile);
    00158
    00159   return CommandCost(EXPENSES_CONSTRUCTION,- _price.clear_roughland * 2);
    00160 }
    00161
    00162 static Foundation GetFoundation_Unmovable(TileIndex tile, Slope tileh);
    00163
    00164 static void DrawTile_Unmovable(TileInfo *ti)
    00165 {
    00166
    00167   switch (GetUnmovableType(ti->tile)) {
    00168     case UNMOVABLE_TRANSMITTER:
    00169     case UNMOVABLE_LIGHTHOUSE: {
    00170       const DrawTileSeqStruct* dtu = &_draw_tile_transmitterlighthouse_data[GetUnmovableType(ti->tile)];
    00171
    00172       if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
    00173       DrawClearLandTile(ti, 2);
    00174
    00175       AddSortableSpriteToDraw(
    00176         dtu->image.sprite, PAL_NONE, ti->x | dtu->delta_x, ti->y | dtu->delta_y,
    00177         dtu->size_x, dtu->size_y, dtu->size_z, ti->z,
    00178         IsTransparencySet(TO_STRUCTURES)
    00179       );
    00180       break;
    00181     }
    00182
    00183     case UNMOVABLE_STATUE:
    00184       /* This should prevent statues from sinking into the ground when on a slope. */
    00185       if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, GetFoundation_Unmovable(ti->tile, ti->tileh));
    00186
    00187       DrawGroundSprite(SPR_CONCRETE_GROUND, PAL_NONE);
    00188
    00189       AddSortableSpriteToDraw(SPR_STATUE_COMPANY, PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)), ti->x, ti->y, 16, 16, 25, ti->z, IsTransparencySet(TO_STRUCTURES));
    00190       break;
    00191
    00192     case UNMOVABLE_OWNED_LAND:
    00193       DrawClearLandTile(ti, 0);
    00194
    00195       AddSortableSpriteToDraw(
    00196         SPR_BOUGHT_LAND, PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)),
    00197         ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSlopeZ(ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2)
    00198       );
    00199       DrawBridgeMiddle(ti);
    00200       break;
    00201
    00202     default: {
    00203       const DrawTileSeqStruct* dtss;
    00204       const DrawTileSprites* t;
    00205       SpriteID palette;
    00206
    00207       assert(IsCompanyHQ(ti->tile));
    00208       if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
    00209
    00210       palette = PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile));
    00211
    00212       t = &_unmovable_display_datas[GetCompanyHQSection(ti->tile)];
    00213       DrawGroundSprite(t->ground.sprite, palette);
    00214
    00215       foreach_draw_tile_seq(dtss, t->seq) {
    00216         AddSortableSpriteToDraw(
    00217           dtss->image.sprite, palette,
    00218           ti->x + dtss->delta_x, ti->y + dtss->delta_y,
    00219           dtss->size_x, dtss->size_y,
    00220           dtss->size_z, ti->z + dtss->delta_z,
    00221           IsTransparencySet(TO_STRUCTURES)
    00222         );
    00223       }
    00224       break;
    00225     }
    00226   }
    00227 }
    00228
    00229 static uint GetSlopeZ_Unmovable(TileIndex tile, uint x, uint y)
    00230 {
    00231   if (IsOwnedLand(tile)) {
    00232     uint z;
    00233     Slope tileh = GetTileSlope(tile, &z);
    00234
    00235     return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
    00236   } else {
    00237     return GetTileMaxZ(tile);
    00238   }
    00239 }
    00240
    00241 static Foundation GetFoundation_Unmovable(TileIndex tile, Slope tileh)
    00242 {
    00243   return IsOwnedLand(tile) ? FOUNDATION_NONE : FlatteningFoundation(tileh);
    00244 }
    00245
    00246 static CommandCost ClearTile_Unmovable(TileIndex tile, byte flags)
    00247 {
    00248   if (IsCompanyHQ(tile)) {
    00249     if (_current_player == OWNER_WATER) {
    00250       return DestroyCompanyHQ(GetTileOwner(tile), DC_EXEC);
    00251     } else {
    00252       return_cmd_error(STR_5804_COMPANY_HEADQUARTERS_IN);
    00253     }
    00254   }
    00255
    00256   if (IsOwnedLand(tile)) {
    00257     return DoCommand(tile, 0, 0, flags, CMD_SELL_LAND_AREA);
    00258   }
    00259
    00260   /* checks if you're allowed to remove unmovable things */
    00261   if (_game_mode != GM_EDITOR && _current_player != OWNER_WATER && ((flags & DC_AUTO || !_cheats.magic_bulldozer.value)) )
    00262     return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
    00263
    00264   if (IsStatue(tile)) {
    00265     if (flags & DC_AUTO) return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
    00266
    00267     TownID town = GetStatueTownID(tile);
    00268     ClrBit(GetTown(town)->statues, GetTileOwner(tile));
    00269     InvalidateWindow(WC_TOWN_AUTHORITY, town);
    00270   }
    00271
    00272   if (flags & DC_EXEC) {
    00273     DoClearSquare(tile);
    00274   }
    00275
    00276   return CommandCost();
    00277 }
    00278
    00279 static void GetAcceptedCargo_Unmovable(TileIndex tile, AcceptedCargo ac)
    00280 {
    00281   uint level; // HQ level (depends on company performance) in the range 1..5.
    00282
    00283   if (!IsCompanyHQ(tile)) return;
    00284
    00285   /* HQ accepts passenger and mail; but we have to divide the values
    00286    * between 4 tiles it occupies! */
    00287
    00288   level = GetCompanyHQSize(tile) + 1;
    00289
    00290   /* Top town building generates 10, so to make HQ interesting, the top
    00291    * type makes 20. */
    00292   ac[CT_PASSENGERS] = max(1U, level);
    00293
    00294   /* Top town building generates 4, HQ can make up to 8. The
    00295    * proportion passengers:mail is different because such a huge
    00296    * commercial building generates unusually high amount of mail
    00297    * correspondence per physical visitor. */
    00298   ac[CT_MAIL] = max(1U, level / 2);
    00299 }
    00300
    00301
    00302 static void GetTileDesc_Unmovable(TileIndex tile, TileDesc *td)
    00303 {
    00304   switch (GetUnmovableType(tile)) {
    00305     case UNMOVABLE_TRANSMITTER: td->str = STR_5801_TRANSMITTER; break;
    00306     case UNMOVABLE_LIGHTHOUSE:  td->str = STR_5802_LIGHTHOUSE; break;
    00307     case UNMOVABLE_STATUE:      td->str = STR_2016_STATUE; break;
    00308     case UNMOVABLE_OWNED_LAND:  td->str = STR_5805_COMPANY_OWNED_LAND; break;
    00309     default:                    td->str = STR_5803_COMPANY_HEADQUARTERS; break;
    00310   }
    00311   td->owner = GetTileOwner(tile);
    00312 }
    00313
    00314 static void AnimateTile_Unmovable(TileIndex tile)
    00315 {
    00316   /* not used */
    00317 }
    00318
    00319 static void TileLoop_Unmovable(TileIndex tile)
    00320 {
    00321   uint level; // HQ level (depends on company performance) in the range 1..5.
    00322   uint32 r;
    00323
    00324   if (!IsCompanyHQ(tile)) return;
    00325
    00326   /* HQ accepts passenger and mail; but we have to divide the values
    00327    * between 4 tiles it occupies! */
    00328
    00329   level = GetCompanyHQSize(tile) + 1;
    00330   assert(level < 6);
    00331
    00332   r = Random();
    00333   /* Top town buildings generate 250, so the top HQ type makes 256. */
    00334   if (GB(r, 0, 8) < (256 / 4 / (6 - level))) {
    00335     uint amt = GB(r, 0, 8) / 8 / 4 + 1;
    00336     if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
    00337     MoveGoodsToStation(tile, 2, 2, CT_PASSENGERS, amt);
    00338   }
    00339
    00340   /* Top town building generates 90, HQ can make up to 196. The
    00341    * proportion passengers:mail is about the same as in the acceptance
    00342    * equations. */
    00343   if (GB(r, 8, 8) < (196 / 4 / (6 - level))) {
    00344     uint amt = GB(r, 8, 8) / 8 / 4 + 1;
    00345     if (_economy.fluct <= 0) amt = (amt + 1) >> 1;
    00346     MoveGoodsToStation(tile, 2, 2, CT_MAIL, amt);
    00347   }
    00348 }
    00349
    00350
    00351 static TrackStatus GetTileTrackStatus_Unmovable(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    00352 {
    00353   return 0;
    00354 }
    00355
    00356 static void ClickTile_Unmovable(TileIndex tile)
    00357 {
    00358   if (IsCompanyHQ(tile)) ShowPlayerCompany(GetTileOwner(tile));
    00359 }
    00360
    00361
    00362 /* checks, if a radio tower is within a 9x9 tile square around tile */
    00363 static bool IsRadioTowerNearby(TileIndex tile)
    00364 {
    00365   TileIndex tile_s = tile - TileDiffXY(4, 4);
    00366
    00367   BEGIN_TILE_LOOP(tile, 9, 9, tile_s)
    00368     if (IsTransmitterTile(tile)) return true;
    00369   END_TILE_LOOP(tile, 9, 9, tile_s)
    00370
    00371   return false;
    00372 }
    00373
    00374 void GenerateUnmovables()
    00375 {
    00376   int i, li, j, loop_count;
    00377   TileIndex tile;
    00378   uint h;
    00379   uint maxx;
    00380   uint maxy;
    00381
    00382   if (_opt.landscape == LT_TOYLAND) return;
    00383
    00384   /* add radio tower */
    00385   i = ScaleByMapSize(1000);
    00386   j = ScaleByMapSize(15); // maximum number of radio towers on the map
    00387   li = ScaleByMapSize1D((Random() & 3) + 7);
    00388   SetGeneratingWorldProgress(GWP_UNMOVABLE, j + li);
    00389
    00390   do {
    00391     tile = RandomTile();
    00392     if (IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == SLOPE_FLAT && h >= TILE_HEIGHT * 4 && !IsBridgeAbove(tile)) {
    00393       if (IsRadioTowerNearby(tile)) continue;
    00394       MakeTransmitter(tile);
    00395       IncreaseGeneratingWorldProgress(GWP_UNMOVABLE);
    00396       if (--j == 0) break;
    00397     }
    00398   } while (--i);
    00399
    00400   if (_opt.landscape == LT_TROPIC) return;
    00401
    00402   /* add lighthouses */
    00403   i = li;
    00404   maxx = MapMaxX();
    00405   maxy = MapMaxY();
    00406   loop_count = 0;
    00407   do {
    00408     uint32 r;
    00409     DiagDirection dir;
    00410     int perimeter;
    00411
    00412 restart:
    00413     /* Avoid infinite loops */
    00414     if (++loop_count > 1000) break;
    00415
    00416     r = Random();
    00417
    00418     /* Scatter the lighthouses more evenly around the perimeter */
    00419     perimeter = (GB(r, 16, 16) % (2 * (maxx + maxy))) - maxy;
    00420     for (dir = DIAGDIR_NE; perimeter > 0; dir++) {
    00421       perimeter -= (DiagDirToAxis(dir) == AXIS_X) ? maxx : maxy;
    00422     }
    00423
    00424     switch (dir) {
    00425       default:
    00426       case DIAGDIR_NE: tile = TileXY(maxx,     r % maxy); break;
    00427       case DIAGDIR_SE: tile = TileXY(r % maxx, 0);        break;
    00428       case DIAGDIR_SW: tile = TileXY(0,        r % maxy); break;
    00429       case DIAGDIR_NW: tile = TileXY(r % maxx, maxy);     break;
    00430     }
    00431     j = 20;
    00432     do {
    00433       if (--j == 0) goto restart;
    00434       tile = TILE_MASK(tile + TileOffsByDiagDir(dir));
    00435     } while (!(IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == SLOPE_FLAT && h <= TILE_HEIGHT * 2 && !IsBridgeAbove(tile)));
    00436
    00437     assert(tile == TILE_MASK(tile));
    00438
    00439     MakeLighthouse(tile);
    00440     IncreaseGeneratingWorldProgress(GWP_UNMOVABLE);
    00441   } while (--i);
    00442 }
    00443
    00444 static void ChangeTileOwner_Unmovable(TileIndex tile, PlayerID old_player, PlayerID new_player)
    00445 {
    00446   if (!IsTileOwner(tile, old_player)) return;
    00447
    00448   if (IsOwnedLand(tile) && new_player != PLAYER_SPECTATOR) {
    00449     SetTileOwner(tile, new_player);
    00450   } else if (IsStatueTile(tile)) {
    00451     TownID town = GetStatueTownID(tile);
    00452     Town *t = GetTown(town);
    00453     ClrBit(t->statues, old_player);
    00454     if (new_player != PLAYER_SPECTATOR && !HasBit(t->statues, new_player)) {
    00455       /* Transfer ownership to the new company */
    00456       SetBit(t->statues, new_player);
    00457       SetTileOwner(tile, new_player);
    00458     } else {
    00459       DoClearSquare(tile);
    00460     }
    00461
    00462     InvalidateWindow(WC_TOWN_AUTHORITY, town);
    00463   } else {
    00464     DoClearSquare(tile);
    00465   }
    00466 }
    00467
    00468 static CommandCost TerraformTile_Unmovable(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
    00469 {
    00470   /* Owned land remains unsold */
    00471   if (IsOwnedLand(tile) && CheckTileOwnership(tile)) return CommandCost();
    00472
    00473   if (AutoslopeEnabled() && (IsStatue(tile) || IsCompanyHQ(tile))) {
    00474     if (!IsSteepSlope(tileh_new) && (z_new + GetSlopeMaxZ(tileh_new) == GetTileMaxZ(tile))) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
    00475   }
    00476
    00477   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00478 }
    00479
    00480 extern const TileTypeProcs _tile_type_unmovable_procs = {
    00481   DrawTile_Unmovable,             /* draw_tile_proc */
    00482   GetSlopeZ_Unmovable,            /* get_slope_z_proc */
    00483   ClearTile_Unmovable,            /* clear_tile_proc */
    00484   GetAcceptedCargo_Unmovable,     /* get_accepted_cargo_proc */
    00485   GetTileDesc_Unmovable,          /* get_tile_desc_proc */
    00486   GetTileTrackStatus_Unmovable,   /* get_tile_track_status_proc */
    00487   ClickTile_Unmovable,            /* click_tile_proc */
    00488   AnimateTile_Unmovable,          /* animate_tile_proc */
    00489   TileLoop_Unmovable,             /* tile_loop_clear */
    00490   ChangeTileOwner_Unmovable,      /* change_tile_owner_clear */
    00491   NULL,                           /* get_produced_cargo_proc */
    00492   NULL,                           /* vehicle_enter_tile_proc */
    00493   GetFoundation_Unmovable,        /* get_foundation_proc */
    00494   TerraformTile_Unmovable,        /* terraform_tile_proc */
    00495 };