69 void TrainPowerChanged(Vehicle* v) |
69 void TrainPowerChanged(Vehicle* v) |
70 { |
70 { |
71 uint32 total_power = 0; |
71 uint32 total_power = 0; |
72 uint32 max_te = 0; |
72 uint32 max_te = 0; |
73 |
73 |
74 for (const Vehicle *u = v; u != NULL; u = u->next) { |
74 for (const Vehicle *u = v; u != NULL; u = u->Next()) { |
75 /* Power is not added for articulated parts */ |
75 /* Power is not added for articulated parts */ |
76 if (IsArticulatedPart(u)) continue; |
76 if (IsArticulatedPart(u)) continue; |
77 |
77 |
78 RailType railtype = GetRailType(u->tile); |
78 RailType railtype = GetRailType(u->tile); |
79 bool engine_has_power = HasPowerOnRail(u->u.rail.railtype, railtype); |
79 bool engine_has_power = HasPowerOnRail(u->u.rail.railtype, railtype); |
111 */ |
111 */ |
112 static void TrainCargoChanged(Vehicle* v) |
112 static void TrainCargoChanged(Vehicle* v) |
113 { |
113 { |
114 uint32 weight = 0; |
114 uint32 weight = 0; |
115 |
115 |
116 for (Vehicle *u = v; u != NULL; u = u->next) { |
116 for (Vehicle *u = v; u != NULL; u = u->Next()) { |
117 uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo.Count() * FreightWagonMult(u->cargo_type) / 16; |
117 uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo.Count() * FreightWagonMult(u->cargo_type) / 16; |
118 |
118 |
119 /* Vehicle weight is not added for articulated parts. */ |
119 /* Vehicle weight is not added for articulated parts. */ |
120 if (!IsArticulatedPart(u)) { |
120 if (!IsArticulatedPart(u)) { |
121 /* vehicle weight is the sum of the weight of the vehicle and the weight of its cargo */ |
121 /* vehicle weight is the sum of the weight of the vehicle and the weight of its cargo */ |
157 const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type); |
157 const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type); |
158 EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE; |
158 EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE; |
159 v->u.rail.cached_total_length = 0; |
159 v->u.rail.cached_total_length = 0; |
160 v->u.rail.compatible_railtypes = 0; |
160 v->u.rail.compatible_railtypes = 0; |
161 |
161 |
162 for (Vehicle *u = v; u != NULL; u = u->next) { |
162 for (Vehicle *u = v; u != NULL; u = u->Next()) { |
163 const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); |
163 const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); |
164 |
164 |
165 /* Update the v->first cache. This is faster than having to brute force it later. */ |
165 /* Check the v->first cache. */ |
166 if (u->first == NULL) u->first = v; |
166 assert(u->First() == v); |
167 |
167 |
168 /* update the 'first engine' */ |
168 /* update the 'first engine' */ |
169 u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine; |
169 u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine; |
170 u->u.rail.railtype = rvi_u->railtype; |
170 u->u.rail.railtype = rvi_u->railtype; |
171 |
171 |
234 uint16 veh_len = CALLBACK_FAILED; |
234 uint16 veh_len = CALLBACK_FAILED; |
235 if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) { |
235 if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) { |
236 veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u); |
236 veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u); |
237 } |
237 } |
238 if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor; |
238 if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor; |
239 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 |
239 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 |
240 u->u.rail.cached_veh_length = 8 - veh_len; |
240 u->u.rail.cached_veh_length = 8 - veh_len; |
241 v->u.rail.cached_total_length += u->u.rail.cached_veh_length; |
241 v->u.rail.cached_total_length += u->u.rail.cached_veh_length; |
242 } |
242 } |
243 |
243 |
244 /* store consist weight/max speed in cache */ |
244 /* store consist weight/max speed in cache */ |
300 |
300 |
301 /** new acceleration*/ |
301 /** new acceleration*/ |
302 static int GetTrainAcceleration(Vehicle *v, bool mode) |
302 static int GetTrainAcceleration(Vehicle *v, bool mode) |
303 { |
303 { |
304 int max_speed = 2000; |
304 int max_speed = 2000; |
305 int speed = v->cur_speed * 10 / 16; //[mph] |
305 int speed = v->GetDisplaySpeed(); //[mph] |
306 int curvecount[2] = {0, 0}; |
306 int curvecount[2] = {0, 0}; |
307 |
307 |
308 /*first find the curve speed limit */ |
308 /*first find the curve speed limit */ |
309 int numcurve = 0; |
309 int numcurve = 0; |
310 int sum = 0; |
310 int sum = 0; |
311 int pos = 0; |
311 int pos = 0; |
312 int lastpos = -1; |
312 int lastpos = -1; |
313 for (const Vehicle *u = v; u->next != NULL; u = u->next, pos++) { |
313 for (const Vehicle *u = v; u->Next() != NULL; u = u->Next(), pos++) { |
314 Direction dir = u->direction; |
314 Direction dir = u->direction; |
315 Direction ndir = u->next->direction; |
315 Direction ndir = u->Next()->direction; |
316 int i; |
316 int i; |
317 |
317 |
318 for (i = 0; i < 2; i++) { |
318 for (i = 0; i < 2; i++) { |
319 if ( _curve_neighbours45[dir][i] == ndir) { |
319 if ( _curve_neighbours45[dir][i] == ndir) { |
320 curvecount[i]++; |
320 curvecount[i]++; |
370 max_speed = min(max_speed, v->u.rail.cached_max_speed); |
370 max_speed = min(max_speed, v->u.rail.cached_max_speed); |
371 |
371 |
372 int num = 0; //number of vehicles, change this into the number of axles later |
372 int num = 0; //number of vehicles, change this into the number of axles later |
373 int incl = 0; |
373 int incl = 0; |
374 int drag_coeff = 20; //[1e-4] |
374 int drag_coeff = 20; //[1e-4] |
375 for (const Vehicle *u = v; u != NULL; u = u->next) { |
375 for (const Vehicle *u = v; u != NULL; u = u->Next()) { |
376 num++; |
376 num++; |
377 drag_coeff += 3; |
377 drag_coeff += 3; |
378 |
378 |
379 if (u->u.rail.track == TRACK_BIT_DEPOT) max_speed = min(max_speed, 61); |
379 if (u->u.rail.track == TRACK_BIT_DEPOT) max_speed = min(max_speed, 61); |
380 |
380 |
582 AddArticulatedParts(vl, VEH_TRAIN); |
582 AddArticulatedParts(vl, VEH_TRAIN); |
583 |
583 |
584 _new_vehicle_id = v->index; |
584 _new_vehicle_id = v->index; |
585 |
585 |
586 VehiclePositionChanged(v); |
586 VehiclePositionChanged(v); |
587 TrainConsistChanged(GetFirstVehicleInChain(v)); |
587 TrainConsistChanged(v->First()); |
588 UpdateTrainGroupID(GetFirstVehicleInChain(v)); |
588 UpdateTrainGroupID(v->First()); |
589 |
589 |
590 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
590 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
591 if (IsLocalPlayer()) { |
591 if (IsLocalPlayer()) { |
592 InvalidateAutoreplaceWindow(VEH_TRAIN, v->group_id); // updates the replace Train window |
592 InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window |
593 } |
593 } |
594 GetPlayer(_current_player)->num_engines[engine]++; |
594 GetPlayer(_current_player)->num_engines[engine]++; |
595 } |
595 } |
596 } |
596 } |
597 |
597 |
619 return CommandCost(GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5); |
619 return CommandCost(GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5); |
620 } |
620 } |
621 |
621 |
622 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building) |
622 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building) |
623 { |
623 { |
|
624 u = new (u) Train(); |
624 u->direction = v->direction; |
625 u->direction = v->direction; |
625 u->owner = v->owner; |
626 u->owner = v->owner; |
626 u->tile = v->tile; |
627 u->tile = v->tile; |
627 u->x_pos = v->x_pos; |
628 u->x_pos = v->x_pos; |
628 u->y_pos = v->y_pos; |
629 u->y_pos = v->y_pos; |
629 u->z_pos = v->z_pos; |
630 u->z_pos = v->z_pos; |
630 u->u.rail.track = TRACK_BIT_DEPOT; |
631 u->u.rail.track = TRACK_BIT_DEPOT; |
631 u->vehstatus = v->vehstatus & ~VS_STOPPED; |
632 u->vehstatus = v->vehstatus & ~VS_STOPPED; |
632 u = new (u) Train(); |
|
633 u->subtype = 0; |
633 u->subtype = 0; |
634 SetMultiheaded(u); |
634 SetMultiheaded(u); |
635 u->spritenum = v->spritenum + 1; |
635 u->spritenum = v->spritenum + 1; |
636 u->cargo_type = v->cargo_type; |
636 u->cargo_type = v->cargo_type; |
637 u->cargo_subtype = v->cargo_subtype; |
637 u->cargo_subtype = v->cargo_subtype; |
638 u->cargo_cap = v->cargo_cap; |
638 u->cargo_cap = v->cargo_cap; |
639 u->u.rail.railtype = v->u.rail.railtype; |
639 u->u.rail.railtype = v->u.rail.railtype; |
640 if (building) v->next = u; |
640 if (building) v->SetNext(u); |
641 u->engine_type = v->engine_type; |
641 u->engine_type = v->engine_type; |
642 u->build_year = v->build_year; |
642 u->build_year = v->build_year; |
643 if (building) v->value >>= 1; |
643 if (building) v->value >>= 1; |
644 u->value = v->value; |
644 u->value = v->value; |
645 u->cur_image = 0xAC2; |
645 u->cur_image = 0xAC2; |
771 |
771 |
772 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
772 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
773 RebuildVehicleLists(); |
773 RebuildVehicleLists(); |
774 InvalidateWindow(WC_COMPANY, v->owner); |
774 InvalidateWindow(WC_COMPANY, v->owner); |
775 if (IsLocalPlayer()) |
775 if (IsLocalPlayer()) |
776 InvalidateAutoreplaceWindow(VEH_TRAIN, v->group_id); // updates the replace Train window |
776 InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window |
777 |
777 |
778 GetPlayer(_current_player)->num_engines[p1]++; |
778 GetPlayer(_current_player)->num_engines[p1]++; |
779 } |
779 } |
780 } |
780 } |
781 |
781 |
791 |
791 |
792 /* check if stopped in a depot */ |
792 /* check if stopped in a depot */ |
793 if (!IsTileDepotType(tile, TRANSPORT_RAIL) || v->cur_speed != 0) return -1; |
793 if (!IsTileDepotType(tile, TRANSPORT_RAIL) || v->cur_speed != 0) return -1; |
794 |
794 |
795 int count = 0; |
795 int count = 0; |
796 for (; v != NULL; v = v->next) { |
796 for (; v != NULL; v = v->Next()) { |
797 /* This count is used by the depot code to determine the number of engines |
797 /* This count is used by the depot code to determine the number of engines |
798 * in the consist. Exclude articulated parts so that autoreplacing to |
798 * in the consist. Exclude articulated parts so that autoreplacing to |
799 * engines with more articulated parts than before works correctly. |
799 * engines with more articulated parts than before works correctly. |
800 * |
800 * |
801 * Also skip counting rear ends of multiheaded engines */ |
801 * Also skip counting rear ends of multiheaded engines */ |
871 * add a vehicle v behind vehicle dest |
870 * add a vehicle v behind vehicle dest |
872 * use this function since it sets flags as needed |
871 * use this function since it sets flags as needed |
873 */ |
872 */ |
874 static void AddWagonToConsist(Vehicle *v, Vehicle *dest) |
873 static void AddWagonToConsist(Vehicle *v, Vehicle *dest) |
875 { |
874 { |
876 UnlinkWagon(v, GetFirstVehicleInChain(v)); |
875 UnlinkWagon(v, v->First()); |
877 if (dest == NULL) return; |
876 if (dest == NULL) return; |
878 |
877 |
879 v->next = dest->next; |
878 Vehicle *next = dest->Next(); |
880 dest->next = v; |
879 dest->SetNext(v); |
|
880 v->SetNext(next); |
881 ClearFreeWagon(v); |
881 ClearFreeWagon(v); |
882 ClearFrontEngine(v); |
882 ClearFrontEngine(v); |
883 } |
883 } |
884 |
884 |
885 /* |
885 /* |
895 for (; v != NULL; v = GetNextVehicle(v)) { |
895 for (; v != NULL; v = GetNextVehicle(v)) { |
896 if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue; |
896 if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue; |
897 |
897 |
898 /* make sure that there are no free cars before next engine */ |
898 /* make sure that there are no free cars before next engine */ |
899 Vehicle *u; |
899 Vehicle *u; |
900 for (u = v; u->next != NULL && !IsTrainEngine(u->next); u = u->next) {} |
900 for (u = v; u->Next() != NULL && !IsTrainEngine(u->Next()); u = u->Next()) {} |
901 |
901 |
902 if (u == v->u.rail.other_multiheaded_part) continue; |
902 if (u == v->u.rail.other_multiheaded_part) continue; |
903 AddWagonToConsist(v->u.rail.other_multiheaded_part, u); |
903 AddWagonToConsist(v->u.rail.other_multiheaded_part, u); |
904 } |
904 } |
905 } |
905 } |
932 dst = GetVehicle(d); |
932 dst = GetVehicle(d); |
933 if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR; |
933 if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR; |
934 } |
934 } |
935 |
935 |
936 /* if an articulated part is being handled, deal with its parent vehicle */ |
936 /* if an articulated part is being handled, deal with its parent vehicle */ |
937 while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src); |
937 while (IsArticulatedPart(src)) src = src->Previous(); |
938 if (dst != NULL) { |
938 if (dst != NULL) { |
939 while (IsArticulatedPart(dst)) dst = GetPrevVehicleInChain(dst); |
939 while (IsArticulatedPart(dst)) dst = dst->Previous(); |
940 } |
940 } |
941 |
941 |
942 /* don't move the same vehicle.. */ |
942 /* don't move the same vehicle.. */ |
943 if (src == dst) return CommandCost(); |
943 if (src == dst) return CommandCost(); |
944 |
944 |
945 /* locate the head of the two chains */ |
945 /* locate the head of the two chains */ |
946 Vehicle *src_head = GetFirstVehicleInChain(src); |
946 Vehicle *src_head = src->First(); |
947 Vehicle *dst_head; |
947 Vehicle *dst_head; |
948 if (dst != NULL) { |
948 if (dst != NULL) { |
949 dst_head = GetFirstVehicleInChain(dst); |
949 dst_head = dst->First(); |
950 if (dst_head->tile != src_head->tile) return CMD_ERROR; |
950 if (dst_head->tile != src_head->tile) return CMD_ERROR; |
951 /* Now deal with articulated part of destination wagon */ |
951 /* Now deal with articulated part of destination wagon */ |
952 dst = GetLastEnginePart(dst); |
952 dst = GetLastEnginePart(dst); |
953 } else { |
953 } else { |
954 dst_head = NULL; |
954 dst_head = NULL; |
1021 } |
1021 } |
1022 } |
1022 } |
1023 |
1023 |
1024 /* do it? */ |
1024 /* do it? */ |
1025 if (flags & DC_EXEC) { |
1025 if (flags & DC_EXEC) { |
1026 /* clear the ->first cache */ |
|
1027 for (Vehicle *u = src_head; u != NULL; u = u->next) u->first = NULL; |
|
1028 for (Vehicle *u = dst_head; u != NULL; u = u->next) u->first = NULL; |
|
1029 |
|
1030 /* If we move the front Engine and if the second vehicle is not an engine |
1026 /* If we move the front Engine and if the second vehicle is not an engine |
1031 add the whole vehicle to the DEFAULT_GROUP */ |
1027 add the whole vehicle to the DEFAULT_GROUP */ |
1032 if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) { |
1028 if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) { |
1033 const Vehicle *v = GetNextVehicle(src); |
1029 const Vehicle *v = GetNextVehicle(src); |
1034 |
1030 |
1040 if (HASBIT(p2, 0)) { |
1036 if (HASBIT(p2, 0)) { |
1041 /* unlink ALL wagons */ |
1037 /* unlink ALL wagons */ |
1042 if (src != src_head) { |
1038 if (src != src_head) { |
1043 Vehicle *v = src_head; |
1039 Vehicle *v = src_head; |
1044 while (GetNextVehicle(v) != src) v = GetNextVehicle(v); |
1040 while (GetNextVehicle(v) != src) v = GetNextVehicle(v); |
1045 GetLastEnginePart(v)->next = NULL; |
1041 GetLastEnginePart(v)->SetNext(NULL); |
1046 } else { |
1042 } else { |
1047 InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line |
1043 InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line |
1048 src_head = NULL; |
1044 src_head = NULL; |
1049 } |
1045 } |
1050 } else { |
1046 } else { |
1051 /* if moving within the same chain, dont use dst_head as it may get invalidated */ |
1047 /* if moving within the same chain, dont use dst_head as it may get invalidated */ |
1052 if (src_head == dst_head) dst_head = NULL; |
1048 if (src_head == dst_head) dst_head = NULL; |
1053 /* unlink single wagon from linked list */ |
1049 /* unlink single wagon from linked list */ |
1054 src_head = UnlinkWagon(src, src_head); |
1050 src_head = UnlinkWagon(src, src_head); |
1055 GetLastEnginePart(src)->next = NULL; |
1051 GetLastEnginePart(src)->SetNext(NULL); |
1056 } |
1052 } |
1057 |
1053 |
1058 if (dst == NULL) { |
1054 if (dst == NULL) { |
1059 /* We make a new line in the depot, so we know already that we invalidate the window data */ |
1055 /* We make a new line in the depot, so we know already that we invalidate the window data */ |
1060 InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile); |
1056 InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile); |
1096 /* link in the wagon(s) in the chain. */ |
1092 /* link in the wagon(s) in the chain. */ |
1097 { |
1093 { |
1098 Vehicle *v; |
1094 Vehicle *v; |
1099 |
1095 |
1100 for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v)); |
1096 for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v)); |
1101 GetLastEnginePart(v)->next = dst->next; |
1097 GetLastEnginePart(v)->SetNext(dst->Next()); |
1102 } |
1098 } |
1103 dst->next = src; |
1099 dst->SetNext(src); |
1104 } |
1100 } |
|
1101 |
1105 if (src->u.rail.other_multiheaded_part != NULL) { |
1102 if (src->u.rail.other_multiheaded_part != NULL) { |
1106 if (src->u.rail.other_multiheaded_part == src_head) { |
1103 if (src->u.rail.other_multiheaded_part == src_head) { |
1107 src_head = src_head->next; |
1104 src_head = src_head->Next(); |
1108 } |
1105 } |
1109 AddWagonToConsist(src->u.rail.other_multiheaded_part, src); |
1106 AddWagonToConsist(src->u.rail.other_multiheaded_part, src); |
1110 /* previous line set the front engine to the old front. We need to clear that */ |
|
1111 src->u.rail.other_multiheaded_part->first = NULL; |
|
1112 } |
1107 } |
1113 |
1108 |
1114 /* If there is an engine behind first_engine we moved away, it should become new first_engine |
1109 /* If there is an engine behind first_engine we moved away, it should become new first_engine |
1115 * To do this, CmdMoveRailVehicle must be called once more |
1110 * To do this, CmdMoveRailVehicle must be called once more |
1116 * we can't loop forever here because next time we reach this line we will have a front engine */ |
1111 * we can't loop forever here because next time we reach this line we will have a front engine */ |
1217 |
1212 |
1218 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1213 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1219 |
1214 |
1220 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1215 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1221 |
1216 |
1222 while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v); |
1217 while (IsArticulatedPart(v)) v = v->Previous(); |
1223 Vehicle *first = GetFirstVehicleInChain(v); |
1218 Vehicle *first = v->First(); |
1224 |
1219 |
1225 /* make sure the vehicle is stopped in the depot */ |
1220 /* make sure the vehicle is stopped in the depot */ |
1226 if (CheckTrainStoppedInDepot(first) < 0) { |
1221 if (CheckTrainStoppedInDepot(first) < 0) { |
1227 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1222 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1228 } |
1223 } |
1260 |
1255 |
1261 /* 2. We are selling the first engine, some special action might be required |
1256 /* 2. We are selling the first engine, some special action might be required |
1262 * here, so take attention */ |
1257 * here, so take attention */ |
1263 if ((flags & DC_EXEC) && v == first) { |
1258 if ((flags & DC_EXEC) && v == first) { |
1264 Vehicle *new_f = GetNextVehicle(first); |
1259 Vehicle *new_f = GetNextVehicle(first); |
1265 |
|
1266 /* 2.1 If the first wagon is sold, update the first-> pointers to NULL */ |
|
1267 for (Vehicle *tmp = first; tmp != NULL; tmp = tmp->next) tmp->first = NULL; |
|
1268 |
1260 |
1269 /* 2.2 If there are wagons present after the deleted front engine, check |
1261 /* 2.2 If there are wagons present after the deleted front engine, check |
1270 * if the second wagon (which will be first) is an engine. If it is one, |
1262 * if the second wagon (which will be first) is an engine. If it is one, |
1271 * promote it as a new train, retaining the unitnumber, orders */ |
1263 * promote it as a new train, retaining the unitnumber, orders */ |
1272 if (new_f != NULL && IsTrainEngine(new_f)) { |
1264 if (new_f != NULL && IsTrainEngine(new_f)) { |
1298 first->orders = NULL; |
1290 first->orders = NULL; |
1299 first->prev_shared = NULL; |
1291 first->prev_shared = NULL; |
1300 first->next_shared = NULL; |
1292 first->next_shared = NULL; |
1301 |
1293 |
1302 /* If we deleted a window then open a new one for the 'new' train */ |
1294 /* If we deleted a window then open a new one for the 'new' train */ |
1303 if (IsLocalPlayer() && w != NULL) ShowTrainViewWindow(new_f); |
1295 if (IsLocalPlayer() && w != NULL) ShowVehicleViewWindow(new_f); |
1304 } |
1296 } |
1305 } |
1297 } |
1306 |
1298 |
1307 /* 3. Delete the requested wagon */ |
1299 /* 3. Delete the requested wagon */ |
1308 cost.AddCost(-v->value); |
1300 cost.AddCost(-v->value); |
1469 static void ReverseTrainSwapVeh(Vehicle *v, int l, int r) |
1461 static void ReverseTrainSwapVeh(Vehicle *v, int l, int r) |
1470 { |
1462 { |
1471 Vehicle *a, *b; |
1463 Vehicle *a, *b; |
1472 |
1464 |
1473 /* locate vehicles to swap */ |
1465 /* locate vehicles to swap */ |
1474 for (a = v; l != 0; l--) a = a->next; |
1466 for (a = v; l != 0; l--) a = a->Next(); |
1475 for (b = v; r != 0; r--) b = b->next; |
1467 for (b = v; r != 0; r--) b = b->Next(); |
1476 |
1468 |
1477 if (a != b) { |
1469 if (a != b) { |
1478 /* swap the hidden bits */ |
1470 /* swap the hidden bits */ |
1479 { |
1471 { |
1480 uint16 tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus&VS_HIDDEN); |
1472 uint16 tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus&VS_HIDDEN); |
1538 * @param before Set to true for the call before reversing, false otherwise |
1530 * @param before Set to true for the call before reversing, false otherwise |
1539 */ |
1531 */ |
1540 static void AdvanceWagons(Vehicle *v, bool before) |
1532 static void AdvanceWagons(Vehicle *v, bool before) |
1541 { |
1533 { |
1542 Vehicle *base = v; |
1534 Vehicle *base = v; |
1543 Vehicle *first = base->next; |
1535 Vehicle *first = base->Next(); |
1544 uint length = CountVehiclesInChain(v); |
1536 uint length = CountVehiclesInChain(v); |
1545 |
1537 |
1546 while (length > 2) { |
1538 while (length > 2) { |
1547 /* find pairwise matching wagon |
1539 /* find pairwise matching wagon |
1548 * start<>end, start+1<>end-1, ... */ |
1540 * start<>end, start+1<>end-1, ... */ |
1549 Vehicle *last = first; |
1541 Vehicle *last = first; |
1550 for (uint i = length - 3; i > 0; i--) last = last->next; |
1542 for (uint i = length - 3; i > 0; i--) last = last->Next(); |
1551 |
1543 |
1552 int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length; |
1544 int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length; |
1553 if (before) differential *= -1; |
1545 if (before) differential *= -1; |
1554 |
1546 |
1555 if (differential > 0) { |
1547 if (differential > 0) { |
1556 /* disconnect last car to make sure only this subset moves */ |
1548 /* disconnect last car to make sure only this subset moves */ |
1557 Vehicle *tempnext = last->next; |
1549 Vehicle *tempnext = last->Next(); |
1558 last->next = NULL; |
1550 last->SetNext(NULL); |
1559 |
1551 |
1560 for (int i = 0; i < differential; i++) TrainController(first, false); |
1552 for (int i = 0; i < differential; i++) TrainController(first, false); |
1561 |
1553 |
1562 last->next = tempnext; |
1554 last->SetNext(tempnext); |
1563 } |
1555 } |
1564 |
1556 |
1565 base = first; |
1557 base = first; |
1566 first = first->next; |
1558 first = first->Next(); |
1567 length -= 2; |
1559 length -= 2; |
1568 } |
1560 } |
1569 } |
1561 } |
1570 |
1562 |
1571 |
1563 |
1592 } |
1584 } |
1593 |
1585 |
1594 /* count number of vehicles */ |
1586 /* count number of vehicles */ |
1595 int r = -1; |
1587 int r = -1; |
1596 const Vehicle *u = v; |
1588 const Vehicle *u = v; |
1597 do r++; while ( (u = u->next) != NULL ); |
1589 do r++; while ((u = u->Next()) != NULL); |
1598 |
1590 |
1599 AdvanceWagons(v, true); |
1591 AdvanceWagons(v, true); |
1600 |
1592 |
1601 /* swap start<>end, start+1<>end-1, ... */ |
1593 /* swap start<>end, start+1<>end-1, ... */ |
1602 int l = 0; |
1594 int l = 0; |
1632 |
1624 |
1633 if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) { |
1625 if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) { |
1634 return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT); |
1626 return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT); |
1635 } |
1627 } |
1636 |
1628 |
1637 Vehicle *front = GetFirstVehicleInChain(v); |
1629 Vehicle *front = v->First(); |
1638 /* make sure the vehicle is stopped in the depot */ |
1630 /* make sure the vehicle is stopped in the depot */ |
1639 if (CheckTrainStoppedInDepot(front) < 0) { |
1631 if (CheckTrainStoppedInDepot(front) < 0) { |
1640 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1632 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1641 } |
1633 } |
1642 |
1634 |
1644 TOGGLEBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION); |
1636 TOGGLEBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION); |
1645 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
1637 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
1646 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
1638 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
1647 } |
1639 } |
1648 } else { |
1640 } else { |
1649 /*turn the whole train around */ |
1641 /* turn the whole train around */ |
1650 if (v->u.rail.crash_anim_pos != 0 || v->breakdown_ctr != 0) return CMD_ERROR; |
1642 if (v->vehstatus & VS_CRASHED || v->breakdown_ctr != 0) return CMD_ERROR; |
1651 |
1643 |
1652 if (flags & DC_EXEC) { |
1644 if (flags & DC_EXEC) { |
1653 if (_patches.realistic_acceleration && v->cur_speed != 0) { |
1645 if (_patches.realistic_acceleration && v->cur_speed != 0) { |
1654 TOGGLEBIT(v->u.rail.flags, VRF_REVERSING); |
1646 TOGGLEBIT(v->u.rail.flags, VRF_REVERSING); |
1655 } else { |
1647 } else { |
1771 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
1763 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
1772 RebuildVehicleLists(); |
1764 RebuildVehicleLists(); |
1773 } |
1765 } |
1774 } |
1766 } |
1775 } |
1767 } |
1776 } while ((v = v->next) != NULL && !only_this); |
1768 } while ((v = v->Next()) != NULL && !only_this); |
1777 |
1769 |
1778 _returned_refit_capacity = num; |
1770 _returned_refit_capacity = num; |
1779 |
1771 |
1780 /* Update the train's cached variables */ |
1772 /* Update the train's cached variables */ |
1781 if (flags & DC_EXEC) TrainConsistChanged(GetFirstVehicleInChain(GetVehicle(p1))); |
1773 if (flags & DC_EXEC) TrainConsistChanged(GetVehicle(p1)->First()); |
1782 |
1774 |
1783 return cost; |
1775 return cost; |
1784 } |
1776 } |
1785 |
1777 |
1786 struct TrainFindDepotData { |
1778 struct TrainFindDepotData { |
2016 CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK); |
2008 CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK); |
2017 sound = true; |
2009 sound = true; |
2018 } |
2010 } |
2019 break; |
2011 break; |
2020 } |
2012 } |
2021 } while ((v = v->next) != NULL); |
2013 } while ((v = v->Next()) != NULL); |
2022 |
2014 |
2023 if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT); |
2015 if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT); |
2024 } |
2016 } |
2025 |
2017 |
2026 static void TrainPlayLeaveStationSound(const Vehicle* v) |
2018 static void TrainPlayLeaveStationSound(const Vehicle* v) |
2045 } |
2037 } |
2046 |
2038 |
2047 static bool CheckTrainStayInDepot(Vehicle *v) |
2039 static bool CheckTrainStayInDepot(Vehicle *v) |
2048 { |
2040 { |
2049 /* bail out if not all wagons are in the same depot or not in a depot at all */ |
2041 /* bail out if not all wagons are in the same depot or not in a depot at all */ |
2050 for (const Vehicle *u = v; u != NULL; u = u->next) { |
2042 for (const Vehicle *u = v; u != NULL; u = u->Next()) { |
2051 if (u->u.rail.track != TRACK_BIT_DEPOT || u->tile != v->tile) return false; |
2043 if (u->u.rail.track != TRACK_BIT_DEPOT || u->tile != v->tile) return false; |
2052 } |
2044 } |
2053 |
2045 |
2054 /* if the train got no power, then keep it in the depot */ |
2046 /* if the train got no power, then keep it in the depot */ |
2055 if (v->u.rail.cached_power == 0) { |
2047 if (v->u.rail.cached_power == 0) { |
2469 { |
2461 { |
2470 Vehicle *v = this; |
2462 Vehicle *v = this; |
2471 do { |
2463 do { |
2472 v->cur_image = v->GetImage(v->direction); |
2464 v->cur_image = v->GetImage(v->direction); |
2473 MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1); |
2465 MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1); |
2474 } while ((v = v->next) != NULL); |
2466 } while ((v = v->Next()) != NULL); |
2475 |
2467 |
2476 /* need to update acceleration and cached values since the goods on the train changed. */ |
2468 /* need to update acceleration and cached values since the goods on the train changed. */ |
2477 TrainCargoChanged(this); |
2469 TrainCargoChanged(this); |
2478 UpdateTrainAcceleration(this); |
2470 UpdateTrainAcceleration(this); |
2479 } |
2471 } |
2717 v->u.rail.track != TRACK_BIT_DEPOT && |
2709 v->u.rail.track != TRACK_BIT_DEPOT && |
2718 myabs(v->z_pos - tcc->v->z_pos) < 6 && |
2710 myabs(v->z_pos - tcc->v->z_pos) < 6 && |
2719 myabs(v->x_pos - tcc->v->x_pos) < 6 && |
2711 myabs(v->x_pos - tcc->v->x_pos) < 6 && |
2720 myabs(v->y_pos - tcc->v->y_pos) < 6 ) { |
2712 myabs(v->y_pos - tcc->v->y_pos) < 6 ) { |
2721 |
2713 |
2722 Vehicle *coll = GetFirstVehicleInChain(v); |
2714 Vehicle *coll = v->First(); |
2723 |
2715 |
2724 /* it can't collide with its own wagons */ |
2716 /* it can't collide with its own wagons */ |
2725 if (tcc->v == coll || |
2717 if (tcc->v == coll || |
2726 (tcc->v->u.rail.track == TRACK_BIT_WORMHOLE && (tcc->v->direction & 2) != (v->direction & 2))) |
2718 (tcc->v->u.rail.track == TRACK_BIT_WORMHOLE && (tcc->v->direction & 2) != (v->direction & 2))) |
2727 return NULL; |
2719 return NULL; |
2755 |
2747 |
2756 assert(v->u.rail.track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile); |
2748 assert(v->u.rail.track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile); |
2757 |
2749 |
2758 TrainCollideChecker tcc; |
2750 TrainCollideChecker tcc; |
2759 tcc.v = v; |
2751 tcc.v = v; |
2760 tcc.v_skip = v->next; |
2752 tcc.v_skip = v->Next(); |
2761 tcc.num = 0; |
2753 tcc.num = 0; |
2762 |
2754 |
2763 /* find colliding vehicles */ |
2755 /* find colliding vehicles */ |
2764 if (v->u.rail.track == TRACK_BIT_WORMHOLE) { |
2756 if (v->u.rail.track == TRACK_BIT_WORMHOLE) { |
2765 VehicleFromPos(v->tile, &tcc, FindTrainCollideEnum); |
2757 VehicleFromPos(v->tile, &tcc, FindTrainCollideEnum); |
2807 static void TrainController(Vehicle *v, bool update_image) |
2799 static void TrainController(Vehicle *v, bool update_image) |
2808 { |
2800 { |
2809 Vehicle *prev; |
2801 Vehicle *prev; |
2810 |
2802 |
2811 /* For every vehicle after and including the given vehicle */ |
2803 /* For every vehicle after and including the given vehicle */ |
2812 for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) { |
2804 for (prev = v->Previous(); v != NULL; prev = v, v = v->Next()) { |
2813 DiagDirection enterdir = DIAGDIR_BEGIN; |
2805 DiagDirection enterdir = DIAGDIR_BEGIN; |
2814 bool update_signals = false; |
2806 bool update_signals = false; |
2815 BeginVehicleMove(v); |
2807 BeginVehicleMove(v); |
2816 |
2808 |
2817 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
2809 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
2934 uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
2926 uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
2935 if (HASBIT(r, VETS_CANNOT_ENTER)) { |
2927 if (HASBIT(r, VETS_CANNOT_ENTER)) { |
2936 goto invalid_rail; |
2928 goto invalid_rail; |
2937 } |
2929 } |
2938 |
2930 |
2939 if (IsLevelCrossingTile(v->tile) && v->next == NULL) { |
2931 if (IsLevelCrossingTile(v->tile) && v->Next() == NULL) { |
2940 UnbarCrossing(v->tile); |
2932 UnbarCrossing(v->tile); |
2941 MarkTileDirtyByTile(v->tile); |
2933 MarkTileDirtyByTile(v->tile); |
2942 } |
2934 } |
2943 |
2935 |
2944 if (IsFrontEngine(v)) v->load_unload_time_rem = 0; |
2936 if (IsFrontEngine(v)) v->load_unload_time_rem = 0; |
2945 |
2937 |
2946 if (!HASBIT(r, VETS_ENTERED_WORMHOLE)) { |
2938 if (!HASBIT(r, VETS_ENTERED_WORMHOLE)) { |
2947 v->tile = gp.new_tile; |
2939 v->tile = gp.new_tile; |
2948 |
2940 |
2949 if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) { |
2941 if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) { |
2950 TrainPowerChanged(GetFirstVehicleInChain(v)); |
2942 TrainPowerChanged(v->First()); |
2951 } |
2943 } |
2952 |
2944 |
2953 v->u.rail.track = chosen_track; |
2945 v->u.rail.track = chosen_track; |
2954 assert(v->u.rail.track); |
2946 assert(v->u.rail.track); |
2955 } |
2947 } |
2997 if (update_signals) { |
2989 if (update_signals) { |
2998 if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir); |
2990 if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir); |
2999 |
2991 |
3000 /* Signals can only change when the first |
2992 /* Signals can only change when the first |
3001 * (above) or the last vehicle moves. */ |
2993 * (above) or the last vehicle moves. */ |
3002 if (v->next == NULL) TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); |
2994 if (v->Next() == NULL) TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); |
3003 } |
2995 } |
3004 } |
2996 } |
3005 return; |
2997 return; |
3006 |
2998 |
3007 invalid_rail: |
2999 invalid_rail: |
3028 { |
3020 { |
3029 /* Go to the last wagon and delete the link pointing there |
3021 /* Go to the last wagon and delete the link pointing there |
3030 * *u is then the one-before-last wagon, and *v the last |
3022 * *u is then the one-before-last wagon, and *v the last |
3031 * one which will physicially be removed */ |
3023 * one which will physicially be removed */ |
3032 Vehicle *u = v; |
3024 Vehicle *u = v; |
3033 for (; v->next != NULL; v = v->next) u = v; |
3025 for (; v->Next() != NULL; v = v->Next()) u = v; |
3034 u->next = NULL; |
3026 u->SetNext(NULL); |
3035 |
3027 |
3036 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
3028 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
3037 DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
3029 DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
3038 RebuildVehicleLists(); |
3030 RebuildVehicleLists(); |
3039 InvalidateWindow(WC_COMPANY, v->owner); |
3031 InvalidateWindow(WC_COMPANY, v->owner); |
3090 /* Refrain from updating the z position of the vehicle when on |
3082 /* Refrain from updating the z position of the vehicle when on |
3091 a bridge, because AfterSetTrainPos will put the vehicle under |
3083 a bridge, because AfterSetTrainPos will put the vehicle under |
3092 the bridge in that case */ |
3084 the bridge in that case */ |
3093 if (v->u.rail.track != TRACK_BIT_WORMHOLE) AfterSetTrainPos(v, false); |
3085 if (v->u.rail.track != TRACK_BIT_WORMHOLE) AfterSetTrainPos(v, false); |
3094 } |
3086 } |
3095 } while ((v = v->next) != NULL); |
3087 } while ((v = v->Next()) != NULL); |
3096 } |
3088 } |
3097 |
3089 |
3098 static void HandleCrashedTrain(Vehicle *v) |
3090 static void HandleCrashedTrain(Vehicle *v) |
3099 { |
3091 { |
3100 int state = ++v->u.rail.crash_anim_pos; |
3092 int state = ++v->u.rail.crash_anim_pos; |
3255 } |
3247 } |
3256 |
3248 |
3257 static void TrainLocoHandler(Vehicle *v, bool mode) |
3249 static void TrainLocoHandler(Vehicle *v, bool mode) |
3258 { |
3250 { |
3259 /* train has crashed? */ |
3251 /* train has crashed? */ |
3260 if (v->u.rail.crash_anim_pos != 0) { |
3252 if (v->vehstatus & VS_CRASHED) { |
3261 if (!mode) HandleCrashedTrain(v); |
3253 if (!mode) HandleCrashedTrain(v); |
3262 return; |
3254 return; |
3263 } |
3255 } |
3264 |
3256 |
3265 if (v->u.rail.force_proceed != 0) v->u.rail.force_proceed--; |
3257 if (v->u.rail.force_proceed != 0) v->u.rail.force_proceed--; |
3313 |
3305 |
3314 SetLastSpeed(v, v->cur_speed); |
3306 SetLastSpeed(v, v->cur_speed); |
3315 } |
3307 } |
3316 |
3308 |
3317 |
3309 |
|
3310 |
|
3311 Money Train::GetRunningCost() const |
|
3312 { |
|
3313 Money cost = 0; |
|
3314 const Vehicle *v = this; |
|
3315 |
|
3316 do { |
|
3317 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); |
|
3318 |
|
3319 byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost_base); |
|
3320 if (cost_factor == 0) continue; |
|
3321 |
|
3322 cost += cost_factor * _price.running_rail[rvi->running_cost_class]; |
|
3323 } while ((v = GetNextVehicle(v)) != NULL); |
|
3324 |
|
3325 return cost; |
|
3326 } |
|
3327 |
|
3328 |
3318 void Train::Tick() |
3329 void Train::Tick() |
3319 { |
3330 { |
3320 if (_age_cargo_skip_counter == 0) this->cargo.AgeCargo(); |
3331 if (_age_cargo_skip_counter == 0) this->cargo.AgeCargo(); |
3321 |
3332 |
3322 this->tick_counter++; |
3333 this->tick_counter++; |
3337 |
3348 |
3338 #define MAX_ACCEPTABLE_DEPOT_DIST 16 |
3349 #define MAX_ACCEPTABLE_DEPOT_DIST 16 |
3339 |
3350 |
3340 static void CheckIfTrainNeedsService(Vehicle *v) |
3351 static void CheckIfTrainNeedsService(Vehicle *v) |
3341 { |
3352 { |
3342 if (_patches.servint_trains == 0) return; |
3353 if (_patches.servint_trains == 0 || !VehicleNeedsService(v)) return; |
3343 if (!VehicleNeedsService(v)) return; |
3354 if (v->IsInDepot()) { |
3344 if (v->vehstatus & VS_STOPPED) return; |
|
3345 if (_patches.gotodepot && VehicleHasDepotOrders(v)) return; |
|
3346 |
|
3347 /* Don't interfere with a depot visit scheduled by the user, or a |
|
3348 * depot visit by the order list. */ |
|
3349 if (v->current_order.type == OT_GOTO_DEPOT && |
|
3350 (v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0) |
|
3351 return; |
|
3352 |
|
3353 if (CheckTrainIsInsideDepot(v)) { |
|
3354 VehicleServiceInDepot(v); |
3355 VehicleServiceInDepot(v); |
3355 return; |
3356 return; |
3356 } |
3357 } |
3357 |
3358 |
3358 TrainFindDepotData tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST); |
3359 TrainFindDepotData tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST); |
3375 v->current_order.dest != depot->index && |
3376 v->current_order.dest != depot->index && |
3376 !CHANCE16(3, 16)) { |
3377 !CHANCE16(3, 16)) { |
3377 return; |
3378 return; |
3378 } |
3379 } |
3379 |
3380 |
3380 if (v->current_order.type == OT_LOADING) v->LeaveStation(); |
|
3381 |
|
3382 v->current_order.type = OT_GOTO_DEPOT; |
3381 v->current_order.type = OT_GOTO_DEPOT; |
3383 v->current_order.flags = OF_NON_STOP; |
3382 v->current_order.flags = OF_NON_STOP; |
3384 v->current_order.dest = depot->index; |
3383 v->current_order.dest = depot->index; |
3385 v->dest_tile = tfdd.tile; |
3384 v->dest_tile = tfdd.tile; |
3386 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
3385 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
3387 } |
3386 } |
3388 |
3387 |
3389 Money GetTrainRunningCost(const Vehicle *v) |
|
3390 { |
|
3391 Money cost = 0; |
|
3392 |
|
3393 do { |
|
3394 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); |
|
3395 |
|
3396 byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost_base); |
|
3397 if (cost_factor == 0) continue; |
|
3398 |
|
3399 cost += cost_factor * _price.running_rail[rvi->running_cost_class]; |
|
3400 } while ((v = GetNextVehicle(v)) != NULL); |
|
3401 |
|
3402 return cost; |
|
3403 } |
|
3404 |
|
3405 void OnNewDay_Train(Vehicle *v) |
3388 void OnNewDay_Train(Vehicle *v) |
3406 { |
3389 { |
3407 if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v); |
3390 if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v); |
3408 |
3391 |
3409 if (IsFrontEngine(v)) { |
3392 if (IsFrontEngine(v)) { |
3420 if (tile != 0) v->dest_tile = tile; |
3403 if (tile != 0) v->dest_tile = tile; |
3421 } |
3404 } |
3422 |
3405 |
3423 if ((v->vehstatus & VS_STOPPED) == 0) { |
3406 if ((v->vehstatus & VS_STOPPED) == 0) { |
3424 /* running costs */ |
3407 /* running costs */ |
3425 CommandCost cost(GetTrainRunningCost(v) / 364); |
3408 CommandCost cost(v->GetRunningCost() / 364); |
3426 |
3409 |
3427 v->profit_this_year -= cost.GetCost() >> 8; |
3410 v->profit_this_year -= cost.GetCost() >> 8; |
3428 |
3411 |
3429 SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN); |
3412 SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN); |
3430 SubtractMoneyFromPlayerFract(v->owner, cost); |
3413 SubtractMoneyFromPlayerFract(v->owner, cost); |