00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007
00008 #include "command_func.h"
00009 #include "landscape.h"
00010 #include "order.h"
00011 #include "rail_map.h"
00012 #include "rail.h"
00013 #include "bridge_map.h"
00014 #include "saveload.h"
00015 #include "station.h"
00016 #include "town.h"
00017 #include "waypoint.h"
00018 #include "variables.h"
00019 #include "yapf/yapf.h"
00020 #include "newgrf.h"
00021 #include "strings_func.h"
00022 #include "gfx_func.h"
00023 #include "functions.h"
00024 #include "window_func.h"
00025 #include "economy_func.h"
00026 #include "date_func.h"
00027 #include "vehicle_func.h"
00028 #include "vehicle_base.h"
00029 #include "string_func.h"
00030 #include "signal_func.h"
00031 #include "player_func.h"
00032 #include "settings_type.h"
00033
00034 #include "table/strings.h"
00035
00036 DEFINE_OLD_POOL_GENERIC(Waypoint, Waypoint)
00037
00038
00039
00042 static void UpdateWaypointSign(Waypoint* wp)
00043 {
00044 Point pt = RemapCoords2(TileX(wp->xy) * TILE_SIZE, TileY(wp->xy) * TILE_SIZE);
00045 SetDParam(0, wp->index);
00046 UpdateViewportSignPos(&wp->sign, pt.x, pt.y - 0x20, STR_WAYPOINT_VIEWPORT);
00047 }
00048
00052 static void RedrawWaypointSign(const Waypoint* wp)
00053 {
00054 MarkAllViewportsDirty(
00055 wp->sign.left - 6,
00056 wp->sign.top,
00057 wp->sign.left + (wp->sign.width_1 << 2) + 12,
00058 wp->sign.top + 48);
00059 }
00060
00064 void UpdateAllWaypointSigns()
00065 {
00066 Waypoint *wp;
00067
00068 FOR_ALL_WAYPOINTS(wp) {
00069 UpdateWaypointSign(wp);
00070 }
00071 }
00072
00077 static void MakeDefaultWaypointName(Waypoint* wp)
00078 {
00079 uint32 used = 0;
00080 uint32 next = 0;
00081 WaypointID idx = 0;
00082
00083 wp->town_index = ClosestTownFromTile(wp->xy, (uint)-1)->index;
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 WaypointID cid = 0;
00096 do {
00097 Waypoint *lwp = GetWaypoint(cid);
00098
00099
00100 if (lwp->IsValid() && wp != lwp) {
00101
00102 if (lwp->name == NULL && lwp->town_index == wp->town_index) {
00103
00104 uint i = (uint)lwp->town_cn - next;
00105
00106 if (i < 32) {
00107 SetBit(used, i);
00108 if (i == 0) {
00109
00110
00111 do {
00112 used >>= 1;
00113 next++;
00114 } while (HasBit(used, 0));
00115
00116
00117
00118 idx = cid;
00119 }
00120 }
00121 }
00122 }
00123
00124 cid++;
00125 if (cid == GetWaypointPoolSize()) cid = 0;
00126 } while (cid != idx);
00127
00128 wp->town_cn = (uint16)next;
00129 wp->name = NULL;
00130 }
00131
00136 static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile)
00137 {
00138 Waypoint *wp, *best = NULL;
00139 uint thres = 8;
00140
00141 FOR_ALL_WAYPOINTS(wp) {
00142 if (wp->deleted) {
00143 uint cur_dist = DistanceManhattan(tile, wp->xy);
00144
00145 if (cur_dist < thres) {
00146 thres = cur_dist;
00147 best = wp;
00148 }
00149 }
00150 }
00151
00152 return best;
00153 }
00154
00159 void AfterLoadWaypoints()
00160 {
00161 Waypoint *wp;
00162
00163 FOR_ALL_WAYPOINTS(wp) {
00164 uint i;
00165
00166 if (wp->grfid == 0) continue;
00167
00168 for (i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) {
00169 const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i);
00170 if (statspec != NULL && statspec->grffile->grfid == wp->grfid && statspec->localidx == wp->localidx) {
00171 wp->stat_id = i;
00172 break;
00173 }
00174 }
00175 }
00176 }
00177
00188 CommandCost CmdBuildTrainWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00189 {
00190 Waypoint *wp;
00191 Slope tileh;
00192 Axis axis;
00193
00194
00195 if (p1 >= GetNumCustomStations(STAT_CLASS_WAYP)) return CMD_ERROR;
00196
00197 if (!IsTileType(tile, MP_RAILWAY) ||
00198 GetRailTileType(tile) != RAIL_TILE_NORMAL || (
00199 (axis = AXIS_X, GetTrackBits(tile) != TRACK_BIT_X) &&
00200 (axis = AXIS_Y, GetTrackBits(tile) != TRACK_BIT_Y)
00201 )) {
00202 return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK);
00203 }
00204
00205 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00206 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00207
00208 tileh = GetTileSlope(tile, NULL);
00209 if (tileh != SLOPE_FLAT &&
00210 (!_patches.build_on_slopes || IsSteepSlope(tileh) || !(tileh & (0x3 << axis)) || !(tileh & ~(0x3 << axis)))) {
00211 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
00212 }
00213
00214 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00215
00216
00217 wp = FindDeletedWaypointCloseTo(tile);
00218 if (wp == NULL && !Waypoint::CanAllocateItem()) return CMD_ERROR;
00219
00220 if (flags & DC_EXEC) {
00221 if (wp == NULL) {
00222 wp = new Waypoint(tile);
00223
00224 wp->town_index = INVALID_TOWN;
00225 wp->name = NULL;
00226 wp->town_cn = 0;
00227 } else {
00228
00229
00230
00231
00232 Vehicle *v;
00233 FOR_ALL_VEHICLES(v) {
00234 if (v->type == VEH_TRAIN &&
00235 v->First() == v &&
00236 v->current_order.type == OT_GOTO_WAYPOINT &&
00237 v->dest_tile == wp->xy) {
00238 v->dest_tile = tile;
00239 }
00240 }
00241
00242 RedrawWaypointSign(wp);
00243 wp->xy = tile;
00244 }
00245
00246 const StationSpec* statspec;
00247
00248 MakeRailWaypoint(tile, GetTileOwner(tile), axis, GetRailType(tile), wp->index);
00249 MarkTileDirtyByTile(tile);
00250
00251 statspec = GetCustomStationSpec(STAT_CLASS_WAYP, p1);
00252
00253 if (statspec != NULL) {
00254 wp->stat_id = p1;
00255 wp->grfid = statspec->grffile->grfid;
00256 wp->localidx = statspec->localidx;
00257 } else {
00258
00259 wp->stat_id = 0;
00260 wp->grfid = 0;
00261 wp->localidx = 0;
00262 }
00263
00264 wp->deleted = 0;
00265 wp->build_date = _date;
00266
00267 if (wp->town_index == INVALID_TOWN) MakeDefaultWaypointName(wp);
00268
00269 UpdateWaypointSign(wp);
00270 RedrawWaypointSign(wp);
00271 YapfNotifyTrackLayoutChange(tile, AxisToTrack(axis));
00272 }
00273
00274 return CommandCost(EXPENSES_CONSTRUCTION, _price.build_train_depot);
00275 }
00276
00280 void WaypointsDailyLoop()
00281 {
00282 Waypoint *wp;
00283
00284
00285 FOR_ALL_WAYPOINTS(wp) {
00286 if (wp->deleted != 0 && --wp->deleted == 0) delete wp;
00287 }
00288 }
00289
00297 CommandCost RemoveTrainWaypoint(TileIndex tile, uint32 flags, bool justremove)
00298 {
00299 Waypoint *wp;
00300
00301
00302 if (!IsTileType(tile, MP_RAILWAY) ||
00303 !IsRailWaypoint(tile) ||
00304 (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) ||
00305 !EnsureNoVehicleOnGround(tile)) {
00306 return CMD_ERROR;
00307 }
00308
00309 if (flags & DC_EXEC) {
00310 Track track = GetRailWaypointTrack(tile);
00311 Owner owner = GetTileOwner(tile);
00312 wp = GetWaypointByTile(tile);
00313
00314 wp->deleted = 30;
00315 RedrawWaypointSign(wp);
00316
00317 if (justremove) {
00318 MakeRailNormal(tile, GetTileOwner(tile), GetRailWaypointBits(tile), GetRailType(tile));
00319 MarkTileDirtyByTile(tile);
00320 } else {
00321 DoClearSquare(tile);
00322 AddTrackToSignalBuffer(tile, track, owner);
00323 }
00324 YapfNotifyTrackLayoutChange(tile, track);
00325 }
00326
00327 return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_train_depot);
00328 }
00329
00338 CommandCost CmdRemoveTrainWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00339 {
00340 return RemoveTrainWaypoint(tile, flags, true);
00341 }
00342
00343 static bool IsUniqueWaypointName(const char *name)
00344 {
00345 const Waypoint *wp;
00346 char buf[512];
00347
00348 FOR_ALL_WAYPOINTS(wp) {
00349 SetDParam(0, wp->index);
00350 GetString(buf, STR_WAYPOINT_RAW, lastof(buf));
00351 if (strcmp(buf, name) == 0) return false;
00352 }
00353
00354 return true;
00355 }
00356
00365 CommandCost CmdRenameWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00366 {
00367 Waypoint *wp;
00368
00369 if (!IsValidWaypointID(p1)) return CMD_ERROR;
00370
00371 wp = GetWaypoint(p1);
00372 if (!IsTileType(wp->xy, MP_RAILWAY) || !CheckTileOwnership(wp->xy)) return CMD_ERROR;
00373
00374 if (!StrEmpty(_cmd_text)) {
00375 if (!IsUniqueWaypointName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
00376
00377 if (flags & DC_EXEC) {
00378 free(wp->name);
00379 wp->name = strdup(_cmd_text);
00380 wp->town_cn = 0;
00381
00382 UpdateWaypointSign(wp);
00383 MarkWholeScreenDirty();
00384 }
00385 } else {
00386 if (flags & DC_EXEC) {
00387 free(wp->name);
00388
00389 MakeDefaultWaypointName(wp);
00390 UpdateWaypointSign(wp);
00391 MarkWholeScreenDirty();
00392 }
00393 }
00394 return CommandCost();
00395 }
00396
00402 Station *ComposeWaypointStation(TileIndex tile)
00403 {
00404 Waypoint *wp = GetWaypointByTile(tile);
00405
00406
00407
00408 static byte stat_raw[sizeof(Station)];
00409 static Station &stat = *(Station*)stat_raw;
00410
00411 stat.train_tile = stat.xy = wp->xy;
00412 stat.town = GetTown(wp->town_index);
00413 stat.build_date = wp->build_date;
00414
00415 return &stat;
00416 }
00417
00425 void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype)
00426 {
00427 x += 33;
00428 y += 17;
00429
00430 if (!DrawStationTile(x, y, railtype, AXIS_X, STAT_CLASS_WAYP, stat_id)) {
00431 DrawDefaultWaypointSprite(x, y, railtype);
00432 }
00433 }
00434
00435 Waypoint::Waypoint(TileIndex tile)
00436 {
00437 this->xy = tile;
00438 }
00439
00440 Waypoint::~Waypoint()
00441 {
00442 free(this->name);
00443
00444 if (CleaningPool()) return;
00445
00446 RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, this->index);
00447
00448 RedrawWaypointSign(this);
00449 this->xy = 0;
00450 }
00451
00455 void FixOldWaypoints()
00456 {
00457 Waypoint *wp;
00458
00459
00460 FOR_ALL_WAYPOINTS(wp) {
00461 wp->town_index = ClosestTownFromTile(wp->xy, (uint)-1)->index;
00462 wp->town_cn = 0;
00463 if (wp->string & 0xC000) {
00464 wp->town_cn = wp->string & 0x3F;
00465 wp->string = STR_NULL;
00466 }
00467 }
00468 }
00469
00470 void InitializeWaypoints()
00471 {
00472 _Waypoint_pool.CleanPool();
00473 _Waypoint_pool.AddBlockToPool();
00474 }
00475
00476 static const SaveLoad _waypoint_desc[] = {
00477 SLE_CONDVAR(Waypoint, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
00478 SLE_CONDVAR(Waypoint, xy, SLE_UINT32, 6, SL_MAX_VERSION),
00479 SLE_CONDVAR(Waypoint, town_index, SLE_UINT16, 12, SL_MAX_VERSION),
00480 SLE_CONDVAR(Waypoint, town_cn, SLE_FILE_U8 | SLE_VAR_U16, 12, 88),
00481 SLE_CONDVAR(Waypoint, town_cn, SLE_UINT16, 89, SL_MAX_VERSION),
00482 SLE_CONDVAR(Waypoint, string, SLE_STRINGID, 0, 83),
00483 SLE_CONDSTR(Waypoint, name, SLE_STR, 0, 84, SL_MAX_VERSION),
00484 SLE_VAR(Waypoint, deleted, SLE_UINT8),
00485
00486 SLE_CONDVAR(Waypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32, 3, 30),
00487 SLE_CONDVAR(Waypoint, build_date, SLE_INT32, 31, SL_MAX_VERSION),
00488 SLE_CONDVAR(Waypoint, localidx, SLE_UINT8, 3, SL_MAX_VERSION),
00489 SLE_CONDVAR(Waypoint, grfid, SLE_UINT32, 17, SL_MAX_VERSION),
00490
00491 SLE_END()
00492 };
00493
00494 static void Save_WAYP()
00495 {
00496 Waypoint *wp;
00497
00498 FOR_ALL_WAYPOINTS(wp) {
00499 SlSetArrayIndex(wp->index);
00500 SlObject(wp, _waypoint_desc);
00501 }
00502 }
00503
00504 static void Load_WAYP()
00505 {
00506 int index;
00507
00508 while ((index = SlIterateArray()) != -1) {
00509 Waypoint *wp = new (index) Waypoint();
00510 SlObject(wp, _waypoint_desc);
00511 }
00512 }
00513
00514 extern const ChunkHandler _waypoint_chunk_handlers[] = {
00515 { 'CHKP', Save_WAYP, Load_WAYP, CH_ARRAY | CH_LAST},
00516 };