src/train_cmd.cpp
changeset 7497 40e457c0a8ac
parent 7493 07944c9e005f
child 7502 f821f134ec5a
equal deleted inserted replaced
7496:49cec492627b 7497:40e457c0a8ac
   159 	v->u.rail.compatible_railtypes = 0;
   159 	v->u.rail.compatible_railtypes = 0;
   160 
   160 
   161 	for (Vehicle *u = v; u != NULL; u = u->Next()) {
   161 	for (Vehicle *u = v; u != NULL; u = u->Next()) {
   162 		const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
   162 		const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
   163 
   163 
   164 		/* Update the v->first cache. This is faster than having to brute force it later. */
   164 		/* Check the v->first cache. */
   165 		if (u->first == NULL) u->first = v;
   165 		assert(u->First() == v);
   166 
   166 
   167 		/* update the 'first engine' */
   167 		/* update the 'first engine' */
   168 		u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine;
   168 		u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine;
   169 		u->u.rail.railtype = rvi_u->railtype;
   169 		u->u.rail.railtype = rvi_u->railtype;
   170 
   170 
   581 			AddArticulatedParts(vl, VEH_TRAIN);
   581 			AddArticulatedParts(vl, VEH_TRAIN);
   582 
   582 
   583 			_new_vehicle_id = v->index;
   583 			_new_vehicle_id = v->index;
   584 
   584 
   585 			VehiclePositionChanged(v);
   585 			VehiclePositionChanged(v);
   586 			TrainConsistChanged(GetFirstVehicleInChain(v));
   586 			TrainConsistChanged(v->First());
   587 			UpdateTrainGroupID(GetFirstVehicleInChain(v));
   587 			UpdateTrainGroupID(v->First());
   588 
   588 
   589 			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
   589 			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
   590 			if (IsLocalPlayer()) {
   590 			if (IsLocalPlayer()) {
   591 				InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
   591 				InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
   592 			}
   592 			}
   618 	return CommandCost(GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5);
   618 	return CommandCost(GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5);
   619 }
   619 }
   620 
   620 
   621 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building)
   621 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building)
   622 {
   622 {
       
   623 	u = new (u) Train();
   623 	u->direction = v->direction;
   624 	u->direction = v->direction;
   624 	u->owner = v->owner;
   625 	u->owner = v->owner;
   625 	u->tile = v->tile;
   626 	u->tile = v->tile;
   626 	u->x_pos = v->x_pos;
   627 	u->x_pos = v->x_pos;
   627 	u->y_pos = v->y_pos;
   628 	u->y_pos = v->y_pos;
   628 	u->z_pos = v->z_pos;
   629 	u->z_pos = v->z_pos;
   629 	u->u.rail.track = TRACK_BIT_DEPOT;
   630 	u->u.rail.track = TRACK_BIT_DEPOT;
   630 	u->vehstatus = v->vehstatus & ~VS_STOPPED;
   631 	u->vehstatus = v->vehstatus & ~VS_STOPPED;
   631 	u = new (u) Train();
       
   632 	u->subtype = 0;
   632 	u->subtype = 0;
   633 	SetMultiheaded(u);
   633 	SetMultiheaded(u);
   634 	u->spritenum = v->spritenum + 1;
   634 	u->spritenum = v->spritenum + 1;
   635 	u->cargo_type = v->cargo_type;
   635 	u->cargo_type = v->cargo_type;
   636 	u->cargo_subtype = v->cargo_subtype;
   636 	u->cargo_subtype = v->cargo_subtype;
   839 	}
   839 	}
   840 
   840 
   841 	Vehicle *u;
   841 	Vehicle *u;
   842 	for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {}
   842 	for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {}
   843 	GetLastEnginePart(u)->SetNext(GetNextVehicle(v));
   843 	GetLastEnginePart(u)->SetNext(GetNextVehicle(v));
   844 	v->first = NULL; // we shouldn't point to the old first, since the vehicle isn't in that chain anymore
       
   845 	return first;
   844 	return first;
   846 }
   845 }
   847 
   846 
   848 static Vehicle *FindGoodVehiclePos(const Vehicle *src)
   847 static Vehicle *FindGoodVehiclePos(const Vehicle *src)
   849 {
   848 {
   870  * add a vehicle v behind vehicle dest
   869  * add a vehicle v behind vehicle dest
   871  * use this function since it sets flags as needed
   870  * use this function since it sets flags as needed
   872  */
   871  */
   873 static void AddWagonToConsist(Vehicle *v, Vehicle *dest)
   872 static void AddWagonToConsist(Vehicle *v, Vehicle *dest)
   874 {
   873 {
   875 	UnlinkWagon(v, GetFirstVehicleInChain(v));
   874 	UnlinkWagon(v, v->First());
   876 	if (dest == NULL) return;
   875 	if (dest == NULL) return;
   877 
   876 
   878 	v->SetNext(dest->Next());
   877 	Vehicle *next = dest->Next();
   879 	dest->SetNext(v);
   878 	dest->SetNext(v);
       
   879 	v->SetNext(next);
   880 	ClearFreeWagon(v);
   880 	ClearFreeWagon(v);
   881 	ClearFrontEngine(v);
   881 	ClearFrontEngine(v);
   882 }
   882 }
   883 
   883 
   884 /*
   884 /*
   931 		dst = GetVehicle(d);
   931 		dst = GetVehicle(d);
   932 		if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR;
   932 		if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR;
   933 	}
   933 	}
   934 
   934 
   935 	/* if an articulated part is being handled, deal with its parent vehicle */
   935 	/* if an articulated part is being handled, deal with its parent vehicle */
   936 	while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src);
   936 	while (IsArticulatedPart(src)) src = src->Previous();
   937 	if (dst != NULL) {
   937 	if (dst != NULL) {
   938 		while (IsArticulatedPart(dst)) dst = GetPrevVehicleInChain(dst);
   938 		while (IsArticulatedPart(dst)) dst = dst->Previous();
   939 	}
   939 	}
   940 
   940 
   941 	/* don't move the same vehicle.. */
   941 	/* don't move the same vehicle.. */
   942 	if (src == dst) return CommandCost();
   942 	if (src == dst) return CommandCost();
   943 
   943 
   944 	/* locate the head of the two chains */
   944 	/* locate the head of the two chains */
   945 	Vehicle *src_head = GetFirstVehicleInChain(src);
   945 	Vehicle *src_head = src->First();
   946 	Vehicle *dst_head;
   946 	Vehicle *dst_head;
   947 	if (dst != NULL) {
   947 	if (dst != NULL) {
   948 		dst_head = GetFirstVehicleInChain(dst);
   948 		dst_head = dst->First();
   949 		if (dst_head->tile != src_head->tile) return CMD_ERROR;
   949 		if (dst_head->tile != src_head->tile) return CMD_ERROR;
   950 		/* Now deal with articulated part of destination wagon */
   950 		/* Now deal with articulated part of destination wagon */
   951 		dst = GetLastEnginePart(dst);
   951 		dst = GetLastEnginePart(dst);
   952 	} else {
   952 	} else {
   953 		dst_head = NULL;
   953 		dst_head = NULL;
  1020 		}
  1020 		}
  1021 	}
  1021 	}
  1022 
  1022 
  1023 	/* do it? */
  1023 	/* do it? */
  1024 	if (flags & DC_EXEC) {
  1024 	if (flags & DC_EXEC) {
  1025 		/* clear the ->first cache */
       
  1026 		for (Vehicle *u = src_head; u != NULL; u = u->Next()) u->first = NULL;
       
  1027 		for (Vehicle *u = dst_head; u != NULL; u = u->Next()) u->first = NULL;
       
  1028 
       
  1029 		/* If we move the front Engine and if the second vehicle is not an engine
  1025 		/* If we move the front Engine and if the second vehicle is not an engine
  1030 		   add the whole vehicle to the DEFAULT_GROUP */
  1026 		   add the whole vehicle to the DEFAULT_GROUP */
  1031 		if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) {
  1027 		if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) {
  1032 			const Vehicle *v = GetNextVehicle(src);
  1028 			const Vehicle *v = GetNextVehicle(src);
  1033 
  1029 
  1099 				for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v));
  1095 				for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v));
  1100 				GetLastEnginePart(v)->SetNext(dst->Next());
  1096 				GetLastEnginePart(v)->SetNext(dst->Next());
  1101 			}
  1097 			}
  1102 			dst->SetNext(src);
  1098 			dst->SetNext(src);
  1103 		}
  1099 		}
       
  1100 
  1104 		if (src->u.rail.other_multiheaded_part != NULL) {
  1101 		if (src->u.rail.other_multiheaded_part != NULL) {
  1105 			if (src->u.rail.other_multiheaded_part == src_head) {
  1102 			if (src->u.rail.other_multiheaded_part == src_head) {
  1106 				src_head = src_head->Next();
  1103 				src_head = src_head->Next();
  1107 			}
  1104 			}
  1108 			AddWagonToConsist(src->u.rail.other_multiheaded_part, src);
  1105 			AddWagonToConsist(src->u.rail.other_multiheaded_part, src);
  1109 			/* previous line set the front engine to the old front. We need to clear that */
       
  1110 			src->u.rail.other_multiheaded_part->first = NULL;
       
  1111 		}
  1106 		}
  1112 
  1107 
  1113 		/* If there is an engine behind first_engine we moved away, it should become new first_engine
  1108 		/* If there is an engine behind first_engine we moved away, it should become new first_engine
  1114 		 * To do this, CmdMoveRailVehicle must be called once more
  1109 		 * To do this, CmdMoveRailVehicle must be called once more
  1115 		 * we can't loop forever here because next time we reach this line we will have a front engine */
  1110 		 * we can't loop forever here because next time we reach this line we will have a front engine */
  1216 
  1211 
  1217 	if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
  1212 	if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
  1218 
  1213 
  1219 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
  1214 	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
  1220 
  1215 
  1221 	while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v);
  1216 	while (IsArticulatedPart(v)) v = v->Previous();
  1222 	Vehicle *first = GetFirstVehicleInChain(v);
  1217 	Vehicle *first = v->First();
  1223 
  1218 
  1224 	/* make sure the vehicle is stopped in the depot */
  1219 	/* make sure the vehicle is stopped in the depot */
  1225 	if (CheckTrainStoppedInDepot(first) < 0) {
  1220 	if (CheckTrainStoppedInDepot(first) < 0) {
  1226 		return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
  1221 		return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
  1227 	}
  1222 	}
  1259 
  1254 
  1260 			/* 2. We are selling the first engine, some special action might be required
  1255 			/* 2. We are selling the first engine, some special action might be required
  1261 			 * here, so take attention */
  1256 			 * here, so take attention */
  1262 			if ((flags & DC_EXEC) && v == first) {
  1257 			if ((flags & DC_EXEC) && v == first) {
  1263 				Vehicle *new_f = GetNextVehicle(first);
  1258 				Vehicle *new_f = GetNextVehicle(first);
  1264 
       
  1265 				/* 2.1 If the first wagon is sold, update the first-> pointers to NULL */
       
  1266 				for (Vehicle *tmp = first; tmp != NULL; tmp = tmp->Next()) tmp->first = NULL;
       
  1267 
  1259 
  1268 				/* 2.2 If there are wagons present after the deleted front engine, check
  1260 				/* 2.2 If there are wagons present after the deleted front engine, check
  1269 				 * if the second wagon (which will be first) is an engine. If it is one,
  1261 				 * if the second wagon (which will be first) is an engine. If it is one,
  1270 				 * promote it as a new train, retaining the unitnumber, orders */
  1262 				 * promote it as a new train, retaining the unitnumber, orders */
  1271 				if (new_f != NULL && IsTrainEngine(new_f)) {
  1263 				if (new_f != NULL && IsTrainEngine(new_f)) {
  1631 
  1623 
  1632 		if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) {
  1624 		if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) {
  1633 			return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT);
  1625 			return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT);
  1634 		}
  1626 		}
  1635 
  1627 
  1636 		Vehicle *front = GetFirstVehicleInChain(v);
  1628 		Vehicle *front = v->First();
  1637 		/* make sure the vehicle is stopped in the depot */
  1629 		/* make sure the vehicle is stopped in the depot */
  1638 		if (CheckTrainStoppedInDepot(front) < 0) {
  1630 		if (CheckTrainStoppedInDepot(front) < 0) {
  1639 			return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
  1631 			return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
  1640 		}
  1632 		}
  1641 
  1633 
  1775 	} while ((v = v->Next()) != NULL && !only_this);
  1767 	} while ((v = v->Next()) != NULL && !only_this);
  1776 
  1768 
  1777 	_returned_refit_capacity = num;
  1769 	_returned_refit_capacity = num;
  1778 
  1770 
  1779 	/* Update the train's cached variables */
  1771 	/* Update the train's cached variables */
  1780 	if (flags & DC_EXEC) TrainConsistChanged(GetFirstVehicleInChain(GetVehicle(p1)));
  1772 	if (flags & DC_EXEC) TrainConsistChanged(GetVehicle(p1)->First());
  1781 
  1773 
  1782 	return cost;
  1774 	return cost;
  1783 }
  1775 }
  1784 
  1776 
  1785 struct TrainFindDepotData {
  1777 struct TrainFindDepotData {
  2716 			v->u.rail.track != TRACK_BIT_DEPOT &&
  2708 			v->u.rail.track != TRACK_BIT_DEPOT &&
  2717 			myabs(v->z_pos - tcc->v->z_pos) < 6 &&
  2709 			myabs(v->z_pos - tcc->v->z_pos) < 6 &&
  2718 			myabs(v->x_pos - tcc->v->x_pos) < 6 &&
  2710 			myabs(v->x_pos - tcc->v->x_pos) < 6 &&
  2719 			myabs(v->y_pos - tcc->v->y_pos) < 6 ) {
  2711 			myabs(v->y_pos - tcc->v->y_pos) < 6 ) {
  2720 
  2712 
  2721 		Vehicle *coll = GetFirstVehicleInChain(v);
  2713 		Vehicle *coll = v->First();
  2722 
  2714 
  2723 		/* it can't collide with its own wagons */
  2715 		/* it can't collide with its own wagons */
  2724 		if (tcc->v == coll ||
  2716 		if (tcc->v == coll ||
  2725 			(tcc->v->u.rail.track == TRACK_BIT_WORMHOLE && (tcc->v->direction & 2) != (v->direction & 2)))
  2717 			(tcc->v->u.rail.track == TRACK_BIT_WORMHOLE && (tcc->v->direction & 2) != (v->direction & 2)))
  2726 			return NULL;
  2718 			return NULL;
  2805 static void TrainController(Vehicle *v, bool update_image)
  2797 static void TrainController(Vehicle *v, bool update_image)
  2806 {
  2798 {
  2807 	Vehicle *prev;
  2799 	Vehicle *prev;
  2808 
  2800 
  2809 	/* For every vehicle after and including the given vehicle */
  2801 	/* For every vehicle after and including the given vehicle */
  2810 	for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->Next()) {
  2802 	for (prev = v->Previous(); v != NULL; prev = v, v = v->Next()) {
  2811 		DiagDirection enterdir = DIAGDIR_BEGIN;
  2803 		DiagDirection enterdir = DIAGDIR_BEGIN;
  2812 		bool update_signals = false;
  2804 		bool update_signals = false;
  2813 		BeginVehicleMove(v);
  2805 		BeginVehicleMove(v);
  2814 
  2806 
  2815 		GetNewVehiclePosResult gp = GetNewVehiclePos(v);
  2807 		GetNewVehiclePosResult gp = GetNewVehiclePos(v);
  2943 
  2935 
  2944 				if (!HASBIT(r, VETS_ENTERED_WORMHOLE)) {
  2936 				if (!HASBIT(r, VETS_ENTERED_WORMHOLE)) {
  2945 					v->tile = gp.new_tile;
  2937 					v->tile = gp.new_tile;
  2946 
  2938 
  2947 					if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) {
  2939 					if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) {
  2948 						TrainPowerChanged(GetFirstVehicleInChain(v));
  2940 						TrainPowerChanged(v->First());
  2949 					}
  2941 					}
  2950 
  2942 
  2951 					v->u.rail.track = chosen_track;
  2943 					v->u.rail.track = chosen_track;
  2952 					assert(v->u.rail.track);
  2944 					assert(v->u.rail.track);
  2953 				}
  2945 				}