103 uint32 weight = 0; |
106 uint32 weight = 0; |
104 |
107 |
105 for (Vehicle *u = v; u != NULL; u = u->next) { |
108 for (Vehicle *u = v; u != NULL; u = u->next) { |
106 uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo_count * FreightWagonMult(u->cargo_type) / 16; |
109 uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo_count * FreightWagonMult(u->cargo_type) / 16; |
107 |
110 |
108 // Vehicle weight is not added for articulated parts. |
111 /* Vehicle weight is not added for articulated parts. */ |
109 if (!IsArticulatedPart(u)) { |
112 if (!IsArticulatedPart(u)) { |
110 // vehicle weight is the sum of the weight of the vehicle and the weight of its cargo |
113 /* vehicle weight is the sum of the weight of the vehicle and the weight of its cargo */ |
111 vweight += RailVehInfo(u->engine_type)->weight; |
114 vweight += RailVehInfo(u->engine_type)->weight; |
112 |
115 |
113 // powered wagons have extra weight added |
116 /* powered wagons have extra weight added */ |
114 if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON)) |
117 if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON)) |
115 vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight; |
118 vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight; |
116 } |
119 } |
117 |
120 |
118 // consist weight is the sum of the weight of all vehicles in the consist |
121 /* consist weight is the sum of the weight of all vehicles in the consist */ |
119 weight += vweight; |
122 weight += vweight; |
120 |
123 |
121 // store vehicle weight in cache |
124 /* store vehicle weight in cache */ |
122 u->u.rail.cached_veh_weight = vweight; |
125 u->u.rail.cached_veh_weight = vweight; |
123 } |
126 } |
124 |
127 |
125 // store consist weight in cache |
128 /* store consist weight in cache */ |
126 v->u.rail.cached_weight = weight; |
129 v->u.rail.cached_weight = weight; |
127 |
130 |
128 /* Now update train power (tractive effort is dependent on weight) */ |
131 /* Now update train power (tractive effort is dependent on weight) */ |
129 TrainPowerChanged(v); |
132 TrainPowerChanged(v); |
130 } |
133 } |
149 v->u.rail.compatible_railtypes = 0; |
152 v->u.rail.compatible_railtypes = 0; |
150 |
153 |
151 for (Vehicle *u = v; u != NULL; u = u->next) { |
154 for (Vehicle *u = v; u != NULL; u = u->next) { |
152 const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); |
155 const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); |
153 |
156 |
154 // Update the v->first cache. This is faster than having to brute force it later. |
157 /* Update the v->first cache. This is faster than having to brute force it later. */ |
155 if (u->first == NULL) u->first = v; |
158 if (u->first == NULL) u->first = v; |
156 |
159 |
157 // update the 'first engine' |
160 /* update the 'first engine' */ |
158 u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine; |
161 u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine; |
159 u->u.rail.railtype = rvi_u->railtype; |
162 u->u.rail.railtype = rvi_u->railtype; |
160 |
163 |
161 if (IsTrainEngine(u)) first_engine = u->engine_type; |
164 if (IsTrainEngine(u)) first_engine = u->engine_type; |
162 |
165 |
163 if (rvi_u->visual_effect != 0) { |
166 if (rvi_u->visual_effect != 0) { |
164 u->u.rail.cached_vis_effect = rvi_u->visual_effect; |
167 u->u.rail.cached_vis_effect = rvi_u->visual_effect; |
165 } else { |
168 } else { |
166 if (IsTrainWagon(u) || IsArticulatedPart(u)) { |
169 if (IsTrainWagon(u) || IsArticulatedPart(u)) { |
167 // Wagons and articulated parts have no effect by default |
170 /* Wagons and articulated parts have no effect by default */ |
168 u->u.rail.cached_vis_effect = 0x40; |
171 u->u.rail.cached_vis_effect = 0x40; |
169 } else if (rvi_u->engclass == 0) { |
172 } else if (rvi_u->engclass == 0) { |
170 // Steam is offset by -4 units |
173 /* Steam is offset by -4 units */ |
171 u->u.rail.cached_vis_effect = 4; |
174 u->u.rail.cached_vis_effect = 4; |
172 } else { |
175 } else { |
173 // Diesel fumes and sparks come from the centre |
176 /* Diesel fumes and sparks come from the centre */ |
174 u->u.rail.cached_vis_effect = 8; |
177 u->u.rail.cached_vis_effect = 8; |
175 } |
178 } |
176 } |
179 } |
177 |
180 |
178 if (!IsArticulatedPart(u)) { |
181 if (!IsArticulatedPart(u)) { |
202 if (HASBIT(u->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) { |
205 if (HASBIT(u->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) { |
203 u->u.rail.railtype = RAILTYPE_RAIL; |
206 u->u.rail.railtype = RAILTYPE_RAIL; |
204 u->u.rail.compatible_railtypes |= (1 << RAILTYPE_RAIL); |
207 u->u.rail.compatible_railtypes |= (1 << RAILTYPE_RAIL); |
205 } |
208 } |
206 |
209 |
207 // max speed is the minimum of the speed limits of all vehicles in the consist |
210 /* max speed is the minimum of the speed limits of all vehicles in the consist */ |
208 if ((rvi_u->railveh_type != RAILVEH_WAGON || _patches.wagon_speed_limits) && |
211 if ((rvi_u->railveh_type != RAILVEH_WAGON || _patches.wagon_speed_limits) && |
209 rvi_u->max_speed != 0 && !UsesWagonOverride(u)) |
212 rvi_u->max_speed != 0 && !UsesWagonOverride(u)) |
210 max_speed = min(rvi_u->max_speed, max_speed); |
213 max_speed = min(rvi_u->max_speed, max_speed); |
211 } |
214 } |
212 |
215 |
213 // check the vehicle length (callback) |
216 /* check the vehicle length (callback) */ |
214 uint16 veh_len = CALLBACK_FAILED; |
217 uint16 veh_len = CALLBACK_FAILED; |
215 if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) { |
218 if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) { |
216 veh_len = GetVehicleCallback(CBID_TRAIN_VEHICLE_LENGTH, 0, 0, u->engine_type, u); |
219 veh_len = GetVehicleCallback(CBID_TRAIN_VEHICLE_LENGTH, 0, 0, u->engine_type, u); |
217 } |
220 } |
218 if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor; |
221 if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor; |
219 veh_len = clamp(veh_len, 0, u->next == NULL ? 7 : 5); // the clamp on vehicles not the last in chain is stricter, as too short wagons can break the 'follow next vehicle' code |
222 veh_len = clamp(veh_len, 0, u->next == NULL ? 7 : 5); // the clamp on vehicles not the last in chain is stricter, as too short wagons can break the 'follow next vehicle' code |
220 u->u.rail.cached_veh_length = 8 - veh_len; |
223 u->u.rail.cached_veh_length = 8 - veh_len; |
221 v->u.rail.cached_total_length += u->u.rail.cached_veh_length; |
224 v->u.rail.cached_total_length += u->u.rail.cached_veh_length; |
222 } |
225 } |
223 |
226 |
224 // store consist weight/max speed in cache |
227 /* store consist weight/max speed in cache */ |
225 v->u.rail.cached_max_speed = max_speed; |
228 v->u.rail.cached_max_speed = max_speed; |
226 |
229 |
227 // recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) |
230 /* recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) */ |
228 TrainCargoChanged(v); |
231 TrainCargoChanged(v); |
229 } |
232 } |
230 |
233 |
231 /* These two arrays are used for realistic acceleration. XXX: How should they |
234 /* These two arrays are used for realistic acceleration. XXX: How should they |
232 * be interpreted? */ |
235 * be interpreted? */ |
261 { |
264 { |
262 const Order* o = &v->current_order; |
265 const Order* o = &v->current_order; |
263 StationID sid = GetStationIndex(tile); |
266 StationID sid = GetStationIndex(tile); |
264 |
267 |
265 assert(v->type == VEH_TRAIN); |
268 assert(v->type == VEH_TRAIN); |
266 //When does a train drive through a station |
269 /* When does a train drive through a station |
267 //first we deal with the "new nonstop handling" |
270 * first we deal with the "new nonstop handling" */ |
268 if (_patches.new_nonstop && o->flags & OF_NON_STOP && sid == o->dest) { |
271 if (_patches.new_nonstop && o->flags & OF_NON_STOP && sid == o->dest) { |
269 return false; |
272 return false; |
270 } |
273 } |
271 |
274 |
272 if (v->last_station_visited == sid) return false; |
275 if (v->last_station_visited == sid) return false; |
276 } |
279 } |
277 |
280 |
278 return true; |
281 return true; |
279 } |
282 } |
280 |
283 |
281 //new acceleration |
284 /** new acceleration*/ |
282 static int GetTrainAcceleration(Vehicle *v, bool mode) |
285 static int GetTrainAcceleration(Vehicle *v, bool mode) |
283 { |
286 { |
284 int max_speed = 2000; |
287 int max_speed = 2000; |
285 int speed = v->cur_speed * 10 / 16; //[mph] |
288 int speed = v->cur_speed * 10 / 16; //[mph] |
286 int curvecount[2] = {0, 0}; |
289 int curvecount[2] = {0, 0}; |
287 |
290 |
288 //first find the curve speed limit |
291 /*first find the curve speed limit */ |
289 int numcurve = 0; |
292 int numcurve = 0; |
290 int sum = 0; |
293 int sum = 0; |
291 int pos = 0; |
294 int pos = 0; |
292 int lastpos = -1; |
295 int lastpos = -1; |
293 for (const Vehicle *u = v; u->next != NULL; u = u->next, pos++) { |
296 for (const Vehicle *u = v; u->next != NULL; u = u->next, pos++) { |
533 u->u.rail.railtype = v->u.rail.railtype; |
536 u->u.rail.railtype = v->u.rail.railtype; |
534 u->build_year = v->build_year; |
537 u->build_year = v->build_year; |
535 u->vehstatus = v->vehstatus & ~VS_STOPPED; |
538 u->vehstatus = v->vehstatus & ~VS_STOPPED; |
536 u->u.rail.first_engine = v->engine_type; |
539 u->u.rail.first_engine = v->engine_type; |
537 |
540 |
538 // get more settings from rail vehicle info |
541 /* get more settings from rail vehicle info */ |
539 u->spritenum = rvi_artic->image_index; |
542 u->spritenum = rvi_artic->image_index; |
540 if (flip_image) u->spritenum++; |
543 if (flip_image) u->spritenum++; |
541 u->cargo_type = rvi_artic->cargo_type; |
544 u->cargo_type = rvi_artic->cargo_type; |
542 u->cargo_subtype = 0; |
545 u->cargo_subtype = 0; |
543 u->cargo_cap = rvi_artic->capacity; |
546 u->cargo_cap = rvi_artic->capacity; |
695 VehiclePositionChanged(u); |
698 VehiclePositionChanged(u); |
696 } |
699 } |
697 |
700 |
698 /** Build a railroad vehicle. |
701 /** Build a railroad vehicle. |
699 * @param tile tile of the depot where rail-vehicle is built |
702 * @param tile tile of the depot where rail-vehicle is built |
|
703 * @param flags type of operation |
700 * @param p1 engine type id |
704 * @param p1 engine type id |
701 * @param p2 bit 0 when set, the train will get number 0, otherwise it will get a free number |
705 * @param p2 bit 0 when set, the train will get number 0, otherwise it will get a free number |
702 * bit 1 prevents any free cars from being added to the train |
706 * bit 1 prevents any free cars from being added to the train |
703 */ |
707 */ |
704 int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
708 int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
705 { |
709 { |
706 /* Check if the engine-type is valid (for the player) */ |
710 /* Check if the engine-type is valid (for the player) */ |
707 if (!IsEngineBuildable(p1, VEH_TRAIN, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE); |
711 if (!IsEngineBuildable(p1, VEH_TRAIN, _current_player)) return_cmd_error(STR_RAIL_VEHICLE_NOT_AVAILABLE); |
708 |
712 |
709 /* Check if the train is actually being built in a depot belonging |
713 /* Check if the train is actually being built in a depot belonging |
710 * to the player. Doesn't matter if only the cost is queried */ |
714 * to the player. Doesn't matter if only the cost is queried */ |
711 if (!(flags & DC_QUERY_COST)) { |
715 if (!(flags & DC_QUERY_COST)) { |
712 if (!IsTileDepotType(tile, TRANSPORT_RAIL)) return CMD_ERROR; |
716 if (!IsTileDepotType(tile, TRANSPORT_RAIL)) return CMD_ERROR; |
872 * @param first The first vehicle of the consist. |
876 * @param first The first vehicle of the consist. |
873 * @return The first vehicle of the consist. |
877 * @return The first vehicle of the consist. |
874 */ |
878 */ |
875 static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first) |
879 static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first) |
876 { |
880 { |
877 // unlinking the first vehicle of the chain? |
881 /* unlinking the first vehicle of the chain? */ |
878 if (v == first) { |
882 if (v == first) { |
879 v = GetNextVehicle(v); |
883 v = GetNextVehicle(v); |
880 if (v == NULL) return NULL; |
884 if (v == NULL) return NULL; |
881 |
885 |
882 if (IsTrainWagon(v)) SetFreeWagon(v); |
886 if (IsTrainWagon(v)) SetFreeWagon(v); |
964 |
969 |
965 Vehicle *src = GetVehicle(s); |
970 Vehicle *src = GetVehicle(s); |
966 |
971 |
967 if (src->type != VEH_TRAIN || !CheckOwnership(src->owner)) return CMD_ERROR; |
972 if (src->type != VEH_TRAIN || !CheckOwnership(src->owner)) return CMD_ERROR; |
968 |
973 |
969 // if nothing is selected as destination, try and find a matching vehicle to drag to. |
974 /* if nothing is selected as destination, try and find a matching vehicle to drag to. */ |
970 Vehicle *dst; |
975 Vehicle *dst; |
971 if (d == INVALID_VEHICLE) { |
976 if (d == INVALID_VEHICLE) { |
972 dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src); |
977 dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src); |
973 } else { |
978 } else { |
974 if (!IsValidVehicleID(d)) return CMD_ERROR; |
979 if (!IsValidVehicleID(d)) return CMD_ERROR; |
975 dst = GetVehicle(d); |
980 dst = GetVehicle(d); |
976 if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR; |
981 if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR; |
977 } |
982 } |
978 |
983 |
979 // if an articulated part is being handled, deal with its parent vehicle |
984 /* if an articulated part is being handled, deal with its parent vehicle */ |
980 while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src); |
985 while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src); |
981 if (dst != NULL) { |
986 if (dst != NULL) { |
982 while (IsArticulatedPart(dst)) dst = GetPrevVehicleInChain(dst); |
987 while (IsArticulatedPart(dst)) dst = GetPrevVehicleInChain(dst); |
983 } |
988 } |
984 |
989 |
985 // don't move the same vehicle.. |
990 /* don't move the same vehicle.. */ |
986 if (src == dst) return 0; |
991 if (src == dst) return 0; |
987 |
992 |
988 /* locate the head of the two chains */ |
993 /* locate the head of the two chains */ |
989 Vehicle *src_head = GetFirstVehicleInChain(src); |
994 Vehicle *src_head = GetFirstVehicleInChain(src); |
990 Vehicle *dst_head; |
995 Vehicle *dst_head; |
991 if (dst != NULL) { |
996 if (dst != NULL) { |
992 dst_head = GetFirstVehicleInChain(dst); |
997 dst_head = GetFirstVehicleInChain(dst); |
993 if (dst_head->tile != src_head->tile) return CMD_ERROR; |
998 if (dst_head->tile != src_head->tile) return CMD_ERROR; |
994 // Now deal with articulated part of destination wagon |
999 /* Now deal with articulated part of destination wagon */ |
995 dst = GetLastEnginePart(dst); |
1000 dst = GetLastEnginePart(dst); |
996 } else { |
1001 } else { |
997 dst_head = NULL; |
1002 dst_head = NULL; |
998 } |
1003 } |
999 |
1004 |
1002 if (dst->next == NULL) { |
1007 if (dst->next == NULL) { |
1003 /* It's the last one, so we will add the wagon just before the rear engine */ |
1008 /* It's the last one, so we will add the wagon just before the rear engine */ |
1004 dst = GetPrevVehicleInChain(dst); |
1009 dst = GetPrevVehicleInChain(dst); |
1005 /* Now if the vehicle we want to link to is the vehicle itself, drop out */ |
1010 /* Now if the vehicle we want to link to is the vehicle itself, drop out */ |
1006 if (dst == src) return CMD_ERROR; |
1011 if (dst == src) return CMD_ERROR; |
1007 // if dst is NULL, it means that dst got a rear multiheaded engine as first engine. We can't use that |
1012 /* if dst is NULL, it means that dst got a rear multiheaded engine as first engine. We can't use that */ |
1008 if (dst == NULL) return CMD_ERROR; |
1013 if (dst == NULL) return CMD_ERROR; |
1009 } else { |
1014 } else { |
1010 /* there are more units on this train, so we will add the wagon after the next one*/ |
1015 /* there are more units on this train, so we will add the wagon after the next one*/ |
1011 dst = dst->next; |
1016 dst = dst->next; |
1012 } |
1017 } |
1030 } |
1035 } |
1031 } |
1036 } |
1032 |
1037 |
1033 if (IsMultiheaded(src) && !IsTrainEngine(src)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR); |
1038 if (IsMultiheaded(src) && !IsTrainEngine(src)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR); |
1034 |
1039 |
1035 // when moving all wagons, we can't have the same src_head and dst_head |
1040 /* when moving all wagons, we can't have the same src_head and dst_head */ |
1036 if (HASBIT(p2, 0) && src_head == dst_head) return 0; |
1041 if (HASBIT(p2, 0) && src_head == dst_head) return 0; |
1037 |
1042 |
1038 { |
1043 { |
1039 int max_len = _patches.mammoth_trains ? 100 : 9; |
1044 int max_len = _patches.mammoth_trains ? 100 : 9; |
1040 |
1045 |
1041 // check if all vehicles in the source train are stopped inside a depot. |
1046 /* check if all vehicles in the source train are stopped inside a depot. */ |
1042 int src_len = CheckTrainStoppedInDepot(src_head); |
1047 int src_len = CheckTrainStoppedInDepot(src_head); |
1043 if (src_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1048 if (src_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1044 |
1049 |
1045 // check the destination row if the source and destination aren't the same. |
1050 /* check the destination row if the source and destination aren't the same. */ |
1046 if (src_head != dst_head) { |
1051 if (src_head != dst_head) { |
1047 int dst_len = 0; |
1052 int dst_len = 0; |
1048 |
1053 |
1049 if (dst_head != NULL) { |
1054 if (dst_head != NULL) { |
1050 // check if all vehicles in the dest train are stopped. |
1055 /* check if all vehicles in the dest train are stopped. */ |
1051 dst_len = CheckTrainStoppedInDepot(dst_head); |
1056 dst_len = CheckTrainStoppedInDepot(dst_head); |
1052 if (dst_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1057 if (dst_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1053 } |
1058 } |
1054 |
1059 |
1055 // We are moving between rows, so only count the wagons from the source |
1060 /* We are moving between rows, so only count the wagons from the source |
1056 // row that are being moved. |
1061 * row that are being moved. */ |
1057 if (HASBIT(p2, 0)) { |
1062 if (HASBIT(p2, 0)) { |
1058 const Vehicle *u; |
1063 const Vehicle *u; |
1059 for (u = src_head; u != src && u != NULL; u = GetNextVehicle(u)) |
1064 for (u = src_head; u != src && u != NULL; u = GetNextVehicle(u)) |
1060 src_len--; |
1065 src_len--; |
1061 } else { |
1066 } else { |
1062 // If moving only one vehicle, just count that. |
1067 /* If moving only one vehicle, just count that. */ |
1063 src_len = 1; |
1068 src_len = 1; |
1064 } |
1069 } |
1065 |
1070 |
1066 if (src_len + dst_len > max_len) { |
1071 if (src_len + dst_len > max_len) { |
1067 // Abort if we're adding too many wagons to a train. |
1072 /* Abort if we're adding too many wagons to a train. */ |
1068 if (dst_head != NULL && IsFrontEngine(dst_head)) return_cmd_error(STR_8819_TRAIN_TOO_LONG); |
1073 if (dst_head != NULL && IsFrontEngine(dst_head)) return_cmd_error(STR_8819_TRAIN_TOO_LONG); |
1069 // Abort if we're making a train on a new row. |
1074 /* Abort if we're making a train on a new row. */ |
1070 if (dst_head == NULL && IsTrainEngine(src)) return_cmd_error(STR_8819_TRAIN_TOO_LONG); |
1075 if (dst_head == NULL && IsTrainEngine(src)) return_cmd_error(STR_8819_TRAIN_TOO_LONG); |
1071 } |
1076 } |
1072 } else { |
1077 } else { |
1073 // Abort if we're creating a new train on an existing row. |
1078 /* Abort if we're creating a new train on an existing row. */ |
1074 if (src_len > max_len && src == src_head && IsTrainEngine(GetNextVehicle(src_head))) |
1079 if (src_len > max_len && src == src_head && IsTrainEngine(GetNextVehicle(src_head))) |
1075 return_cmd_error(STR_8819_TRAIN_TOO_LONG); |
1080 return_cmd_error(STR_8819_TRAIN_TOO_LONG); |
1076 } |
1081 } |
1077 } |
1082 } |
1078 |
1083 |
1079 // moving a loco to a new line?, then we need to assign a unitnumber. |
1084 /* moving a loco to a new line?, then we need to assign a unitnumber. */ |
1080 if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) { |
1085 if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) { |
1081 UnitID unit_num = GetFreeUnitNumber(VEH_TRAIN); |
1086 UnitID unit_num = GetFreeUnitNumber(VEH_TRAIN); |
1082 if (unit_num > _patches.max_trains) |
1087 if (unit_num > _patches.max_trains) |
1083 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
1088 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
1084 |
1089 |
1102 /* clear the ->first cache */ |
1107 /* clear the ->first cache */ |
1103 for (Vehicle *u = src_head; u != NULL; u = u->next) u->first = NULL; |
1108 for (Vehicle *u = src_head; u != NULL; u = u->next) u->first = NULL; |
1104 for (Vehicle *u = dst_head; u != NULL; u = u->next) u->first = NULL; |
1109 for (Vehicle *u = dst_head; u != NULL; u = u->next) u->first = NULL; |
1105 |
1110 |
1106 if (HASBIT(p2, 0)) { |
1111 if (HASBIT(p2, 0)) { |
1107 // unlink ALL wagons |
1112 /* unlink ALL wagons */ |
1108 if (src != src_head) { |
1113 if (src != src_head) { |
1109 Vehicle *v = src_head; |
1114 Vehicle *v = src_head; |
1110 while (GetNextVehicle(v) != src) v = GetNextVehicle(v); |
1115 while (GetNextVehicle(v) != src) v = GetNextVehicle(v); |
1111 GetLastEnginePart(v)->next = NULL; |
1116 GetLastEnginePart(v)->next = NULL; |
1112 } else { |
1117 } else { |
1113 InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line |
1118 InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line |
1114 src_head = NULL; |
1119 src_head = NULL; |
1115 } |
1120 } |
1116 } else { |
1121 } else { |
1117 // if moving within the same chain, dont use dst_head as it may get invalidated |
1122 /* if moving within the same chain, dont use dst_head as it may get invalidated */ |
1118 if (src_head == dst_head) dst_head = NULL; |
1123 if (src_head == dst_head) dst_head = NULL; |
1119 // unlink single wagon from linked list |
1124 /* unlink single wagon from linked list */ |
1120 src_head = UnlinkWagon(src, src_head); |
1125 src_head = UnlinkWagon(src, src_head); |
1121 GetLastEnginePart(src)->next = NULL; |
1126 GetLastEnginePart(src)->next = NULL; |
1122 } |
1127 } |
1123 |
1128 |
1124 if (dst == NULL) { |
1129 if (dst == NULL) { |
1125 /* We make a new line in the depot, so we know already that we invalidate the window data */ |
1130 /* We make a new line in the depot, so we know already that we invalidate the window data */ |
1126 InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile); |
1131 InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile); |
1127 |
1132 |
1128 // move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4. |
1133 /* move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4. */ |
1129 if (IsTrainEngine(src)) { |
1134 if (IsTrainEngine(src)) { |
1130 if (!IsFrontEngine(src)) { |
1135 if (!IsFrontEngine(src)) { |
1131 // setting the type to 0 also involves setting up the orders field. |
1136 /* setting the type to 0 also involves setting up the orders field. */ |
1132 SetFrontEngine(src); |
1137 SetFrontEngine(src); |
1133 assert(src->orders == NULL); |
1138 assert(src->orders == NULL); |
1134 src->num_orders = 0; |
1139 src->num_orders = 0; |
1135 } |
1140 } |
1136 } else { |
1141 } else { |
1137 SetFreeWagon(src); |
1142 SetFreeWagon(src); |
1138 } |
1143 } |
1139 dst_head = src; |
1144 dst_head = src; |
1140 } else { |
1145 } else { |
1141 if (IsFrontEngine(src)) { |
1146 if (IsFrontEngine(src)) { |
1142 // the vehicle was previously a loco. need to free the order list and delete vehicle windows etc. |
1147 /* the vehicle was previously a loco. need to free the order list and delete vehicle windows etc. */ |
1143 DeleteWindowById(WC_VEHICLE_VIEW, src->index); |
1148 DeleteWindowById(WC_VEHICLE_VIEW, src->index); |
1144 DeleteVehicleOrders(src); |
1149 DeleteVehicleOrders(src); |
1145 } |
1150 } |
1146 |
1151 |
1147 if (IsFrontEngine(src) || IsFreeWagon(src)) { |
1152 if (IsFrontEngine(src) || IsFreeWagon(src)) { |
1163 if (src->u.rail.other_multiheaded_part != NULL) { |
1168 if (src->u.rail.other_multiheaded_part != NULL) { |
1164 if (src->u.rail.other_multiheaded_part == src_head) { |
1169 if (src->u.rail.other_multiheaded_part == src_head) { |
1165 src_head = src_head->next; |
1170 src_head = src_head->next; |
1166 } |
1171 } |
1167 AddWagonToConsist(src->u.rail.other_multiheaded_part, src); |
1172 AddWagonToConsist(src->u.rail.other_multiheaded_part, src); |
1168 // previous line set the front engine to the old front. We need to clear that |
1173 /* previous line set the front engine to the old front. We need to clear that */ |
1169 src->u.rail.other_multiheaded_part->first = NULL; |
1174 src->u.rail.other_multiheaded_part->first = NULL; |
1170 } |
1175 } |
1171 |
1176 |
1172 if (HASBIT(p2, 0) && src_head != NULL && src_head != src) { |
1177 if (HASBIT(p2, 0) && src_head != NULL && src_head != src) { |
1173 /* if we stole a rear multiheaded engine, we better give it back to the front end */ |
1178 /* if we stole a rear multiheaded engine, we better give it back to the front end */ |
1267 return 0; |
1273 return 0; |
1268 } |
1274 } |
1269 |
1275 |
1270 /** Sell a (single) train wagon/engine. |
1276 /** Sell a (single) train wagon/engine. |
1271 * @param tile unused |
1277 * @param tile unused |
|
1278 * @param flags type of operation |
1272 * @param p1 the wagon/engine index |
1279 * @param p1 the wagon/engine index |
1273 * @param p2 the selling mode |
1280 * @param p2 the selling mode |
1274 * - p2 = 0: only sell the single dragged wagon/engine (and any belonging rear-engines) |
1281 * - p2 = 0: only sell the single dragged wagon/engine (and any belonging rear-engines) |
1275 * - p2 = 1: sell the vehicle and all vehicles following it in the chain |
1282 * - p2 = 1: sell the vehicle and all vehicles following it in the chain |
1276 if the wagon is dragged, don't delete the possibly belonging rear-engine to some front |
1283 if the wagon is dragged, don't delete the possibly belonging rear-engine to some front |
1288 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1295 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1289 |
1296 |
1290 while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v); |
1297 while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v); |
1291 Vehicle *first = GetFirstVehicleInChain(v); |
1298 Vehicle *first = GetFirstVehicleInChain(v); |
1292 |
1299 |
1293 // make sure the vehicle is stopped in the depot |
1300 /* make sure the vehicle is stopped in the depot */ |
1294 if (CheckTrainStoppedInDepot(first) < 0) { |
1301 if (CheckTrainStoppedInDepot(first) < 0) { |
1295 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1302 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1296 } |
1303 } |
1297 |
1304 |
1298 if (IsMultiheaded(v) && !IsTrainEngine(v)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR); |
1305 if (IsMultiheaded(v) && !IsTrainEngine(v)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR); |
1594 Vehicle *base = v; |
1601 Vehicle *base = v; |
1595 Vehicle *first = base->next; |
1602 Vehicle *first = base->next; |
1596 uint length = CountVehiclesInChain(v); |
1603 uint length = CountVehiclesInChain(v); |
1597 |
1604 |
1598 while (length > 2) { |
1605 while (length > 2) { |
1599 // find pairwise matching wagon |
1606 /* find pairwise matching wagon |
1600 // start<>end, start+1<>end-1, ... |
1607 * start<>end, start+1<>end-1, ... */ |
1601 Vehicle *last = first; |
1608 Vehicle *last = first; |
1602 for (uint i = length - 3; i > 0; i--) last = last->next; |
1609 for (uint i = length - 3; i > 0; i--) last = last->next; |
1603 |
1610 |
1604 int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length; |
1611 int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length; |
1605 if (before) differential *= -1; |
1612 if (before) differential *= -1; |
1606 |
1613 |
1607 if (differential > 0) { |
1614 if (differential > 0) { |
1608 // disconnect last car to make sure only this subset moves |
1615 /* disconnect last car to make sure only this subset moves */ |
1609 Vehicle *tempnext = last->next; |
1616 Vehicle *tempnext = last->next; |
1610 last->next = NULL; |
1617 last->next = NULL; |
1611 |
1618 |
1612 for (int i = 0; i < differential; i++) TrainController(first, false); |
1619 for (int i = 0; i < differential; i++) TrainController(first, false); |
1613 |
1620 |
1665 CLRBIT(v->u.rail.flags, VRF_REVERSING); |
1672 CLRBIT(v->u.rail.flags, VRF_REVERSING); |
1666 } |
1673 } |
1667 |
1674 |
1668 /** Reverse train. |
1675 /** Reverse train. |
1669 * @param tile unused |
1676 * @param tile unused |
|
1677 * @param flags type of operation |
1670 * @param p1 train to reverse |
1678 * @param p1 train to reverse |
1671 * @param p2 if true, reverse a unit in a train (needs to be in a depot) |
1679 * @param p2 if true, reverse a unit in a train (needs to be in a depot) |
1672 */ |
1680 */ |
1673 int32 CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1681 int32 CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1674 { |
1682 { |
1677 Vehicle *v = GetVehicle(p1); |
1685 Vehicle *v = GetVehicle(p1); |
1678 |
1686 |
1679 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1687 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1680 |
1688 |
1681 if (p2) { |
1689 if (p2) { |
1682 // turn a single unit around |
1690 /* turn a single unit around */ |
1683 |
1691 |
1684 if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) { |
1692 if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) { |
1685 return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT); |
1693 return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT); |
1686 } |
1694 } |
1687 |
1695 |
1688 Vehicle *front = GetFirstVehicleInChain(v); |
1696 Vehicle *front = GetFirstVehicleInChain(v); |
1689 // make sure the vehicle is stopped in the depot |
1697 /* make sure the vehicle is stopped in the depot */ |
1690 if (CheckTrainStoppedInDepot(front) < 0) { |
1698 if (CheckTrainStoppedInDepot(front) < 0) { |
1691 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1699 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1692 } |
1700 } |
1693 |
1701 |
1694 if (flags & DC_EXEC) { |
1702 if (flags & DC_EXEC) { |
1695 TOGGLEBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION); |
1703 TOGGLEBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION); |
1696 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
1704 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
1697 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
1705 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
1698 } |
1706 } |
1699 } else { |
1707 } else { |
1700 //turn the whole train around |
1708 /*turn the whole train around */ |
1701 if (v->u.rail.crash_anim_pos != 0 || v->breakdown_ctr != 0) return CMD_ERROR; |
1709 if (v->u.rail.crash_anim_pos != 0 || v->breakdown_ctr != 0) return CMD_ERROR; |
1702 |
1710 |
1703 if (flags & DC_EXEC) { |
1711 if (flags & DC_EXEC) { |
1704 if (_patches.realistic_acceleration && v->cur_speed != 0) { |
1712 if (_patches.realistic_acceleration && v->cur_speed != 0) { |
1705 TOGGLEBIT(v->u.rail.flags, VRF_REVERSING); |
1713 TOGGLEBIT(v->u.rail.flags, VRF_REVERSING); |
1891 * is removed. */ |
1901 * is removed. */ |
1892 tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH; |
1902 tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH; |
1893 if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true; |
1903 if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true; |
1894 } |
1904 } |
1895 } else { |
1905 } else { |
1896 // search in the forward direction first. |
1906 /* search in the forward direction first. */ |
1897 DiagDirection i = DirToDiagDir(v->direction); |
1907 DiagDirection i = DirToDiagDir(v->direction); |
1898 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { |
1908 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { |
1899 i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT); |
1909 i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT); |
1900 } |
1910 } |
1901 NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); |
1911 NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); |
1902 if (tfdd.best_length == (uint)-1){ |
1912 if (tfdd.best_length == (uint)-1){ |
1903 tfdd.reverse = true; |
1913 tfdd.reverse = true; |
1904 // search in backwards direction |
1914 /* search in backwards direction */ |
1905 i = ReverseDiagDir(DirToDiagDir(v->direction)); |
1915 i = ReverseDiagDir(DirToDiagDir(v->direction)); |
1906 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { |
1916 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { |
1907 i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT); |
1917 i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT); |
1908 } |
1918 } |
1909 NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); |
1919 NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); |
2008 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); |
2019 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); |
2009 int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8; |
2020 int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8; |
2010 byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2); |
2021 byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2); |
2011 bool disable_effect = HASBIT(v->u.rail.cached_vis_effect, 6); |
2022 bool disable_effect = HASBIT(v->u.rail.cached_vis_effect, 6); |
2012 |
2023 |
2013 // no smoke? |
2024 /* no smoke? */ |
2014 if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) || |
2025 if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) || |
2015 disable_effect || |
2026 disable_effect || |
2016 rvi->railtype > RAILTYPE_ELECTRIC || |
2027 rvi->railtype > RAILTYPE_ELECTRIC || |
2017 v->vehstatus & VS_HIDDEN) { |
2028 v->vehstatus & VS_HIDDEN) { |
2018 continue; |
2029 continue; |
2019 } |
2030 } |
2020 |
2031 |
2021 // No smoke in depots or tunnels |
2032 /* No smoke in depots or tunnels */ |
2022 if (IsTileDepotType(v->tile, TRANSPORT_RAIL) || IsTunnelTile(v->tile)) continue; |
2033 if (IsTileDepotType(v->tile, TRANSPORT_RAIL) || IsTunnelTile(v->tile)) continue; |
2023 |
2034 |
2024 // No sparks for electric vehicles on nonelectrified tracks |
2035 /* No sparks for electric vehicles on nonelectrified tracks */ |
2025 if (!HasPowerOnRail(v->u.rail.railtype, GetTileRailType(v->tile))) continue; |
2036 if (!HasPowerOnRail(v->u.rail.railtype, GetTileRailType(v->tile))) continue; |
2026 |
2037 |
2027 if (effect_type == 0) { |
2038 if (effect_type == 0) { |
2028 // Use default effect type for engine class. |
2039 /* Use default effect type for engine class. */ |
2029 effect_type = rvi->engclass; |
2040 effect_type = rvi->engclass; |
2030 } else { |
2041 } else { |
2031 effect_type--; |
2042 effect_type--; |
2032 } |
2043 } |
2033 |
2044 |
2039 y = -y; |
2050 y = -y; |
2040 } |
2051 } |
2041 |
2052 |
2042 switch (effect_type) { |
2053 switch (effect_type) { |
2043 case 0: |
2054 case 0: |
2044 // steam smoke. |
2055 /* steam smoke. */ |
2045 if (GB(v->tick_counter, 0, 4) == 0) { |
2056 if (GB(v->tick_counter, 0, 4) == 0) { |
2046 CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE); |
2057 CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE); |
2047 sound = true; |
2058 sound = true; |
2048 } |
2059 } |
2049 break; |
2060 break; |
2050 |
2061 |
2051 case 1: |
2062 case 1: |
2052 // diesel smoke |
2063 /* diesel smoke */ |
2053 if (u->cur_speed <= 40 && CHANCE16(15, 128)) { |
2064 if (u->cur_speed <= 40 && CHANCE16(15, 128)) { |
2054 CreateEffectVehicleRel(v, 0, 0, 10, EV_DIESEL_SMOKE); |
2065 CreateEffectVehicleRel(v, 0, 0, 10, EV_DIESEL_SMOKE); |
2055 sound = true; |
2066 sound = true; |
2056 } |
2067 } |
2057 break; |
2068 break; |
2058 |
2069 |
2059 case 2: |
2070 case 2: |
2060 // blue spark |
2071 /* blue spark */ |
2061 if (GB(v->tick_counter, 0, 2) == 0 && CHANCE16(1, 45)) { |
2072 if (GB(v->tick_counter, 0, 2) == 0 && CHANCE16(1, 45)) { |
2062 CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK); |
2073 CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK); |
2063 sound = true; |
2074 sound = true; |
2064 } |
2075 } |
2065 break; |
2076 break; |
2092 } |
2103 } |
2093 } |
2104 } |
2094 |
2105 |
2095 static bool CheckTrainStayInDepot(Vehicle *v) |
2106 static bool CheckTrainStayInDepot(Vehicle *v) |
2096 { |
2107 { |
2097 // bail out if not all wagons are in the same depot or not in a depot at all |
2108 /* bail out if not all wagons are in the same depot or not in a depot at all */ |
2098 for (const Vehicle *u = v; u != NULL; u = u->next) { |
2109 for (const Vehicle *u = v; u != NULL; u = u->next) { |
2099 if (u->u.rail.track != TRACK_BIT_DEPOT || u->tile != v->tile) return false; |
2110 if (u->u.rail.track != TRACK_BIT_DEPOT || u->tile != v->tile) return false; |
2100 } |
2111 } |
2101 |
2112 |
2102 // if the train got no power, then keep it in the depot |
2113 /* if the train got no power, then keep it in the depot */ |
2103 if (v->u.rail.cached_power == 0) { |
2114 if (v->u.rail.cached_power == 0) { |
2104 v->vehstatus |= VS_STOPPED; |
2115 v->vehstatus |= VS_STOPPED; |
2105 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
2116 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
2106 return true; |
2117 return true; |
2107 } |
2118 } |
2149 TrackdirByte best_track; |
2160 TrackdirByte best_track; |
2150 }; |
2161 }; |
2151 |
2162 |
2152 static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, Trackdir track, uint length) |
2163 static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, Trackdir track, uint length) |
2153 { |
2164 { |
2154 // heading for nowhere? |
2165 /* heading for nowhere? */ |
2155 if (ttfd->dest_coords == 0) return false; |
2166 if (ttfd->dest_coords == 0) return false; |
2156 |
2167 |
2157 // did we reach the final station? |
2168 /* did we reach the final station? */ |
2158 if ((ttfd->station_index == INVALID_STATION && tile == ttfd->dest_coords) || ( |
2169 if ((ttfd->station_index == INVALID_STATION && tile == ttfd->dest_coords) || ( |
2159 IsTileType(tile, MP_STATION) && |
2170 IsTileType(tile, MP_STATION) && |
2160 IsRailwayStation(tile) && |
2171 IsRailwayStation(tile) && |
2161 GetStationIndex(tile) == ttfd->station_index |
2172 GetStationIndex(tile) == ttfd->station_index |
2162 )) { |
2173 )) { |
2163 /* We do not check for dest_coords if we have a station_index, |
2174 /* We do not check for dest_coords if we have a station_index, |
2164 * because in that case the dest_coords are just an |
2175 * because in that case the dest_coords are just an |
2165 * approximation of where the station is */ |
2176 * approximation of where the station is */ |
2166 // found station |
2177 |
|
2178 /* found station */ |
2167 ttfd->best_track = track; |
2179 ttfd->best_track = track; |
2168 ttfd->best_bird_dist = 0; |
2180 ttfd->best_bird_dist = 0; |
2169 return true; |
2181 return true; |
2170 } else { |
2182 } else { |
2171 // didn't find station, keep track of the best path so far. |
2183 /* didn't find station, keep track of the best path so far. */ |
2172 uint dist = DistanceManhattan(tile, ttfd->dest_coords); |
2184 uint dist = DistanceManhattan(tile, ttfd->dest_coords); |
2173 if (dist < ttfd->best_bird_dist) { |
2185 if (dist < ttfd->best_bird_dist) { |
2174 ttfd->best_bird_dist = dist; |
2186 ttfd->best_bird_dist = dist; |
2175 ttfd->best_track = track; |
2187 ttfd->best_track = track; |
2176 } |
2188 } |
2203 0x05200520, |
2215 0x05200520, |
2204 0x2A002A00, |
2216 0x2A002A00, |
2205 }; |
2217 }; |
2206 |
2218 |
2207 static const byte _search_directions[6][4] = { |
2219 static const byte _search_directions[6][4] = { |
2208 { 0, 9, 2, 9 }, // track 1 |
2220 { 0, 9, 2, 9 }, ///< track 1 |
2209 { 9, 1, 9, 3 }, // track 2 |
2221 { 9, 1, 9, 3 }, ///< track 2 |
2210 { 9, 0, 3, 9 }, // track upper |
2222 { 9, 0, 3, 9 }, ///< track upper |
2211 { 1, 9, 9, 2 }, // track lower |
2223 { 1, 9, 9, 2 }, ///< track lower |
2212 { 3, 2, 9, 9 }, // track left |
2224 { 3, 2, 9, 9 }, ///< track left |
2213 { 9, 9, 1, 0 }, // track right |
2225 { 9, 9, 1, 0 }, ///< track right |
2214 }; |
2226 }; |
2215 |
2227 |
2216 static const byte _pick_track_table[6] = {1, 3, 2, 2, 0, 0}; |
2228 static const byte _pick_track_table[6] = {1, 3, 2, 2, 0, 0}; |
2217 |
2229 |
2218 /* choose a track */ |
2230 /* choose a track */ |
2219 static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks) |
2231 static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks) |
2220 { |
2232 { |
2221 Track best_track; |
2233 Track best_track; |
2222 // pathfinders are able to tell that route was only 'guessed' |
2234 /* pathfinders are able to tell that route was only 'guessed' */ |
2223 bool path_not_found = false; |
2235 bool path_not_found = false; |
2224 |
2236 |
2225 #ifdef PF_BENCHMARK |
2237 #ifdef PF_BENCHMARK |
2226 TIC() |
2238 TIC() |
2227 #endif |
2239 #endif |
2248 assert(trackdir != 0xff); |
2260 assert(trackdir != 0xff); |
2249 |
2261 |
2250 NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes); |
2262 NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes); |
2251 |
2263 |
2252 if (ftd.best_trackdir == 0xff) { |
2264 if (ftd.best_trackdir == 0xff) { |
2253 /* We are already at our target. Just do something */ |
2265 /* We are already at our target. Just do something |
2254 //TODO: maybe display error? |
2266 * @todo maybe display error? |
2255 //TODO: go straight ahead if possible? |
2267 * @todo: go straight ahead if possible? */ |
2256 best_track = FindFirstTrack(tracks); |
2268 best_track = FindFirstTrack(tracks); |
2257 } else { |
2269 } else { |
2258 /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains |
2270 /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains |
2259 the direction we need to take to get there, if ftd.best_bird_dist is not 0, |
2271 the direction we need to take to get there, if ftd.best_bird_dist is not 0, |
2260 we did not find our target, but ftd.best_trackdir contains the direction leading |
2272 we did not find our target, but ftd.best_trackdir contains the direction leading |
2278 fd.best_track = INVALID_TRACKDIR; |
2290 fd.best_track = INVALID_TRACKDIR; |
2279 |
2291 |
2280 NewTrainPathfind(tile - TileOffsByDiagDir(enterdir), v->dest_tile, |
2292 NewTrainPathfind(tile - TileOffsByDiagDir(enterdir), v->dest_tile, |
2281 v->u.rail.compatible_railtypes, enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd); |
2293 v->u.rail.compatible_railtypes, enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd); |
2282 |
2294 |
2283 // check whether the path was found or only 'guessed' |
2295 /* check whether the path was found or only 'guessed' */ |
2284 if (fd.best_bird_dist != 0) path_not_found = true; |
2296 if (fd.best_bird_dist != 0) path_not_found = true; |
2285 |
2297 |
2286 if (fd.best_track == 0xff) { |
2298 if (fd.best_track == 0xff) { |
2287 // blaha |
2299 /* blaha */ |
2288 best_track = FindFirstTrack(tracks); |
2300 best_track = FindFirstTrack(tracks); |
2289 } else { |
2301 } else { |
2290 best_track = TrackdirToTrack(fd.best_track); |
2302 best_track = TrackdirToTrack(fd.best_track); |
2291 } |
2303 } |
2292 |
2304 |
2293 int time = NpfEndInterval(perf); |
2305 int time = NpfEndInterval(perf); |
2294 DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0); |
2306 DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0); |
2295 } |
2307 } |
2296 // handle "path not found" state |
2308 /* handle "path not found" state */ |
2297 if (path_not_found) { |
2309 if (path_not_found) { |
2298 // PF didn't find the route |
2310 /* PF didn't find the route */ |
2299 if (!HASBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) { |
2311 if (!HASBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) { |
2300 // it is first time the problem occurred, set the "path not found" flag |
2312 /* it is first time the problem occurred, set the "path not found" flag */ |
2301 SETBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION); |
2313 SETBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION); |
2302 // and notify user about the event |
2314 /* and notify user about the event */ |
2303 if (_patches.lost_train_warn && v->owner == _local_player) { |
2315 if (_patches.lost_train_warn && v->owner == _local_player) { |
2304 SetDParam(0, v->unitnumber); |
2316 SetDParam(0, v->unitnumber); |
2305 AddNewsItem( |
2317 AddNewsItem( |
2306 STR_TRAIN_IS_LOST, |
2318 STR_TRAIN_IS_LOST, |
2307 NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), |
2319 NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), |
2308 v->index, |
2320 v->index, |
2309 0); |
2321 0); |
2310 } |
2322 } |
2311 } |
2323 } |
2312 } else { |
2324 } else { |
2313 // route found, is the train marked with "path not found" flag? |
2325 /* route found, is the train marked with "path not found" flag? */ |
2314 if (HASBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) { |
2326 if (HASBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) { |
2315 // clear the flag as the PF's problem was solved |
2327 /* clear the flag as the PF's problem was solved */ |
2316 CLRBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION); |
2328 CLRBIT(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION); |
2317 // can we also delete the "News" item somehow? |
2329 /* can we also delete the "News" item somehow? */ |
2318 } |
2330 } |
2319 } |
2331 } |
2320 |
2332 |
2321 #ifdef PF_BENCHMARK |
2333 #ifdef PF_BENCHMARK |
2322 TOC("PF time = ", 1) |
2334 TOC("PF time = ", 1) |
2438 return false; |
2450 return false; |
2439 |
2451 |
2440 default: break; |
2452 default: break; |
2441 } |
2453 } |
2442 |
2454 |
2443 // check if we've reached the waypoint? |
2455 /* check if we've reached the waypoint? */ |
2444 bool at_waypoint = false; |
2456 bool at_waypoint = false; |
2445 if (v->current_order.type == OT_GOTO_WAYPOINT && v->tile == v->dest_tile) { |
2457 if (v->current_order.type == OT_GOTO_WAYPOINT && v->tile == v->dest_tile) { |
2446 v->cur_order_index++; |
2458 v->cur_order_index++; |
2447 at_waypoint = true; |
2459 at_waypoint = true; |
2448 } |
2460 } |
2449 |
2461 |
2450 // check if we've reached a non-stop station while TTDPatch nonstop is enabled.. |
2462 /* check if we've reached a non-stop station while TTDPatch nonstop is enabled.. */ |
2451 if (_patches.new_nonstop && |
2463 if (_patches.new_nonstop && |
2452 v->current_order.flags & OF_NON_STOP && |
2464 v->current_order.flags & OF_NON_STOP && |
2453 IsTileType(v->tile, MP_STATION) && |
2465 IsTileType(v->tile, MP_STATION) && |
2454 v->current_order.dest == GetStationIndex(v->tile)) { |
2466 v->current_order.dest == GetStationIndex(v->tile)) { |
2455 v->cur_order_index++; |
2467 v->cur_order_index++; |
2456 } |
2468 } |
2457 |
2469 |
2458 // Get the current order |
2470 /* Get the current order */ |
2459 if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; |
2471 if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; |
2460 |
2472 |
2461 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
2473 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
2462 |
2474 |
2463 // If no order, do nothing. |
2475 /* If no order, do nothing. */ |
2464 if (order == NULL) { |
2476 if (order == NULL) { |
2465 v->current_order.Free(); |
2477 v->current_order.Free(); |
2466 v->dest_tile = 0; |
2478 v->dest_tile = 0; |
2467 return false; |
2479 return false; |
2468 } |
2480 } |
2469 |
2481 |
2470 // If it is unchanged, keep it. |
2482 /* If it is unchanged, keep it. */ |
2471 if (order->type == v->current_order.type && |
2483 if (order->type == v->current_order.type && |
2472 order->flags == v->current_order.flags && |
2484 order->flags == v->current_order.flags && |
2473 order->dest == v->current_order.dest) |
2485 order->dest == v->current_order.dest) |
2474 return false; |
2486 return false; |
2475 |
2487 |
2476 // Otherwise set it, and determine the destination tile. |
2488 /* Otherwise set it, and determine the destination tile. */ |
2477 v->current_order = *order; |
2489 v->current_order = *order; |
2478 |
2490 |
2479 v->dest_tile = 0; |
2491 v->dest_tile = 0; |
2480 |
2492 |
2481 InvalidateVehicleOrder(v); |
2493 InvalidateVehicleOrder(v); |
2514 { |
2526 { |
2515 switch (v->current_order.type) { |
2527 switch (v->current_order.type) { |
2516 case OT_LOADING: { |
2528 case OT_LOADING: { |
2517 if (mode) return; |
2529 if (mode) return; |
2518 |
2530 |
2519 // don't mark the train as lost if we're loading on the final station. |
2531 /* don't mark the train as lost if we're loading on the final station. */ |
2520 if (v->current_order.flags & OF_NON_STOP) { |
2532 if (v->current_order.flags & OF_NON_STOP) { |
2521 v->u.rail.days_since_order_progr = 0; |
2533 v->u.rail.days_since_order_progr = 0; |
2522 } |
2534 } |
2523 |
2535 |
2524 if (--v->load_unload_time_rem) return; |
2536 if (--v->load_unload_time_rem) return; |
2525 |
2537 |
2526 if (CanFillVehicle(v) && ( |
2538 if (CanFillVehicle(v) && ( |
2527 v->current_order.flags & OF_FULL_LOAD || |
2539 v->current_order.flags & OF_FULL_LOAD || |
2528 (_patches.gradual_loading && !HASBIT(v->vehicle_flags, VF_LOADING_FINISHED)) |
2540 (_patches.gradual_loading && !HASBIT(v->vehicle_flags, VF_LOADING_FINISHED)) |
2529 )) { |
2541 )) { |
2530 v->u.rail.days_since_order_progr = 0; /* Prevent a train lost message for full loading trains */ |
2542 v->u.rail.days_since_order_progr = 0; // Prevent a train lost message for full loading trains |
2531 SET_EXPENSES_TYPE(EXPENSES_TRAIN_INC); |
2543 SET_EXPENSES_TYPE(EXPENSES_TRAIN_INC); |
2532 if (LoadUnloadVehicle(v, false)) { |
2544 if (LoadUnloadVehicle(v, false)) { |
2533 InvalidateWindow(WC_TRAINS_LIST, v->owner); |
2545 InvalidateWindow(WC_TRAINS_LIST, v->owner); |
2534 MarkTrainDirty(v); |
2546 MarkTrainDirty(v); |
2535 |
2547 |
2536 // need to update acceleration and cached values since the goods on the train changed. |
2548 /* need to update acceleration and cached values since the goods on the train changed. */ |
2537 TrainCargoChanged(v); |
2549 TrainCargoChanged(v); |
2538 UpdateTrainAcceleration(v); |
2550 UpdateTrainAcceleration(v); |
2539 } |
2551 } |
2540 return; |
2552 return; |
2541 } |
2553 } |
2612 v->index, |
2624 v->index, |
2613 0 |
2625 0 |
2614 ); |
2626 ); |
2615 } |
2627 } |
2616 |
2628 |
2617 // Did we reach the final destination? |
2629 /* Did we reach the final destination? */ |
2618 if (v->current_order.type == OT_GOTO_STATION && |
2630 if (v->current_order.type == OT_GOTO_STATION && |
2619 v->current_order.dest == station) { |
2631 v->current_order.dest == station) { |
2620 // Yeah, keep the load/unload flags |
2632 /* Yeah, keep the load/unload flags |
2621 // Non Stop now means if the order should be increased. |
2633 * Non Stop now means if the order should be increased. */ |
2622 v->BeginLoading(); |
2634 v->BeginLoading(); |
2623 v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER; |
2635 v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER; |
2624 v->current_order.flags |= OF_NON_STOP; |
2636 v->current_order.flags |= OF_NON_STOP; |
2625 } else { |
2637 } else { |
2626 // No, just do a simple load |
2638 /* No, just do a simple load */ |
2627 v->BeginLoading(); |
2639 v->BeginLoading(); |
2628 v->current_order.flags = 0; |
2640 v->current_order.flags = 0; |
2629 } |
2641 } |
2630 v->current_order.dest = 0; |
2642 v->current_order.dest = 0; |
2631 |
2643 |
2652 CLRBIT(v->u.rail.flags, VRF_GOINGDOWN); |
2664 CLRBIT(v->u.rail.flags, VRF_GOINGDOWN); |
2653 |
2665 |
2654 if (new_z != old_z) { |
2666 if (new_z != old_z) { |
2655 TileIndex tile = TileVirtXY(v->x_pos, v->y_pos); |
2667 TileIndex tile = TileVirtXY(v->x_pos, v->y_pos); |
2656 |
2668 |
2657 // XXX workaround, whole UP/DOWN detection needs overhaul |
2669 /* XXX workaround, whole UP/DOWN detection needs overhaul */ |
2658 if (!IsTunnelTile(tile)) { |
2670 if (!IsTunnelTile(tile)) { |
2659 SETBIT(v->u.rail.flags, (new_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN); |
2671 SETBIT(v->u.rail.flags, (new_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN); |
2660 } |
2672 } |
2661 } |
2673 } |
2662 } |
2674 } |
2725 byte z_down; // fraction to remove when moving down |
2737 byte z_down; // fraction to remove when moving down |
2726 }; |
2738 }; |
2727 |
2739 |
2728 static const RailtypeSlowdownParams _railtype_slowdown[] = { |
2740 static const RailtypeSlowdownParams _railtype_slowdown[] = { |
2729 // normal accel |
2741 // normal accel |
2730 {256 / 4, 256 / 2, 256 / 4, 2}, // normal |
2742 {256 / 4, 256 / 2, 256 / 4, 2}, ///< normal |
2731 {256 / 4, 256 / 2, 256 / 4, 2}, // electrified |
2743 {256 / 4, 256 / 2, 256 / 4, 2}, ///< electrified |
2732 {256 / 4, 256 / 2, 256 / 4, 2}, // monorail |
2744 {256 / 4, 256 / 2, 256 / 4, 2}, ///< monorail |
2733 {0, 256 / 2, 256 / 4, 2}, // maglev |
2745 {0, 256 / 2, 256 / 4, 2}, ///< maglev |
2734 }; |
2746 }; |
2735 |
2747 |
2736 /* Modify the speed of the vehicle due to a turn */ |
2748 /** Modify the speed of the vehicle due to a turn */ |
2737 static void AffectSpeedByDirChange(Vehicle* v, Direction new_dir) |
2749 static void AffectSpeedByDirChange(Vehicle* v, Direction new_dir) |
2738 { |
2750 { |
2739 if (_patches.realistic_acceleration) return; |
2751 if (_patches.realistic_acceleration) return; |
2740 |
2752 |
2741 DirDiff diff = DirDifference(v->direction, new_dir); |
2753 DirDiff diff = DirDifference(v->direction, new_dir); |
2743 |
2755 |
2744 const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype]; |
2756 const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype]; |
2745 v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8; |
2757 v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8; |
2746 } |
2758 } |
2747 |
2759 |
2748 /* Modify the speed of the vehicle due to a change in altitude */ |
2760 /** Modify the speed of the vehicle due to a change in altitude */ |
2749 static void AffectSpeedByZChange(Vehicle *v, byte old_z) |
2761 static void AffectSpeedByZChange(Vehicle *v, byte old_z) |
2750 { |
2762 { |
2751 if (old_z == v->z_pos || _patches.realistic_acceleration) return; |
2763 if (old_z == v->z_pos || _patches.realistic_acceleration) return; |
2752 |
2764 |
2753 const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype]; |
2765 const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype]; |
2846 /* it can't collide with its own wagons */ |
2858 /* it can't collide with its own wagons */ |
2847 if (v == coll || |
2859 if (v == coll || |
2848 (v->u.rail.track == TRACK_BIT_WORMHOLE && (v->direction & 2) != (realcoll->direction & 2))) |
2860 (v->u.rail.track == TRACK_BIT_WORMHOLE && (v->direction & 2) != (realcoll->direction & 2))) |
2849 return; |
2861 return; |
2850 |
2862 |
2851 //two drivers + passangers killed in train v |
2863 /* two drivers + passangers killed in train v */ |
2852 uint num = 2 + CountPassengersInTrain(v); |
2864 uint num = 2 + CountPassengersInTrain(v); |
2853 if (!(coll->vehstatus & VS_CRASHED)) |
2865 if (!(coll->vehstatus & VS_CRASHED)) |
2854 //two drivers + passangers killed in train coll (if it was not crashed already) |
2866 /* two drivers + passangers killed in train coll (if it was not crashed already) */ |
2855 num += 2 + CountPassengersInTrain(coll); |
2867 num += 2 + CountPassengersInTrain(coll); |
2856 |
2868 |
2857 SetVehicleCrashed(v); |
2869 SetVehicleCrashed(v); |
2858 if (IsFrontEngine(coll)) SetVehicleCrashed(coll); |
2870 if (IsFrontEngine(coll)) SetVehicleCrashed(coll); |
2859 |
2871 |
2957 chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits)); |
2969 chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits)); |
2958 assert(chosen_track & tracks); |
2970 assert(chosen_track & tracks); |
2959 |
2971 |
2960 /* Check if it's a red signal and that force proceed is not clicked. */ |
2972 /* Check if it's a red signal and that force proceed is not clicked. */ |
2961 if ((tracks >> 16) & chosen_track && v->u.rail.force_proceed == 0) { |
2973 if ((tracks >> 16) & chosen_track && v->u.rail.force_proceed == 0) { |
2962 // In front of a red signal |
2974 /* In front of a red signal |
2963 /* find the first set bit in ts. need to do it in 2 steps, since |
2975 * find the first set bit in ts. need to do it in 2 steps, since |
2964 * FIND_FIRST_BIT only handles 6 bits at a time. */ |
2976 * FIND_FIRST_BIT only handles 6 bits at a time. */ |
2965 Trackdir i = FindFirstTrackdir((TrackdirBits)(uint16)ts); |
2977 Trackdir i = FindFirstTrackdir((TrackdirBits)(uint16)ts); |
2966 |
2978 |
2967 if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) { |
2979 if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) { |
2968 v->cur_speed = 0; |
2980 v->cur_speed = 0; |
3394 v->tick_counter++; |
3406 v->tick_counter++; |
3395 |
3407 |
3396 if (IsFrontEngine(v)) { |
3408 if (IsFrontEngine(v)) { |
3397 TrainLocoHandler(v, false); |
3409 TrainLocoHandler(v, false); |
3398 |
3410 |
3399 // make sure vehicle wasn't deleted. |
3411 /* make sure vehicle wasn't deleted. */ |
3400 if (v->type == VEH_TRAIN && IsFrontEngine(v)) |
3412 if (v->type == VEH_TRAIN && IsFrontEngine(v)) |
3401 TrainLocoHandler(v, true); |
3413 TrainLocoHandler(v, true); |
3402 } else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) { |
3414 } else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) { |
3403 // Delete flooded standalone wagon |
3415 /* Delete flooded standalone wagon */ |
3404 if (++v->u.rail.crash_anim_pos >= 4400) |
3416 if (++v->u.rail.crash_anim_pos >= 4400) |
3405 DeleteVehicle(v); |
3417 DeleteVehicle(v); |
3406 } |
3418 } |
3407 } |
3419 } |
3408 |
3420 |
3413 if (_patches.servint_trains == 0) return; |
3425 if (_patches.servint_trains == 0) return; |
3414 if (!VehicleNeedsService(v)) return; |
3426 if (!VehicleNeedsService(v)) return; |
3415 if (v->vehstatus & VS_STOPPED) return; |
3427 if (v->vehstatus & VS_STOPPED) return; |
3416 if (_patches.gotodepot && VehicleHasDepotOrders(v)) return; |
3428 if (_patches.gotodepot && VehicleHasDepotOrders(v)) return; |
3417 |
3429 |
3418 // Don't interfere with a depot visit scheduled by the user, or a |
3430 /* Don't interfere with a depot visit scheduled by the user, or a |
3419 // depot visit by the order list. |
3431 * depot visit by the order list. */ |
3420 if (v->current_order.type == OT_GOTO_DEPOT && |
3432 if (v->current_order.type == OT_GOTO_DEPOT && |
3421 (v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0) |
3433 (v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0) |
3422 return; |
3434 return; |
3423 |
3435 |
3424 if (CheckTrainIsInsideDepot(v)) { |
3436 if (CheckTrainIsInsideDepot(v)) { |
3513 { |
3525 { |
3514 Vehicle *v; |
3526 Vehicle *v; |
3515 |
3527 |
3516 FOR_ALL_VEHICLES(v) { |
3528 FOR_ALL_VEHICLES(v) { |
3517 if (v->type == VEH_TRAIN && IsFrontEngine(v)) { |
3529 if (v->type == VEH_TRAIN && IsFrontEngine(v)) { |
3518 // show warning if train is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) |
3530 /* show warning if train is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */ |
3519 if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->profit_this_year < 0) { |
3531 if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->profit_this_year < 0) { |
3520 SetDParam(1, v->profit_this_year); |
3532 SetDParam(1, v->profit_this_year); |
3521 SetDParam(0, v->unitnumber); |
3533 SetDParam(0, v->unitnumber); |
3522 AddNewsItem( |
3534 AddNewsItem( |
3523 STR_TRAIN_IS_UNPROFITABLE, |
3535 STR_TRAIN_IS_UNPROFITABLE, |