--- a/src/vehicle.cpp Mon Dec 03 23:39:38 2007 +0000
+++ b/src/vehicle.cpp Tue Jan 22 21:00:30 2008 +0000
@@ -8,27 +8,21 @@
#include "roadveh.h"
#include "ship.h"
#include "spritecache.h"
-#include "table/sprites.h"
-#include "table/strings.h"
-#include "functions.h"
+#include "tile_cmd.h"
#include "landscape.h"
-#include "map.h"
-#include "tile.h"
-#include "vehicle.h"
#include "timetable.h"
-#include "gfx.h"
-#include "viewport.h"
+#include "viewport_func.h"
+#include "gfx_func.h"
#include "news.h"
-#include "command.h"
+#include "command_func.h"
#include "saveload.h"
-#include "player.h"
+#include "player_func.h"
#include "engine.h"
-#include "sound.h"
#include "debug.h"
#include "vehicle_gui.h"
#include "depot.h"
#include "station.h"
-#include "rail.h"
+#include "rail_type.h"
#include "train.h"
#include "aircraft.h"
#include "industry_map.h"
@@ -36,18 +30,36 @@
#include "water_map.h"
#include "network/network.h"
#include "yapf/yapf.h"
-#include "date.h"
#include "newgrf_callbacks.h"
#include "newgrf_engine.h"
#include "newgrf_sound.h"
-#include "helpers.hpp"
#include "group.h"
-#include "economy.h"
-#include "strings.h"
+#include "order.h"
+#include "strings_func.h"
+#include "zoom_func.h"
+#include "functions.h"
+#include "date_func.h"
+#include "window_func.h"
+#include "vehicle_func.h"
+#include "signal_func.h"
+#include "sound_func.h"
+#include "variables.h"
+#include "autoreplace_func.h"
+#include "autoreplace_gui.h"
+#include "string_func.h"
+#include "settings_type.h"
+
+#include "table/sprites.h"
+#include "table/strings.h"
#define INVALID_COORD (0x7fffffff)
#define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
+VehicleID _vehicle_id_ctr_day;
+Vehicle *_place_clicked_vehicle;
+VehicleID _new_vehicle_id;
+uint16 _returned_refit_capacity;
+
/* Tables used in vehicle.h to find the right command for a certain vehicle type */
const uint32 _veh_build_proc_table[] = {
@@ -92,10 +104,10 @@
bool VehicleNeedsService(const Vehicle *v)
{
if (v->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
- if (v->current_order.type != OT_GOTO_DEPOT || !(v->current_order.flags & OF_PART_OF_ORDERS)) { // Don't interfere with a depot visit by the order list
+ if (v->current_order.type != OT_GOTO_DEPOT || !(v->current_order.flags & OFB_PART_OF_ORDERS)) { // Don't interfere with a depot visit by the order list
if (_patches.gotodepot && VehicleHasDepotOrders(v)) return false;
if (v->current_order.type == OT_LOADING) return false;
- if (v->current_order.type == OT_GOTO_DEPOT && v->current_order.flags & OF_HALT_IN_DEPOT) return false;
+ if (v->current_order.type == OT_GOTO_DEPOT && v->current_order.flags & OFB_HALT_IN_DEPOT) return false;
}
if (_patches.no_servicing_if_no_breakdowns && _opt.diff.vehicle_breakdowns == 0) {
@@ -119,33 +131,23 @@
static void *EnsureNoVehicleProcZ(Vehicle *v, void *data)
{
- const TileInfo *ti = (const TileInfo*)data;
-
- if (v->tile != ti->tile || v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
- if (v->z_pos > ti->z) return NULL;
+ byte z = *(byte*)data;
+
+ if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
+ if (v->z_pos > z) return NULL;
_error_message = VehicleInTheWayErrMsg(v);
return v;
}
+Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z)
+{
+ return (Vehicle*)VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ);
+}
bool EnsureNoVehicleOnGround(TileIndex tile)
{
- TileInfo ti;
-
- ti.tile = tile;
- ti.z = GetTileMaxZ(tile);
- return VehicleFromPos(tile, &ti, EnsureNoVehicleProcZ) == NULL;
-}
-
-Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z)
-{
- TileInfo ti;
-
- ti.tile = tile;
- ti.z = z;
-
- return (Vehicle*)VehicleFromPos(tile, &ti, EnsureNoVehicleProcZ);
+ return FindVehicleOnTileZ(tile, GetTileMaxZ(tile)) == NULL;
}
Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z, bool without_crashed)
@@ -174,6 +176,30 @@
}
+/** Procedure called for every vehicle found in tunnel/bridge in the hash map */
+static void *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
+{
+ if (v->type != VEH_TRAIN && v->type != VEH_ROAD) return NULL;
+
+ _error_message = VehicleInTheWayErrMsg(v);
+ return v;
+}
+
+/**
+ * Finds vehicle in tunnel / bridge
+ * @param tile first end
+ * @param endtile second end
+ * @return pointer to vehicle found
+ */
+Vehicle *GetVehicleTunnelBridge(TileIndex tile, TileIndex endtile)
+{
+ Vehicle *v = (Vehicle*)VehicleFromPos(tile, NULL, &GetVehicleTunnelBridgeProc);
+ if (v != NULL) return v;
+
+ return (Vehicle*)VehicleFromPos(endtile, NULL, &GetVehicleTunnelBridgeProc);
+}
+
+
static void UpdateVehiclePosHash(Vehicle* v, int x, int y);
void VehiclePositionChanged(Vehicle *v)
@@ -194,7 +220,7 @@
}
/** Called after load to update coordinates */
-void AfterLoadVehicles()
+void AfterLoadVehicles(bool clear_te_id)
{
Vehicle *v;
@@ -204,7 +230,7 @@
v->UpdateDeltaXY(v->direction);
- v->fill_percent_te_id = INVALID_TE_ID;
+ if (clear_te_id) v->fill_percent_te_id = INVALID_TE_ID;
v->first = NULL;
if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
if (v->type == VEH_ROAD) v->u.road.first_engine = INVALID_ENGINE;
@@ -537,16 +563,16 @@
delete this->Next();
}
- Window *w = FindWindowById(WC_VEHICLE_VIEW, this->index);
- if (w != NULL && WP(w, vp_d).follow_vehicle == this->index) {
- ScrollMainWindowTo(this->x_pos, this->y_pos); // lock the main view on the vehicle's last position
+ Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+ if (WP(w, vp_d).follow_vehicle == this->index) {
+ ScrollMainWindowTo(this->x_pos, this->y_pos, true); // lock the main view on the vehicle's last position
WP(w, vp_d).follow_vehicle = INVALID_VEHICLE;
}
}
Vehicle::~Vehicle()
{
- DeleteName(this->string_id);
+ free(this->name);
if (CleaningPool()) return;
@@ -570,6 +596,9 @@
do {
Vehicle *u = v;
+ /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
+ * it may happen that vehicle chain is deleted when visible */
+ if (!(v->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(v);
v = v->Next();
delete u;
} while (v != NULL);
@@ -584,7 +613,7 @@
void VehicleEnteredDepotThisTick(Vehicle *v)
{
/* we need to set v->leave_depot_instantly as we have no control of it's contents at this time */
- if (HasBit(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HasBit(v->current_order.flags, OFB_PART_OF_ORDERS) && v->current_order.type == OT_GOTO_DEPOT) {
+ if (HasBit(v->current_order.flags, OF_HALT_IN_DEPOT) && !HasBit(v->current_order.flags, OF_PART_OF_ORDERS) && v->current_order.type == OT_GOTO_DEPOT) {
/* we keep the vehicle in the depot since the user ordered it to stay */
v->leave_depot_instantly = false;
} else {
@@ -678,19 +707,33 @@
*/
CommandCost GetRefitCost(EngineID engine_type)
{
- CommandCost base_cost;
-
+ Money base_cost;
+ ExpensesType expense_type;
switch (GetEngine(engine_type)->type) {
- case VEH_SHIP: base_cost.AddCost(_price.ship_base); break;
- case VEH_ROAD: base_cost.AddCost(_price.roadveh_base); break;
- case VEH_AIRCRAFT: base_cost.AddCost(_price.aircraft_base); break;
+ case VEH_SHIP:
+ base_cost = _price.ship_base;
+ expense_type = EXPENSES_SHIP_RUN;
+ break;
+
+ case VEH_ROAD:
+ base_cost = _price.roadveh_base;
+ expense_type = EXPENSES_ROADVEH_RUN;
+ break;
+
+ case VEH_AIRCRAFT:
+ base_cost = _price.aircraft_base;
+ expense_type = EXPENSES_AIRCRAFT_RUN;
+ break;
+
case VEH_TRAIN:
- base_cost.AddCost(2 * ((RailVehInfo(engine_type)->railveh_type == RAILVEH_WAGON) ?
- _price.build_railwagon : _price.build_railvehicle));
+ base_cost = 2 * ((RailVehInfo(engine_type)->railveh_type == RAILVEH_WAGON) ?
+ _price.build_railwagon : _price.build_railvehicle);
+ expense_type = EXPENSES_TRAIN_RUN;
break;
- default: NOT_REACHED(); break;
+
+ default: NOT_REACHED();
}
- return CommandCost((EngInfo(engine_type)->refit_cost * base_cost.GetCost()) >> 10);
+ return CommandCost(expense_type, (EngInfo(engine_type)->refit_cost * base_cost) >> 10);
}
static void DoDrawVehicle(const Vehicle *v)
@@ -1584,7 +1627,7 @@
uint16 wagon_list_length = 0;
uint16 wagon_count = 0;
- CommandCost cost;
+ CommandCost cost(EXPENSES_NEW_VEHICLES);
uint i, sell_command, total_number_vehicles;
VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
@@ -1669,7 +1712,6 @@
* Because of this, we can't estimate costs due to wagon removal and we will have to always return 0 and pay manually
* Since we pay after each vehicle is replaced and MaybeReplaceVehicle() check if the player got enough money
* we should never reach a condition where the player will end up with negative money from doing this */
- SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
SubtractMoneyFromPlayer(ret);
}
}
@@ -1698,7 +1740,7 @@
{
Vehicle *v_front, *v;
Vehicle *w_front, *w, *w_rear;
- CommandCost cost, total_cost;
+ CommandCost cost, total_cost(EXPENSES_NEW_VEHICLES);
uint32 build_argument = 2;
if (!IsValidVehicleID(p1)) return CMD_ERROR;
@@ -1852,9 +1894,6 @@
return CMD_ERROR;
}
- /* Set the expense type last as refitting will make the cost go towards
- * running costs... */
- SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
return total_cost;
}
@@ -2115,7 +2154,7 @@
max += v->cargo_cap;
if (v->cargo_cap != 0) {
unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
- loading |= (u->current_order.flags & OF_UNLOAD) == 0 && st->goods[v->cargo_type].days_since_pickup != 255;
+ loading |= (u->current_order.flags & OFB_UNLOAD) == 0 && st->goods[v->cargo_type].days_since_pickup != 255;
cars++;
}
}
@@ -2137,7 +2176,7 @@
case VEH_TRAIN:
InvalidateWindowClasses(WC_TRAINS_LIST);
if (!IsFrontEngine(v)) v = v->First();
- UpdateSignalsOnSegment(v->tile, GetRailDepotDirection(v->tile));
+ UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
v->load_unload_time_rem = 0;
break;
@@ -2201,11 +2240,11 @@
}
}
- if (HasBit(t.flags, OFB_PART_OF_ORDERS)) {
+ if (HasBit(t.flags, OF_PART_OF_ORDERS)) {
/* Part of orders */
UpdateVehicleTimetable(v, true);
v->cur_order_index++;
- } else if (HasBit(t.flags, OFB_HALT_IN_DEPOT)) {
+ } else if (HasBit(t.flags, OF_HALT_IN_DEPOT)) {
/* Force depot visit */
v->vehstatus |= VS_STOPPED;
if (v->owner == _local_player) {
@@ -2269,7 +2308,6 @@
CommandCost CmdNameVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v;
- StringID str;
if (!IsValidVehicleID(p1) || StrEmpty(_cmd_text)) return CMD_ERROR;
@@ -2279,17 +2317,11 @@
if (!IsUniqueVehicleName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
- str = AllocateName(_cmd_text, 2);
- if (str == 0) return CMD_ERROR;
-
if (flags & DC_EXEC) {
- StringID old_str = v->string_id;
- v->string_id = str;
- DeleteName(old_str);
+ free(v->name);
+ v->name = strdup(_cmd_text);
ResortVehicleLists();
MarkWholeScreenDirty();
- } else {
- DeleteName(str);
}
return CommandCost();
@@ -2322,26 +2354,51 @@
}
-static Rect _old_vehicle_coords;
-
-void BeginVehicleMove(Vehicle *v)
+static Rect _old_vehicle_coords; ///< coords of vehicle before it has moved
+
+/**
+ * Stores the vehicle image coords for later call to EndVehicleMove()
+ * @param v vehicle which image's coords to store
+ * @see _old_vehicle_coords
+ * @see EndVehicleMove()
+ */
+void BeginVehicleMove(const Vehicle *v)
{
- _old_vehicle_coords.left = v->left_coord;
- _old_vehicle_coords.top = v->top_coord;
- _old_vehicle_coords.right = v->right_coord;
+ _old_vehicle_coords.left = v->left_coord;
+ _old_vehicle_coords.top = v->top_coord;
+ _old_vehicle_coords.right = v->right_coord;
_old_vehicle_coords.bottom = v->bottom_coord;
}
-void EndVehicleMove(Vehicle *v)
+/**
+ * Marks screen dirty after a vehicle has moved
+ * @param v vehicle which is marked dirty
+ * @see _old_vehicle_coords
+ * @see BeginVehicleMove()
+ */
+void EndVehicleMove(const Vehicle *v)
{
MarkAllViewportsDirty(
- min(_old_vehicle_coords.left,v->left_coord),
- min(_old_vehicle_coords.top,v->top_coord),
- max(_old_vehicle_coords.right,v->right_coord)+1,
- max(_old_vehicle_coords.bottom,v->bottom_coord)+1
+ min(_old_vehicle_coords.left, v->left_coord),
+ min(_old_vehicle_coords.top, v->top_coord),
+ max(_old_vehicle_coords.right, v->right_coord) + 1,
+ max(_old_vehicle_coords.bottom, v->bottom_coord) + 1
);
}
+/**
+ * Marks viewports dirty where the vehicle's image is
+ * In fact, it equals
+ * BeginVehicleMove(v); EndVehicleMove(v);
+ * @param v vehicle to mark dirty
+ * @see BeginVehicleMove()
+ * @see EndVehicleMove()
+ */
+void MarkSingleVehicleDirty(const Vehicle *v)
+{
+ MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
+}
+
/* returns true if staying in the same tile */
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
{
@@ -2547,42 +2604,35 @@
case VEH_TRAIN: {
const RailVehicleInfo *rvi = RailVehInfo(engine_type);
- switch (rvi->railtype) {
- default: NOT_REACHED();
- case RAILTYPE_RAIL:
- case RAILTYPE_ELECTRIC:
- {
- if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
- if (rvi->railveh_type == RAILVEH_WAGON) {
- if (!GetCargo(cargo_type)->is_freight) {
- if (parent_engine_type == INVALID_ENGINE) {
- scheme = LS_PASSENGER_WAGON_STEAM;
- } else {
- switch (RailVehInfo(parent_engine_type)->engclass) {
- default: NOT_REACHED();
- case EC_STEAM: scheme = LS_PASSENGER_WAGON_STEAM; break;
- case EC_DIESEL: scheme = LS_PASSENGER_WAGON_DIESEL; break;
- case EC_ELECTRIC: scheme = LS_PASSENGER_WAGON_ELECTRIC; break;
- }
- }
- } else {
- scheme = LS_FREIGHT_WAGON;
- }
+ if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
+ if (rvi->railveh_type == RAILVEH_WAGON) {
+ if (!GetCargo(cargo_type)->is_freight) {
+ if (parent_engine_type == INVALID_ENGINE) {
+ scheme = LS_PASSENGER_WAGON_STEAM;
} else {
- bool is_mu = HasBit(EngInfo(engine_type)->misc_flags, EF_RAIL_IS_MU);
-
- switch (rvi->engclass) {
+ switch (RailVehInfo(parent_engine_type)->engclass) {
default: NOT_REACHED();
- case EC_STEAM: scheme = LS_STEAM; break;
- case EC_DIESEL: scheme = is_mu ? LS_DMU : LS_DIESEL; break;
- case EC_ELECTRIC: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break;
+ case EC_STEAM: scheme = LS_PASSENGER_WAGON_STEAM; break;
+ case EC_DIESEL: scheme = LS_PASSENGER_WAGON_DIESEL; break;
+ case EC_ELECTRIC: scheme = LS_PASSENGER_WAGON_ELECTRIC; break;
+ case EC_MONORAIL: scheme = LS_PASSENGER_WAGON_MONORAIL; break;
+ case EC_MAGLEV: scheme = LS_PASSENGER_WAGON_MAGLEV; break;
}
}
- break;
+ } else {
+ scheme = LS_FREIGHT_WAGON;
}
-
- case RAILTYPE_MONO: scheme = LS_MONORAIL; break;
- case RAILTYPE_MAGLEV: scheme = LS_MAGLEV; break;
+ } else {
+ bool is_mu = HasBit(EngInfo(engine_type)->misc_flags, EF_RAIL_IS_MU);
+
+ switch (rvi->engclass) {
+ default: NOT_REACHED();
+ case EC_STEAM: scheme = LS_STEAM; break;
+ case EC_DIESEL: scheme = is_mu ? LS_DMU : LS_DIESEL; break;
+ case EC_ELECTRIC: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break;
+ case EC_MONORAIL: scheme = LS_MONORAIL; break;
+ case EC_MAGLEV: scheme = LS_MAGLEV; break;
+ }
}
break;
}
@@ -2702,7 +2752,8 @@
SLE_VAR(Vehicle, subtype, SLE_UINT8),
SLE_REF(Vehicle, next, REF_VEHICLE_OLD),
- SLE_VAR(Vehicle, string_id, SLE_STRINGID),
+ SLE_CONDVAR(Vehicle, name, SLE_NAME, 0, 83),
+ SLE_CONDSTR(Vehicle, name, SLE_STR, 0, 84, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, unitnumber, SLE_FILE_U8 | SLE_VAR_U16, 0, 7),
SLE_CONDVAR(Vehicle, unitnumber, SLE_UINT16, 8, SL_MAX_VERSION),
SLE_VAR(Vehicle, owner, SLE_UINT8),
@@ -3062,14 +3113,14 @@
this->current_order.dest == this->last_station_visited) {
/* Arriving at the ordered station.
* Keep the load/unload flags, as we (obviously) still need them. */
- this->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER;
+ this->current_order.flags &= OFB_FULL_LOAD | OFB_UNLOAD | OFB_TRANSFER;
/* Furthermore add the Non Stop flag to mark that this station
* is the actual destination of the vehicle, which is (for example)
* necessary to be known for HandleTrainLoading to determine
* whether the train is lost or not; not marking a train lost
* that arrives at random stations is bad. */
- this->current_order.flags |= OF_NON_STOP;
+ this->current_order.flags |= OFB_NON_STOP;
UpdateVehicleTimetable(this, true);
} else {
/* This is just an unordered intermediate stop */
@@ -3079,11 +3130,10 @@
current_order.type = OT_LOADING;
GetStation(this->last_station_visited)->loading_vehicles.push_back(this);
- SET_EXPENSES_TYPE(this->GetExpenseType(true));
VehiclePayment(this);
InvalidateWindow(this->GetVehicleListWindowClass(), this->owner);
- InvalidateWindowWidget(WC_VEHICLE_VIEW, this->index, STATUS_BAR);
+ InvalidateWindowWidget(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
InvalidateWindow(WC_STATION_VIEW, this->last_station_visited);
@@ -3096,7 +3146,7 @@
assert(current_order.type == OT_LOADING);
/* Only update the timetable if the vehicle was supposed to stop here. */
- if (current_order.flags & OF_NON_STOP) UpdateVehicleTimetable(this, false);
+ if (current_order.flags & OFB_NON_STOP) UpdateVehicleTimetable(this, false);
current_order.type = OT_LEAVESTATION;
current_order.flags = 0;
@@ -3123,7 +3173,7 @@
this->LeaveStation();
/* If this was not the final order, don't remove it from the list. */
- if (!(b.flags & OF_NON_STOP)) return;
+ if (!(b.flags & OFB_NON_STOP)) return;
break;
}
@@ -3166,3 +3216,15 @@
this->sprite_height = 1;
this->z_height = 1;
}
+
+void StopAllVehicles()
+{
+ Vehicle *v;
+ FOR_ALL_VEHICLES(v) {
+ /* Code ripped from CmdStartStopTrain. Can't call it, because of
+ * ownership problems, so we'll duplicate some code, for now */
+ v->vehstatus |= VS_STOPPED;
+ InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
+ InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
+ }
+}