--- a/src/train_cmd.cpp Wed Jun 13 11:17:30 2007 +0000
+++ b/src/train_cmd.cpp Wed Jun 13 11:45:14 2007 +0000
@@ -37,6 +37,7 @@
#include "yapf/yapf.h"
#include "date.h"
#include "cargotype.h"
+#include "group.h"
static bool TrainCheckIfLineEnds(Vehicle *v);
static void TrainController(Vehicle *v, bool update_image);
@@ -114,7 +115,7 @@
/* Vehicle weight is not added for articulated parts. */
if (!IsArticulatedPart(u)) {
/* vehicle weight is the sum of the weight of the vehicle and the weight of its cargo */
- vweight += RailVehInfo(u->engine_type)->weight;
+ vweight += GetVehicleProperty(u, 0x16, RailVehInfo(u->engine_type)->weight);
/* powered wagons have extra weight added */
if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON))
@@ -166,6 +167,9 @@
if (IsTrainEngine(u)) first_engine = u->engine_type;
+ /* Cache wagon override sprite group. NULL is returned if there is none */
+ u->u.rail.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->u.rail.first_engine);
+
if (rvi_u->visual_effect != 0) {
u->u.rail.cached_vis_effect = rvi_u->visual_effect;
} else {
@@ -190,7 +194,7 @@
}
if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
- UsesWagonOverride(u) && (u->u.rail.cached_vis_effect < 0x40)) {
+ UsesWagonOverride(u) && !HASBIT(u->u.rail.cached_vis_effect, 7)) {
/* wagon is powered */
SETBIT(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status
} else {
@@ -217,6 +221,11 @@
}
}
+ if (u->cargo_type == rvi_u->cargo_type && u->cargo_subtype == 0) {
+ /* Set cargo capacity if we've not been refitted */
+ u->cargo_cap = GetVehicleProperty(u, 0x14, rvi_u->capacity);
+ }
+
/* check the vehicle length (callback) */
uint16 veh_len = CALLBACK_FAILED;
if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) {
@@ -535,7 +544,6 @@
u->x_pos = v->x_pos;
u->y_pos = v->y_pos;
u->z_pos = v->z_pos;
- u->z_height = v->z_height;
u->u.rail.track = v->u.rail.track;
u->u.rail.railtype = v->u.rail.railtype;
u->build_year = v->build_year;
@@ -552,7 +560,7 @@
u->max_age = 0;
u->engine_type = engine_type;
u->value = 0;
- u->type = VEH_TRAIN;
+ u = new (u) Train();
u->subtype = 0;
SetArticulatedPart(u);
u->cur_image = 0xAC2;
@@ -567,7 +575,7 @@
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
const RailVehicleInfo *rvi = RailVehInfo(engine);
- int32 value = (rvi->base_cost * _eco->GetPrice(CEconomy::BUILD_RAILWAGON)) >> 8;
+ int32 value = (GetEngineProperty(engine, 0x17, rvi->base_cost) * _eco->GetPrice(CEconomy::BUILD_RAILWAGON)) >> 8;
uint num_vehicles = 1 + CountArticulatedParts(engine);
@@ -608,7 +616,6 @@
v->y_pos = y;
v->z_pos = GetSlopeZ(x, y);
v->owner = _current_player;
- v->z_height = 6;
v->u.rail.track = TRACK_BIT_DEPOT;
v->vehstatus = VS_HIDDEN | VS_DEFPAL;
@@ -630,16 +637,19 @@
v->u.rail.railtype = rvi->railtype;
v->build_year = _cur_year;
- v->type = VEH_TRAIN;
+ v = new (v) Train();
v->cur_image = 0xAC2;
v->random_bits = VehicleRandomBits();
+ v->group_id = DEFAULT_GROUP;
+
AddArticulatedParts(vl);
_new_vehicle_id = v->index;
VehiclePositionChanged(v);
TrainConsistChanged(GetFirstVehicleInChain(v));
+ UpdateTrainGroupID(GetFirstVehicleInChain(v));
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
if (IsLocalPlayer()) {
@@ -668,9 +678,9 @@
}
}
-static int32 EstimateTrainCost(const RailVehicleInfo* rvi)
+static int32 EstimateTrainCost(EngineID engine, const RailVehicleInfo* rvi)
{
- return rvi->base_cost * (_eco->GetPrice(CEconomy::BUILD_RAILVEHICLE) >> 3) >> 5;
+ return GetEngineProperty(engine, 0x17, rvi->base_cost) * (_eco->GetPrice(CEconomy::BUILD_RAILVEHICLE) >> 3) >> 5;
}
static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building)
@@ -681,7 +691,6 @@
u->x_pos = v->x_pos;
u->y_pos = v->y_pos;
u->z_pos = v->z_pos;
- u->z_height = 6;
u->u.rail.track = TRACK_BIT_DEPOT;
u->vehstatus = v->vehstatus & ~VS_STOPPED;
u->subtype = 0;
@@ -696,7 +705,7 @@
u->build_year = v->build_year;
if (building) v->value >>= 1;
u->value = v->value;
- u->type = VEH_TRAIN;
+ u = new (u) Train();
u->cur_image = 0xAC2;
u->random_bits = VehicleRandomBits();
VehiclePositionChanged(u);
@@ -731,7 +740,7 @@
if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags);
- int32 value = EstimateTrainCost(rvi);
+ int32 value = EstimateTrainCost(p1, rvi);
uint num_vehicles =
(rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) +
@@ -763,7 +772,6 @@
v->x_pos = x;
v->y_pos = y;
v->z_pos = GetSlopeZ(x, y);
- v->z_height = 6;
v->u.rail.track = TRACK_BIT_DEPOT;
v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
v->spritenum = rvi->image_index;
@@ -789,13 +797,15 @@
v->service_interval = _patches.servint_trains;
v->date_of_last_service = _date;
v->build_year = _cur_year;
- v->type = VEH_TRAIN;
+ v = new (v) Train();
v->cur_image = 0xAC2;
v->random_bits = VehicleRandomBits();
v->vehicle_flags = 0;
if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SETBIT(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
+ v->group_id = DEFAULT_GROUP;
+
v->subtype = 0;
SetFrontEngine(v);
SetTrainEngine(v);
@@ -817,6 +827,7 @@
TrainConsistChanged(v);
UpdateTrainAcceleration(v);
+ UpdateTrainGroupID(v);
if (!HASBIT(p2, 1)) { // check if the cars should be added to the new vehicle
NormalizeTrainVehInDepot(v);
@@ -1112,6 +1123,16 @@
for (Vehicle *u = src_head; u != NULL; u = u->next) u->first = NULL;
for (Vehicle *u = dst_head; u != NULL; u = u->next) u->first = NULL;
+ /* If we move the front Engine and if the second vehicle is not an engine
+ add the whole vehicle to the DEFAULT_GROUP */
+ if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) {
+ const Vehicle *v = GetNextVehicle(src);
+
+ if (v != NULL && !IsTrainEngine(v)) {
+ DoCommand(tile, DEFAULT_GROUP, v->index, flags, CMD_ADD_VEHICLE_GROUP);
+ }
+ }
+
if (HASBIT(p2, 0)) {
/* unlink ALL wagons */
if (src != src_head) {
@@ -1141,6 +1162,14 @@
SetFrontEngine(src);
assert(src->orders == NULL);
src->num_orders = 0;
+
+ // Decrease the engines number of the src engine_type
+ if (!IsDefaultGroupID(src->group_id) && IsValidGroupID(src->group_id)) {
+ GetGroup(src->group_id)->num_engines[src->engine_type]--;
+ }
+
+ // If we move an engine to a new line affect it to the DEFAULT_GROUP
+ src->group_id = DEFAULT_GROUP;
}
} else {
SetFreeWagon(src);
@@ -1202,13 +1231,18 @@
* To do this, CmdMoveRailVehicle must be called once more
* we can't loop forever here because next time we reach this line we will have a front engine */
if (src_head != NULL && !IsFrontEngine(src_head) && IsTrainEngine(src_head)) {
+ /* As in CmdMoveRailVehicle src_head->group_id will be equal to DEFAULT_GROUP
+ * we need to save the group and reaffect it to src_head */
+ const GroupID tmp_g = src_head->group_id;
CmdMoveRailVehicle(0, flags, src_head->index | (INVALID_VEHICLE << 16), 1);
+ SetTrainGroupID(src_head, tmp_g);
src_head = NULL; // don't do anything more to this train since the new call will do it
}
if (src_head != NULL) {
NormaliseTrainConsist(src_head);
TrainConsistChanged(src_head);
+ UpdateTrainGroupID(src_head);
if (IsFrontEngine(src_head)) {
UpdateTrainAcceleration(src_head);
InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index);
@@ -1223,6 +1257,7 @@
if (dst_head != NULL) {
NormaliseTrainConsist(dst_head);
TrainConsistChanged(dst_head);
+ UpdateTrainGroupID(dst_head);
if (IsFrontEngine(dst_head)) {
UpdateTrainAcceleration(dst_head);
InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index);
@@ -1269,7 +1304,6 @@
DeleteVehicleNews(p1, STR_8814_TRAIN_IS_WAITING_IN_DEPOT);
}
- v->u.rail.days_since_order_progr = 0;
v->vehstatus ^= VS_STOPPED;
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
@@ -1364,6 +1398,8 @@
if (first->next_shared != NULL) {
first->next_shared->prev_shared = new_f;
new_f->next_shared = first->next_shared;
+ } else {
+ RemoveVehicleFromGroup(v);
}
/*
@@ -1394,6 +1430,7 @@
if (first != NULL) {
NormaliseTrainConsist(first);
TrainConsistChanged(first);
+ UpdateTrainGroupID(first);
if (IsFrontEngine(first)) {
InvalidateWindow(WC_VEHICLE_DETAILS, first->index);
InvalidateWindow(WC_VEHICLE_REFIT, first->index);
@@ -1447,6 +1484,7 @@
first = UnlinkWagon(v, first);
DeleteDepotHighlightOfVehicle(v);
DeleteVehicle(v);
+ RemoveVehicleFromGroup(v);
}
}
@@ -1454,6 +1492,7 @@
if (flags & DC_EXEC && first != NULL) {
NormaliseTrainConsist(first);
TrainConsistChanged(first);
+ UpdateTrainGroupID(first);
if (IsFrontEngine(first)) UpdateTrainAcceleration(first);
InvalidateWindow(WC_VEHICLE_DETAILS, first->index);
InvalidateWindow(WC_VEHICLE_REFIT, first->index);
@@ -1463,9 +1502,9 @@
return cost;
}
-static void UpdateTrainDeltaXY(Vehicle *v, Direction direction)
+void Train::UpdateDeltaXY(Direction direction)
{
-#define MKIT(a,b,c,d) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0)
+#define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
static const uint32 _delta_xy_table[8] = {
MKIT(3, 3, -1, -1),
MKIT(3, 7, -1, -3),
@@ -1479,16 +1518,16 @@
#undef MKIT
uint32 x = _delta_xy_table[direction];
-
- v->x_offs = GB(x, 0, 8);
- v->y_offs = GB(x, 8, 8);
- v->sprite_width = GB(x, 16, 8);
- v->sprite_height = GB(x, 24, 8);
+ this->x_offs = GB(x, 0, 8);
+ this->y_offs = GB(x, 8, 8);
+ this->sprite_width = GB(x, 16, 8);
+ this->sprite_height = GB(x, 24, 8);
+ this->z_height = 6;
}
static void UpdateVarsAfterSwap(Vehicle *v)
{
- UpdateTrainDeltaXY(v, v->direction);
+ v->UpdateDeltaXY(v->direction);
v->cur_image = GetTrainImage(v, v->direction);
BeginVehicleMove(v);
VehiclePositionChanged(v);
@@ -1751,11 +1790,14 @@
* param p2 various bitstuffed elements
* - p2 = (bit 0-7) - the new cargo type to refit to
* - p2 = (bit 8-15) - the new cargo subtype to refit to
+ * - p2 = (bit 16) - refit only this vehicle
+ * @return cost of refit or error
*/
int32 CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
CargoID new_cid = GB(p2, 0, 8);
byte new_subtype = GB(p2, 8, 8);
+ bool only_this = HASBIT(p2, 16);
if (!IsValidVehicleID(p1)) return CMD_ERROR;
@@ -1833,7 +1875,7 @@
}
}
}
- } while ((v = v->next) != NULL);
+ } while ((v = v->next) != NULL && !only_this);
_returned_refit_capacity = num;
@@ -1966,7 +2008,6 @@
if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
if (flags & DC_EXEC) {
if (HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
- v->u.rail.days_since_order_progr = 0;
v->cur_order_index++;
}
@@ -2029,7 +2070,6 @@
/* no smoke? */
if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) ||
disable_effect ||
- rvi->railtype > RAILTYPE_ELECTRIC ||
v->vehstatus & VS_HIDDEN) {
continue;
}
@@ -2090,22 +2130,20 @@
static const SoundFx sfx[] = {
SND_04_TRAIN,
SND_0A_TRAIN_HORN,
- SND_0A_TRAIN_HORN
+ SND_0A_TRAIN_HORN,
+ SND_47_MAGLEV_2,
+ SND_41_MAGLEV
};
if (PlayVehicleSound(v, VSE_START)) return;
EngineID engtype = v->engine_type;
- switch (RailVehInfo(engtype)->railtype) {
- case RAILTYPE_RAIL:
- case RAILTYPE_ELECTRIC:
- SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], v);
- break;
-
- case RAILTYPE_MONO: SndPlayVehicleFx(SND_47_MAGLEV_2, v); break;
- case RAILTYPE_MAGLEV: SndPlayVehicleFx(SND_41_MAGLEV, v); break;
- default: NOT_REACHED();
- }
+ SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], v);
+}
+
+void Train::PlayLeaveStationSound() const
+{
+ TrainPlayLeaveStationSound(this);
}
static bool CheckTrainStayInDepot(Vehicle *v)
@@ -2146,7 +2184,7 @@
v->vehstatus &= ~VS_HIDDEN;
v->cur_speed = 0;
- UpdateTrainDeltaXY(v, v->direction);
+ v->UpdateDeltaXY(v->direction);
v->cur_image = GetTrainImage(v, v->direction);
VehiclePositionChanged(v);
UpdateSignalsOnSegment(v->tile, DirToDiagDir(v->direction));
@@ -2519,62 +2557,17 @@
return !at_waypoint && CheckReverseTrain(v);
}
-static void MarkTrainDirty(Vehicle *v)
+void Train::MarkDirty()
{
+ Vehicle *v = this;
do {
v->cur_image = GetTrainImage(v, v->direction);
MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
} while ((v = v->next) != NULL);
-}
-
-static void HandleTrainLoading(Vehicle *v, bool mode)
-{
- switch (v->current_order.type) {
- case OT_LOADING: {
- if (mode) return;
-
- /* don't mark the train as lost if we're loading on the final station. */
- if (v->current_order.flags & OF_NON_STOP) {
- v->u.rail.days_since_order_progr = 0;
- }
-
- if (--v->load_unload_time_rem) return;
-
- if (CanFillVehicle(v) && (
- v->current_order.flags & OF_FULL_LOAD ||
- (_patches.gradual_loading && !HASBIT(v->vehicle_flags, VF_LOADING_FINISHED))
- )) {
- v->u.rail.days_since_order_progr = 0; // Prevent a train lost message for full loading trains
- SET_EXPENSES_TYPE(EXPENSES_TRAIN_INC);
- if (LoadUnloadVehicle(v, false)) {
- InvalidateWindow(WC_TRAINS_LIST, v->owner);
- MarkTrainDirty(v);
-
- /* need to update acceleration and cached values since the goods on the train changed. */
- TrainCargoChanged(v);
- UpdateTrainAcceleration(v);
- }
- return;
- }
-
- TrainPlayLeaveStationSound(v);
-
- Order b = v->current_order;
- v->LeaveStation();
-
- /* If this was not the final order, don't remove it from the list. */
- if (!(b.flags & OF_NON_STOP)) return;
- break;
- }
-
- case OT_DUMMY: break;
-
- default: return;
- }
-
- v->u.rail.days_since_order_progr = 0;
- v->cur_order_index++;
- InvalidateVehicleOrder(v);
+
+ /* need to update acceleration and cached values since the goods on the train changed. */
+ TrainCargoChanged(this);
+ UpdateTrainAcceleration(this);
}
static int UpdateTrainSpeed(Vehicle *v)
@@ -2631,29 +2624,8 @@
);
}
- /* Did we reach the final destination? */
- if (v->current_order.type == OT_GOTO_STATION &&
- v->current_order.dest == station) {
- /* Yeah, keep the load/unload flags
- * Non Stop now means if the order should be increased. */
- v->BeginLoading();
- v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER;
- v->current_order.flags |= OF_NON_STOP;
- } else {
- /* No, just do a simple load */
- v->BeginLoading();
- v->current_order.flags = 0;
- }
+ v->BeginLoading();
v->current_order.dest = 0;
-
- SET_EXPENSES_TYPE(EXPENSES_TRAIN_INC);
- if (LoadUnloadVehicle(v, true) != 0) {
- InvalidateWindow(WC_TRAINS_LIST, v->owner);
- TrainCargoChanged(v);
- UpdateTrainAcceleration(v);
- }
- MarkTrainDirty(v);
- InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
}
static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
@@ -3078,7 +3050,7 @@
/* update image of train, as well as delta XY */
Direction newdir = GetNewVehicleDirection(v, gp.x, gp.y);
- UpdateTrainDeltaXY(v, newdir);
+ v->UpdateDeltaXY(newdir);
if (update_image) v->cur_image = GetTrainImage(v, newdir);
v->x_pos = gp.x;
@@ -3130,6 +3102,9 @@
BeginVehicleMove(v);
EndVehicleMove(v);
+
+ if (IsFrontEngine(v)) RemoveVehicleFromGroup(v);
+
DeleteVehicle(v);
if (v->u.rail.track != TRACK_BIT_DEPOT && v->u.rail.track != TRACK_BIT_WORMHOLE)
@@ -3174,7 +3149,7 @@
if (!(v->vehstatus & VS_HIDDEN)) {
v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
BeginVehicleMove(v);
- UpdateTrainDeltaXY(v, v->direction);
+ v->UpdateDeltaXY(v->direction);
v->cur_image = GetTrainImage(v, v->direction);
/* Refrain from updating the z position of the vehicle when on
a bridge, because AfterSetTrainPos will put the vehicle under
@@ -3215,6 +3190,7 @@
if (state >= 4440 && !(v->tick_counter&0x1F)) {
DeleteLastWagon(v);
+ InvalidateWindow(WC_REPLACE_VEHICLE, (v->group_id << 16) | VEH_TRAIN);
}
}
@@ -3376,7 +3352,7 @@
return;
}
- HandleTrainLoading(v, mode);
+ v->HandleLoading(mode);
if (v->current_order.type == OT_LOADING) return;
@@ -3465,6 +3441,8 @@
return;
}
+ if (v->current_order.type == OT_LOADING) v->LeaveStation();
+
v->current_order.type = OT_GOTO_DEPOT;
v->current_order.flags = OF_NON_STOP;
v->current_order.dest = depot->index;