00001
00002
00005 #include "stdafx.h"
00006
00007 #include "command_func.h"
00008 #include "landscape.h"
00009 #include "economy_func.h"
00010 #include "bridge_map.h"
00011 #include "town.h"
00012 #include "waypoint.h"
00013 #include "yapf/yapf.h"
00014 #include "strings_func.h"
00015 #include "gfx_func.h"
00016 #include "functions.h"
00017 #include "window_func.h"
00018 #include "date_func.h"
00019 #include "vehicle_func.h"
00020 #include "string_func.h"
00021 #include "company_func.h"
00022 #include "newgrf_station.h"
00023 #include "viewport_func.h"
00024 #include "train.h"
00025
00026 #include "table/strings.h"
00027
00031 void UpdateWaypointSign(Waypoint *wp)
00032 {
00033 Point pt = RemapCoords2(TileX(wp->xy) * TILE_SIZE, TileY(wp->xy) * TILE_SIZE);
00034 SetDParam(0, wp->index);
00035 UpdateViewportSignPos(&wp->sign, pt.x, pt.y - 0x20, STR_WAYPOINT_VIEWPORT);
00036 }
00037
00041 void RedrawWaypointSign(const Waypoint *wp)
00042 {
00043 MarkAllViewportsDirty(
00044 wp->sign.left - 6,
00045 wp->sign.top,
00046 wp->sign.left + (wp->sign.width_1 << 2) + 12,
00047 wp->sign.top + 48);
00048 }
00049
00054 static void MakeDefaultWaypointName(Waypoint *wp)
00055 {
00056 uint32 used = 0;
00057 uint32 next = 0;
00058 WaypointID idx = 0;
00059
00060 wp->town_index = ClosestTownFromTile(wp->xy, UINT_MAX)->index;
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 WaypointID cid = 0;
00073 do {
00074 Waypoint *lwp = GetWaypoint(cid);
00075
00076
00077 if (lwp->IsValid() && wp != lwp) {
00078
00079 if (lwp->name == NULL && lwp->town_index == wp->town_index) {
00080
00081 uint i = (uint)lwp->town_cn - next;
00082
00083 if (i < 32) {
00084 SetBit(used, i);
00085 if (i == 0) {
00086
00087
00088 do {
00089 used >>= 1;
00090 next++;
00091 } while (HasBit(used, 0));
00092
00093
00094
00095 idx = cid;
00096 }
00097 }
00098 }
00099 }
00100
00101 cid++;
00102 if (cid == GetWaypointPoolSize()) cid = 0;
00103 } while (cid != idx);
00104
00105 wp->town_cn = (uint16)next;
00106 wp->name = NULL;
00107 }
00108
00113 static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile)
00114 {
00115 Waypoint *wp, *best = NULL;
00116 uint thres = 8;
00117
00118 FOR_ALL_WAYPOINTS(wp) {
00119 if (wp->deleted && wp->owner == _current_company) {
00120 uint cur_dist = DistanceManhattan(tile, wp->xy);
00121
00122 if (cur_dist < thres) {
00123 thres = cur_dist;
00124 best = wp;
00125 }
00126 }
00127 }
00128
00129 return best;
00130 }
00131
00142 CommandCost CmdBuildTrainWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00143 {
00144 Waypoint *wp;
00145 Slope tileh;
00146 Axis axis;
00147
00148
00149 if (p1 >= GetNumCustomStations(STAT_CLASS_WAYP)) return CMD_ERROR;
00150
00151 if (!IsTileType(tile, MP_RAILWAY) ||
00152 GetRailTileType(tile) != RAIL_TILE_NORMAL || (
00153 (axis = AXIS_X, GetTrackBits(tile) != TRACK_BIT_X) &&
00154 (axis = AXIS_Y, GetTrackBits(tile) != TRACK_BIT_Y)
00155 )) {
00156 return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK);
00157 }
00158
00159 Owner owner = GetTileOwner(tile);
00160 if (!CheckOwnership(owner)) return CMD_ERROR;
00161 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00162
00163 tileh = GetTileSlope(tile, NULL);
00164 if (tileh != SLOPE_FLAT &&
00165 (!_settings_game.construction.build_on_slopes || IsSteepSlope(tileh) || !(tileh & (0x3 << axis)) || !(tileh & ~(0x3 << axis)))) {
00166 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
00167 }
00168
00169 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00170
00171
00172 wp = FindDeletedWaypointCloseTo(tile);
00173 if (wp == NULL && !Waypoint::CanAllocateItem()) return CMD_ERROR;
00174
00175 if (flags & DC_EXEC) {
00176 if (wp == NULL) {
00177 wp = new Waypoint(tile);
00178
00179 wp->town_index = INVALID_TOWN;
00180 wp->name = NULL;
00181 wp->town_cn = 0;
00182 } else {
00183
00184
00185
00186
00187 Vehicle *v;
00188 FOR_ALL_VEHICLES(v) {
00189 if (v->type == VEH_TRAIN &&
00190 v->First() == v &&
00191 v->current_order.IsType(OT_GOTO_WAYPOINT) &&
00192 v->dest_tile == wp->xy) {
00193 v->dest_tile = tile;
00194 }
00195 }
00196
00197 RedrawWaypointSign(wp);
00198 wp->xy = tile;
00199 InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index);
00200 }
00201 wp->owner = owner;
00202
00203 const StationSpec *statspec;
00204
00205 bool reserved = HasBit(GetTrackReservation(tile), AxisToTrack(axis));
00206 MakeRailWaypoint(tile, owner, axis, GetRailType(tile), wp->index);
00207 SetDepotWaypointReservation(tile, reserved);
00208 MarkTileDirtyByTile(tile);
00209
00210 statspec = GetCustomStationSpec(STAT_CLASS_WAYP, p1);
00211
00212 if (statspec != NULL) {
00213 wp->stat_id = p1;
00214 wp->grfid = statspec->grffile->grfid;
00215 wp->localidx = statspec->localidx;
00216 } else {
00217
00218 wp->stat_id = 0;
00219 wp->grfid = 0;
00220 wp->localidx = 0;
00221 }
00222
00223 wp->deleted = 0;
00224 wp->build_date = _date;
00225
00226 if (wp->town_index == INVALID_TOWN) MakeDefaultWaypointName(wp);
00227
00228 UpdateWaypointSign(wp);
00229 RedrawWaypointSign(wp);
00230 YapfNotifyTrackLayoutChange(tile, AxisToTrack(axis));
00231 }
00232
00233 return CommandCost(EXPENSES_CONSTRUCTION, _price.build_train_depot);
00234 }
00235
00243 CommandCost RemoveTrainWaypoint(TileIndex tile, DoCommandFlag flags, bool justremove)
00244 {
00245 Waypoint *wp;
00246
00247
00248 if (!IsRailWaypointTile(tile) ||
00249 (!CheckTileOwnership(tile) && _current_company != OWNER_WATER) ||
00250 !EnsureNoVehicleOnGround(tile)) {
00251 return CMD_ERROR;
00252 }
00253
00254 if (flags & DC_EXEC) {
00255 Track track = GetRailWaypointTrack(tile);
00256 wp = GetWaypointByTile(tile);
00257
00258 wp->deleted = 30;
00259 RedrawWaypointSign(wp);
00260
00261 Vehicle *v = NULL;
00262 if (justremove) {
00263 TrackBits tracks = GetRailWaypointBits(tile);
00264 bool reserved = GetDepotWaypointReservation(tile);
00265 MakeRailNormal(tile, wp->owner, tracks, GetRailType(tile));
00266 if (reserved) SetTrackReservation(tile, tracks);
00267 MarkTileDirtyByTile(tile);
00268 } else {
00269 if (GetDepotWaypointReservation(tile)) {
00270 v = GetTrainForReservation(tile, track);
00271 if (v != NULL) FreeTrainTrackReservation(v);
00272 }
00273 DoClearSquare(tile);
00274 AddTrackToSignalBuffer(tile, track, wp->owner);
00275 }
00276 YapfNotifyTrackLayoutChange(tile, track);
00277 if (v != NULL) TryPathReserve(v, true);
00278 }
00279
00280 return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_train_depot);
00281 }
00282
00291 CommandCost CmdRemoveTrainWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00292 {
00293 return RemoveTrainWaypoint(tile, flags, true);
00294 }
00295
00296 static bool IsUniqueWaypointName(const char *name)
00297 {
00298 const Waypoint *wp;
00299
00300 FOR_ALL_WAYPOINTS(wp) {
00301 if (wp->name != NULL && strcmp(wp->name, name) == 0) return false;
00302 }
00303
00304 return true;
00305 }
00306
00315 CommandCost CmdRenameWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00316 {
00317 if (!IsValidWaypointID(p1)) return CMD_ERROR;
00318
00319 Waypoint *wp = GetWaypoint(p1);
00320 if (!CheckOwnership(wp->owner)) return CMD_ERROR;
00321
00322 bool reset = StrEmpty(text);
00323
00324 if (!reset) {
00325 if (strlen(text) >= MAX_LENGTH_WAYPOINT_NAME_BYTES) return CMD_ERROR;
00326 if (!IsUniqueWaypointName(text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
00327 }
00328
00329 if (flags & DC_EXEC) {
00330 free(wp->name);
00331
00332 if (reset) {
00333 MakeDefaultWaypointName(wp);
00334 } else {
00335 wp->name = strdup(text);
00336 }
00337
00338 UpdateWaypointSign(wp);
00339 MarkWholeScreenDirty();
00340 }
00341 return CommandCost();
00342 }