src/train_cmd.cpp
branchgamebalance
changeset 9911 0b8b245a2391
parent 9910 0b2aebc8283e
child 9912 1ac8aac92385
--- 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;