00001
00002
00005 #include "stdafx.h"
00006
00007 #include "command_func.h"
00008 #include "landscape.h"
00009 #include "rail.h"
00010 #include "bridge_map.h"
00011 #include "station_base.h"
00012 #include "town.h"
00013 #include "waypoint.h"
00014 #include "yapf/yapf.h"
00015 #include "strings_func.h"
00016 #include "gfx_func.h"
00017 #include "functions.h"
00018 #include "window_func.h"
00019 #include "date_func.h"
00020 #include "vehicle_func.h"
00021 #include "string_func.h"
00022 #include "company_func.h"
00023 #include "newgrf_station.h"
00024 #include "oldpool_func.h"
00025 #include "viewport_func.h"
00026 #include "train.h"
00027
00028 #include "table/strings.h"
00029
00030 DEFINE_OLD_POOL_GENERIC(Waypoint, Waypoint)
00031
00032
00033
00036 static void UpdateWaypointSign(Waypoint *wp)
00037 {
00038 Point pt = RemapCoords2(TileX(wp->xy) * TILE_SIZE, TileY(wp->xy) * TILE_SIZE);
00039 SetDParam(0, wp->index);
00040 UpdateViewportSignPos(&wp->sign, pt.x, pt.y - 0x20, STR_WAYPOINT_VIEWPORT);
00041 }
00042
00046 static void RedrawWaypointSign(const Waypoint *wp)
00047 {
00048 MarkAllViewportsDirty(
00049 wp->sign.left - 6,
00050 wp->sign.top,
00051 wp->sign.left + (wp->sign.width_1 << 2) + 12,
00052 wp->sign.top + 48);
00053 }
00054
00058 void UpdateAllWaypointSigns()
00059 {
00060 Waypoint *wp;
00061
00062 FOR_ALL_WAYPOINTS(wp) {
00063 UpdateWaypointSign(wp);
00064 }
00065 }
00066
00071 static void MakeDefaultWaypointName(Waypoint *wp)
00072 {
00073 uint32 used = 0;
00074 uint32 next = 0;
00075 WaypointID idx = 0;
00076
00077 wp->town_index = ClosestTownFromTile(wp->xy, UINT_MAX)->index;
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 WaypointID cid = 0;
00090 do {
00091 Waypoint *lwp = GetWaypoint(cid);
00092
00093
00094 if (lwp->IsValid() && wp != lwp) {
00095
00096 if (lwp->name == NULL && lwp->town_index == wp->town_index) {
00097
00098 uint i = (uint)lwp->town_cn - next;
00099
00100 if (i < 32) {
00101 SetBit(used, i);
00102 if (i == 0) {
00103
00104
00105 do {
00106 used >>= 1;
00107 next++;
00108 } while (HasBit(used, 0));
00109
00110
00111
00112 idx = cid;
00113 }
00114 }
00115 }
00116 }
00117
00118 cid++;
00119 if (cid == GetWaypointPoolSize()) cid = 0;
00120 } while (cid != idx);
00121
00122 wp->town_cn = (uint16)next;
00123 wp->name = NULL;
00124 }
00125
00130 static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile)
00131 {
00132 Waypoint *wp, *best = NULL;
00133 uint thres = 8;
00134
00135 FOR_ALL_WAYPOINTS(wp) {
00136 if (wp->deleted && wp->owner == _current_company) {
00137 uint cur_dist = DistanceManhattan(tile, wp->xy);
00138
00139 if (cur_dist < thres) {
00140 thres = cur_dist;
00141 best = wp;
00142 }
00143 }
00144 }
00145
00146 return best;
00147 }
00148
00159 CommandCost CmdBuildTrainWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00160 {
00161 Waypoint *wp;
00162 Slope tileh;
00163 Axis axis;
00164
00165
00166 if (p1 >= GetNumCustomStations(STAT_CLASS_WAYP)) return CMD_ERROR;
00167
00168 if (!IsTileType(tile, MP_RAILWAY) ||
00169 GetRailTileType(tile) != RAIL_TILE_NORMAL || (
00170 (axis = AXIS_X, GetTrackBits(tile) != TRACK_BIT_X) &&
00171 (axis = AXIS_Y, GetTrackBits(tile) != TRACK_BIT_Y)
00172 )) {
00173 return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK);
00174 }
00175
00176 Owner owner = GetTileOwner(tile);
00177 if (!CheckOwnership(owner)) return CMD_ERROR;
00178 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00179
00180 tileh = GetTileSlope(tile, NULL);
00181 if (tileh != SLOPE_FLAT &&
00182 (!_settings_game.construction.build_on_slopes || IsSteepSlope(tileh) || !(tileh & (0x3 << axis)) || !(tileh & ~(0x3 << axis)))) {
00183 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
00184 }
00185
00186 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00187
00188
00189 wp = FindDeletedWaypointCloseTo(tile);
00190 if (wp == NULL && !Waypoint::CanAllocateItem()) return CMD_ERROR;
00191
00192 if (flags & DC_EXEC) {
00193 if (wp == NULL) {
00194 wp = new Waypoint(tile);
00195
00196 wp->town_index = INVALID_TOWN;
00197 wp->name = NULL;
00198 wp->town_cn = 0;
00199 } else {
00200
00201
00202
00203
00204 Vehicle *v;
00205 FOR_ALL_VEHICLES(v) {
00206 if (v->type == VEH_TRAIN &&
00207 v->First() == v &&
00208 v->current_order.IsType(OT_GOTO_WAYPOINT) &&
00209 v->dest_tile == wp->xy) {
00210 v->dest_tile = tile;
00211 }
00212 }
00213
00214 RedrawWaypointSign(wp);
00215 wp->xy = tile;
00216 InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index);
00217 }
00218 wp->owner = owner;
00219
00220 const StationSpec *statspec;
00221
00222 bool reserved = HasBit(GetTrackReservation(tile), AxisToTrack(axis));
00223 MakeRailWaypoint(tile, owner, axis, GetRailType(tile), wp->index);
00224 SetDepotWaypointReservation(tile, reserved);
00225 MarkTileDirtyByTile(tile);
00226
00227 statspec = GetCustomStationSpec(STAT_CLASS_WAYP, p1);
00228
00229 if (statspec != NULL) {
00230 wp->stat_id = p1;
00231 wp->grfid = statspec->grffile->grfid;
00232 wp->localidx = statspec->localidx;
00233 } else {
00234
00235 wp->stat_id = 0;
00236 wp->grfid = 0;
00237 wp->localidx = 0;
00238 }
00239
00240 wp->deleted = 0;
00241 wp->build_date = _date;
00242
00243 if (wp->town_index == INVALID_TOWN) MakeDefaultWaypointName(wp);
00244
00245 UpdateWaypointSign(wp);
00246 RedrawWaypointSign(wp);
00247 YapfNotifyTrackLayoutChange(tile, AxisToTrack(axis));
00248 }
00249
00250 return CommandCost(EXPENSES_CONSTRUCTION, _price.build_train_depot);
00251 }
00252
00256 void WaypointsDailyLoop()
00257 {
00258 Waypoint *wp;
00259
00260
00261 FOR_ALL_WAYPOINTS(wp) {
00262 if (wp->deleted != 0 && --wp->deleted == 0) delete wp;
00263 }
00264 }
00265
00273 CommandCost RemoveTrainWaypoint(TileIndex tile, DoCommandFlag flags, bool justremove)
00274 {
00275 Waypoint *wp;
00276
00277
00278 if (!IsRailWaypointTile(tile) ||
00279 (!CheckTileOwnership(tile) && _current_company != OWNER_WATER) ||
00280 !EnsureNoVehicleOnGround(tile)) {
00281 return CMD_ERROR;
00282 }
00283
00284 if (flags & DC_EXEC) {
00285 Track track = GetRailWaypointTrack(tile);
00286 wp = GetWaypointByTile(tile);
00287
00288 wp->deleted = 30;
00289 RedrawWaypointSign(wp);
00290
00291 Vehicle *v = NULL;
00292 if (justremove) {
00293 TrackBits tracks = GetRailWaypointBits(tile);
00294 bool reserved = GetDepotWaypointReservation(tile);
00295 MakeRailNormal(tile, wp->owner, tracks, GetRailType(tile));
00296 if (reserved) SetTrackReservation(tile, tracks);
00297 MarkTileDirtyByTile(tile);
00298 } else {
00299 if (GetDepotWaypointReservation(tile)) {
00300 v = GetTrainForReservation(tile, track);
00301 if (v != NULL) FreeTrainTrackReservation(v);
00302 }
00303 DoClearSquare(tile);
00304 AddTrackToSignalBuffer(tile, track, wp->owner);
00305 }
00306 YapfNotifyTrackLayoutChange(tile, track);
00307 if (v != NULL) TryPathReserve(v, true);
00308 }
00309
00310 return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_train_depot);
00311 }
00312
00321 CommandCost CmdRemoveTrainWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00322 {
00323 return RemoveTrainWaypoint(tile, flags, true);
00324 }
00325
00326 static bool IsUniqueWaypointName(const char *name)
00327 {
00328 const Waypoint *wp;
00329
00330 FOR_ALL_WAYPOINTS(wp) {
00331 if (wp->name != NULL && strcmp(wp->name, name) == 0) return false;
00332 }
00333
00334 return true;
00335 }
00336
00345 CommandCost CmdRenameWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00346 {
00347 if (!IsValidWaypointID(p1)) return CMD_ERROR;
00348
00349 Waypoint *wp = GetWaypoint(p1);
00350 if (!CheckOwnership(wp->owner)) return CMD_ERROR;
00351
00352 bool reset = StrEmpty(text);
00353
00354 if (!reset) {
00355 if (strlen(text) >= MAX_LENGTH_WAYPOINT_NAME_BYTES) return CMD_ERROR;
00356 if (!IsUniqueWaypointName(text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
00357 }
00358
00359 if (flags & DC_EXEC) {
00360 free(wp->name);
00361
00362 if (reset) {
00363 MakeDefaultWaypointName(wp);
00364 } else {
00365 wp->name = strdup(text);
00366 }
00367
00368 UpdateWaypointSign(wp);
00369 MarkWholeScreenDirty();
00370 }
00371 return CommandCost();
00372 }
00373
00379 Station *ComposeWaypointStation(TileIndex tile)
00380 {
00381 Waypoint *wp = GetWaypointByTile(tile);
00382
00383
00384
00385 static byte stat_raw[sizeof(Station)];
00386 static Station &stat = *(Station*)stat_raw;
00387
00388 stat.train_tile = stat.xy = wp->xy;
00389 stat.town = GetTown(wp->town_index);
00390 stat.build_date = wp->build_date;
00391
00392 return &stat;
00393 }
00394
00402 void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype)
00403 {
00404 x += 33;
00405 y += 17;
00406
00407 if (!DrawStationTile(x, y, railtype, AXIS_X, STAT_CLASS_WAYP, stat_id)) {
00408 DrawDefaultWaypointSprite(x, y, railtype);
00409 }
00410 }
00411
00412 Waypoint::Waypoint(TileIndex tile)
00413 {
00414 this->xy = tile;
00415 }
00416
00417 Waypoint::~Waypoint()
00418 {
00419 free(this->name);
00420
00421 if (CleaningPool()) return;
00422 DeleteWindowById(WC_WAYPOINT_VIEW, this->index);
00423 RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, this->index);
00424
00425 RedrawWaypointSign(this);
00426 this->xy = INVALID_TILE;
00427 }
00428
00429 void InitializeWaypoints()
00430 {
00431 _Waypoint_pool.CleanPool();
00432 _Waypoint_pool.AddBlockToPool();
00433 }