9 #include "tile_cmd.h" |
9 #include "tile_cmd.h" |
10 #include "landscape.h" |
10 #include "landscape.h" |
11 #include "gui.h" |
11 #include "gui.h" |
12 #include "station_map.h" |
12 #include "station_map.h" |
13 #include "tunnel_map.h" |
13 #include "tunnel_map.h" |
14 #include "timetable.h" |
|
15 #include "articulated_vehicles.h" |
14 #include "articulated_vehicles.h" |
16 #include "command_func.h" |
15 #include "command_func.h" |
17 #include "pathfind.h" |
16 #include "pathfind.h" |
18 #include "npf.h" |
17 #include "npf.h" |
19 #include "station.h" |
18 #include "station_base.h" |
20 #include "news.h" |
19 #include "news_func.h" |
21 #include "engine.h" |
20 #include "engine_func.h" |
22 #include "player_func.h" |
21 #include "player_func.h" |
23 #include "player_base.h" |
22 #include "player_base.h" |
24 #include "depot.h" |
23 #include "depot.h" |
25 #include "waypoint.h" |
24 #include "waypoint.h" |
26 #include "vehicle_gui.h" |
25 #include "vehicle_gui.h" |
45 #include "signal_func.h" |
44 #include "signal_func.h" |
46 #include "variables.h" |
45 #include "variables.h" |
47 #include "autoreplace_gui.h" |
46 #include "autoreplace_gui.h" |
48 #include "gfx_func.h" |
47 #include "gfx_func.h" |
49 #include "settings_type.h" |
48 #include "settings_type.h" |
|
49 #include "order_func.h" |
50 |
50 |
51 #include "table/strings.h" |
51 #include "table/strings.h" |
52 #include "table/train_cmd.h" |
52 #include "table/train_cmd.h" |
53 |
53 |
54 static bool TrainCheckIfLineEnds(Vehicle *v); |
54 static bool TrainCheckIfLineEnds(Vehicle *v); |
55 static void TrainController(Vehicle *v, bool update_image); |
55 static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image); |
56 static TileIndex TrainApproachingCrossingTile(const Vehicle *v); |
56 static TileIndex TrainApproachingCrossingTile(const Vehicle *v); |
57 |
57 |
58 static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8}; |
58 static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8}; |
59 static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10}; |
59 static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10}; |
60 |
60 |
178 * Recalculates the cached stuff of a train. Should be called each time a vehicle is added |
178 * Recalculates the cached stuff of a train. Should be called each time a vehicle is added |
179 * to/removed from the chain, and when the game is loaded. |
179 * to/removed from the chain, and when the game is loaded. |
180 * Note: this needs to be called too for 'wagon chains' (in the depot, without an engine) |
180 * Note: this needs to be called too for 'wagon chains' (in the depot, without an engine) |
181 * @param v First vehicle of the chain. |
181 * @param v First vehicle of the chain. |
182 */ |
182 */ |
183 void TrainConsistChanged(Vehicle* v) |
183 void TrainConsistChanged(Vehicle *v) |
184 { |
184 { |
185 uint16 max_speed = 0xFFFF; |
185 uint16 max_speed = UINT16_MAX; |
186 |
186 |
187 assert(v->type == VEH_TRAIN); |
187 assert(v->type == VEH_TRAIN); |
188 assert(IsFrontEngine(v) || IsFreeWagon(v)); |
188 assert(IsFrontEngine(v) || IsFreeWagon(v)); |
189 |
189 |
190 const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type); |
190 const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type); |
211 /* Cache wagon override sprite group. NULL is returned if there is none */ |
211 /* Cache wagon override sprite group. NULL is returned if there is none */ |
212 u->u.rail.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->u.rail.first_engine); |
212 u->u.rail.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->u.rail.first_engine); |
213 |
213 |
214 /* Reset color map */ |
214 /* Reset color map */ |
215 u->colormap = PAL_NONE; |
215 u->colormap = PAL_NONE; |
|
216 |
|
217 /* Set user defined data (must be done before other properties) */ |
|
218 u->u.rail.user_def_data = GetVehicleProperty(u, 0x25, rvi_u->user_def_data); |
216 |
219 |
217 if (rvi_u->visual_effect != 0) { |
220 if (rvi_u->visual_effect != 0) { |
218 u->u.rail.cached_vis_effect = rvi_u->visual_effect; |
221 u->u.rail.cached_vis_effect = rvi_u->visual_effect; |
219 } else { |
222 } else { |
220 if (IsTrainWagon(u) || IsArticulatedPart(u)) { |
223 if (IsTrainWagon(u) || IsArticulatedPart(u)) { |
268 if (u->cargo_type == rvi_u->cargo_type && u->cargo_subtype == 0) { |
271 if (u->cargo_type == rvi_u->cargo_type && u->cargo_subtype == 0) { |
269 /* Set cargo capacity if we've not been refitted */ |
272 /* Set cargo capacity if we've not been refitted */ |
270 u->cargo_cap = GetVehicleProperty(u, 0x14, rvi_u->capacity); |
273 u->cargo_cap = GetVehicleProperty(u, 0x14, rvi_u->capacity); |
271 } |
274 } |
272 |
275 |
273 u->u.rail.user_def_data = GetVehicleProperty(u, 0x25, rvi_u->user_def_data); |
|
274 |
|
275 /* check the vehicle length (callback) */ |
276 /* check the vehicle length (callback) */ |
276 uint16 veh_len = CALLBACK_FAILED; |
277 uint16 veh_len = CALLBACK_FAILED; |
277 if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) { |
278 if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) { |
278 veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u); |
279 veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u); |
279 } |
280 } |
287 v->u.rail.cached_max_speed = max_speed; |
288 v->u.rail.cached_max_speed = max_speed; |
288 v->u.rail.cached_tilt = train_can_tilt; |
289 v->u.rail.cached_tilt = train_can_tilt; |
289 |
290 |
290 /* 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) */ |
291 /* 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) */ |
291 TrainCargoChanged(v); |
292 TrainCargoChanged(v); |
|
293 |
|
294 if (IsFrontEngine(v)) { |
|
295 UpdateTrainAcceleration(v); |
|
296 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
297 } |
292 } |
298 } |
293 |
299 |
294 enum AccelType { |
300 enum AccelType { |
295 AM_ACCEL, |
301 AM_ACCEL, |
296 AM_BRAKE |
302 AM_BRAKE |
297 }; |
303 }; |
298 |
304 |
299 static bool TrainShouldStop(const Vehicle* v, TileIndex tile) |
|
300 { |
|
301 const Order* o = &v->current_order; |
|
302 StationID sid = GetStationIndex(tile); |
|
303 |
|
304 assert(v->type == VEH_TRAIN); |
|
305 /* When does a train drive through a station |
|
306 * first we deal with the "new nonstop handling" */ |
|
307 if (_patches.new_nonstop && o->flags & OFB_NON_STOP && sid == o->dest) { |
|
308 return false; |
|
309 } |
|
310 |
|
311 if (v->last_station_visited == sid) return false; |
|
312 |
|
313 if (sid != o->dest && (o->flags & OFB_NON_STOP || _patches.new_nonstop)) { |
|
314 return false; |
|
315 } |
|
316 |
|
317 return true; |
|
318 } |
|
319 |
|
320 /** new acceleration*/ |
305 /** new acceleration*/ |
321 static int GetTrainAcceleration(Vehicle *v, bool mode) |
306 static int GetTrainAcceleration(Vehicle *v, bool mode) |
322 { |
307 { |
323 static const int absolute_max_speed = 2000; |
308 static const int absolute_max_speed = UINT16_MAX; |
324 int max_speed = absolute_max_speed; |
309 int max_speed = absolute_max_speed; |
325 int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h |
310 int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h |
326 int curvecount[2] = {0, 0}; |
311 int curvecount[2] = {0, 0}; |
327 |
312 |
328 /*first find the curve speed limit */ |
313 /*first find the curve speed limit */ |
540 CommandCost value(EXPENSES_NEW_VEHICLES, (GetEngineProperty(engine, 0x17, rvi->base_cost) * _price.build_railwagon) >> 8); |
525 CommandCost value(EXPENSES_NEW_VEHICLES, (GetEngineProperty(engine, 0x17, rvi->base_cost) * _price.build_railwagon) >> 8); |
541 |
526 |
542 uint num_vehicles = 1 + CountArticulatedParts(engine, false); |
527 uint num_vehicles = 1 + CountArticulatedParts(engine, false); |
543 |
528 |
544 if (!(flags & DC_QUERY_COST)) { |
529 if (!(flags & DC_QUERY_COST)) { |
|
530 /* Check that the wagon can drive on the track in question */ |
|
531 if (!IsCompatibleRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; |
|
532 |
545 /* Allow for the wagon and the articulated parts, plus one to "terminate" the list. */ |
533 /* Allow for the wagon and the articulated parts, plus one to "terminate" the list. */ |
546 Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * (num_vehicles + 1)); |
534 Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * (num_vehicles + 1)); |
547 memset(vl, 0, sizeof(*vl) * (num_vehicles + 1)); |
535 memset(vl, 0, sizeof(*vl) * (num_vehicles + 1)); |
548 |
536 |
549 if (!Vehicle::AllocateList(vl, num_vehicles)) |
537 if (!Vehicle::AllocateList(vl, num_vehicles)) |
581 v->z_pos = GetSlopeZ(x, y); |
569 v->z_pos = GetSlopeZ(x, y); |
582 v->owner = _current_player; |
570 v->owner = _current_player; |
583 v->u.rail.track = TRACK_BIT_DEPOT; |
571 v->u.rail.track = TRACK_BIT_DEPOT; |
584 v->vehstatus = VS_HIDDEN | VS_DEFPAL; |
572 v->vehstatus = VS_HIDDEN | VS_DEFPAL; |
585 |
573 |
586 v->subtype = 0; |
574 // v->subtype = 0; |
587 SetTrainWagon(v); |
575 SetTrainWagon(v); |
588 |
576 |
589 if (u != NULL) { |
577 if (u != NULL) { |
590 u->SetNext(v); |
578 u->SetNext(v); |
591 } else { |
579 } else { |
592 SetFreeWagon(v); |
580 SetFreeWagon(v); |
593 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
581 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
594 } |
582 } |
595 |
583 |
596 v->cargo_type = rvi->cargo_type; |
584 v->cargo_type = rvi->cargo_type; |
597 v->cargo_subtype = 0; |
585 // v->cargo_subtype = 0; |
598 v->cargo_cap = rvi->capacity; |
586 v->cargo_cap = rvi->capacity; |
599 v->value = value.GetCost(); |
587 v->value = value.GetCost(); |
600 // v->day_counter = 0; |
588 // v->day_counter = 0; |
601 |
589 |
602 v->u.rail.railtype = rvi->railtype; |
590 v->u.rail.railtype = rvi->railtype; |
640 break; |
628 break; |
641 } |
629 } |
642 } |
630 } |
643 } |
631 } |
644 |
632 |
645 static CommandCost EstimateTrainCost(EngineID engine, const RailVehicleInfo* rvi) |
633 static CommandCost EstimateTrainCost(EngineID engine, const RailVehicleInfo *rvi) |
646 { |
634 { |
647 return CommandCost(EXPENSES_NEW_VEHICLES, GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5); |
635 return CommandCost(EXPENSES_NEW_VEHICLES, GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5); |
648 } |
636 } |
649 |
637 |
650 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building) |
638 static void AddRearEngineToMultiheadedTrain(Vehicle *v, Vehicle *u, bool building) |
651 { |
639 { |
652 u = new (u) Train(); |
640 u = new (u) Train(); |
653 u->direction = v->direction; |
641 u->direction = v->direction; |
654 u->owner = v->owner; |
642 u->owner = v->owner; |
655 u->tile = v->tile; |
643 u->tile = v->tile; |
656 u->x_pos = v->x_pos; |
644 u->x_pos = v->x_pos; |
657 u->y_pos = v->y_pos; |
645 u->y_pos = v->y_pos; |
658 u->z_pos = v->z_pos; |
646 u->z_pos = v->z_pos; |
659 u->u.rail.track = TRACK_BIT_DEPOT; |
647 u->u.rail.track = TRACK_BIT_DEPOT; |
660 u->vehstatus = v->vehstatus & ~VS_STOPPED; |
648 u->vehstatus = v->vehstatus & ~VS_STOPPED; |
661 u->subtype = 0; |
649 // u->subtype = 0; |
662 SetMultiheaded(u); |
650 SetMultiheaded(u); |
663 u->spritenum = v->spritenum + 1; |
651 u->spritenum = v->spritenum + 1; |
664 u->cargo_type = v->cargo_type; |
652 u->cargo_type = v->cargo_type; |
665 u->cargo_subtype = v->cargo_subtype; |
653 u->cargo_subtype = v->cargo_subtype; |
666 u->cargo_cap = v->cargo_cap; |
654 u->cargo_cap = v->cargo_cap; |
694 if (!IsTileOwner(tile, _current_player)) return CMD_ERROR; |
682 if (!IsTileOwner(tile, _current_player)) return CMD_ERROR; |
695 } |
683 } |
696 |
684 |
697 const RailVehicleInfo *rvi = RailVehInfo(p1); |
685 const RailVehicleInfo *rvi = RailVehInfo(p1); |
698 |
686 |
699 /* Check if depot and new engine uses the same kind of tracks */ |
|
700 /* We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */ |
|
701 if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; |
|
702 |
|
703 if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags); |
687 if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags); |
704 |
688 |
705 CommandCost value = EstimateTrainCost(p1, rvi); |
689 CommandCost value = EstimateTrainCost(p1, rvi); |
706 |
690 |
707 uint num_vehicles = |
691 uint num_vehicles = |
708 (rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + |
692 (rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + |
709 CountArticulatedParts(p1, false); |
693 CountArticulatedParts(p1, false); |
710 |
694 |
711 if (!(flags & DC_QUERY_COST)) { |
695 if (!(flags & DC_QUERY_COST)) { |
|
696 /* Check if depot and new engine uses the same kind of tracks * |
|
697 * We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */ |
|
698 if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; |
|
699 |
712 /* Allow for the dual-heads and the articulated parts, plus one to "terminate" the list. */ |
700 /* Allow for the dual-heads and the articulated parts, plus one to "terminate" the list. */ |
713 Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * (num_vehicles + 1)); |
701 Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * (num_vehicles + 1)); |
714 memset(vl, 0, sizeof(*vl) * (num_vehicles + 1)); |
702 memset(vl, 0, sizeof(*vl) * (num_vehicles + 1)); |
715 |
703 |
716 if (!Vehicle::AllocateList(vl, num_vehicles)) |
704 if (!Vehicle::AllocateList(vl, num_vehicles)) { |
717 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
705 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
|
706 } |
718 |
707 |
719 Vehicle *v = vl[0]; |
708 Vehicle *v = vl[0]; |
720 |
709 |
721 UnitID unit_num = HasBit(p2, 0) ? 0 : GetFreeUnitNumber(VEH_TRAIN); |
710 UnitID unit_num = HasBit(p2, 0) ? 0 : GetFreeUnitNumber(VEH_TRAIN); |
722 if (unit_num > _patches.max_trains) |
711 if (unit_num > _patches.max_trains) |
733 v->tile = tile; |
722 v->tile = tile; |
734 v->owner = _current_player; |
723 v->owner = _current_player; |
735 v->x_pos = x; |
724 v->x_pos = x; |
736 v->y_pos = y; |
725 v->y_pos = y; |
737 v->z_pos = GetSlopeZ(x, y); |
726 v->z_pos = GetSlopeZ(x, y); |
738 v->running_ticks = 0; |
727 // v->running_ticks = 0; |
739 v->u.rail.track = TRACK_BIT_DEPOT; |
728 v->u.rail.track = TRACK_BIT_DEPOT; |
740 v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; |
729 v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; |
741 v->spritenum = rvi->image_index; |
730 v->spritenum = rvi->image_index; |
742 v->cargo_type = rvi->cargo_type; |
731 v->cargo_type = rvi->cargo_type; |
743 v->cargo_subtype = 0; |
732 // v->cargo_subtype = 0; |
744 v->cargo_cap = rvi->capacity; |
733 v->cargo_cap = rvi->capacity; |
745 v->max_speed = rvi->max_speed; |
734 v->max_speed = rvi->max_speed; |
746 v->value = value.GetCost(); |
735 v->value = value.GetCost(); |
747 v->last_station_visited = INVALID_STATION; |
736 v->last_station_visited = INVALID_STATION; |
748 v->dest_tile = 0; |
737 // v->dest_tile = 0; |
749 |
738 |
750 v->engine_type = p1; |
739 v->engine_type = p1; |
751 |
740 |
752 const Engine *e = GetEngine(p1); |
741 const Engine *e = GetEngine(p1); |
753 v->reliability = e->reliability; |
742 v->reliability = e->reliability; |
787 } else { |
776 } else { |
788 AddArticulatedParts(vl, VEH_TRAIN); |
777 AddArticulatedParts(vl, VEH_TRAIN); |
789 } |
778 } |
790 |
779 |
791 TrainConsistChanged(v); |
780 TrainConsistChanged(v); |
792 UpdateTrainAcceleration(v); |
|
793 UpdateTrainGroupID(v); |
781 UpdateTrainGroupID(v); |
794 |
782 |
795 if (!HasBit(p2, 1)) { // check if the cars should be added to the new vehicle |
783 if (!HasBit(p2, 1)) { // check if the cars should be added to the new vehicle |
796 NormalizeTrainVehInDepot(v); |
784 NormalizeTrainVehInDepot(v); |
797 } |
785 } |
798 |
786 |
799 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
787 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
800 RebuildVehicleLists(); |
788 RebuildVehicleLists(); |
801 InvalidateWindow(WC_COMPANY, v->owner); |
789 InvalidateWindow(WC_COMPANY, v->owner); |
802 if (IsLocalPlayer()) |
790 if (IsLocalPlayer()) { |
803 InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window |
791 InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window |
|
792 } |
804 |
793 |
805 GetPlayer(_current_player)->num_engines[p1]++; |
794 GetPlayer(_current_player)->num_engines[p1]++; |
806 } |
795 } |
807 } |
796 } |
808 |
797 |
1181 /* setting the type to 0 also involves setting up the orders field. */ |
1170 /* setting the type to 0 also involves setting up the orders field. */ |
1182 SetFrontEngine(src); |
1171 SetFrontEngine(src); |
1183 assert(src->orders == NULL); |
1172 assert(src->orders == NULL); |
1184 src->num_orders = 0; |
1173 src->num_orders = 0; |
1185 |
1174 |
1186 // Decrease the engines number of the src engine_type |
1175 /* Decrease the engines number of the src engine_type */ |
1187 if (!IsDefaultGroupID(src->group_id) && IsValidGroupID(src->group_id)) { |
1176 if (!IsDefaultGroupID(src->group_id) && IsValidGroupID(src->group_id)) { |
1188 GetGroup(src->group_id)->num_engines[src->engine_type]--; |
1177 GetGroup(src->group_id)->num_engines[src->engine_type]--; |
1189 } |
1178 } |
1190 |
1179 |
1191 // If we move an engine to a new line affect it to the DEFAULT_GROUP |
1180 /* If we move an engine to a new line affect it to the DEFAULT_GROUP */ |
1192 src->group_id = DEFAULT_GROUP; |
1181 src->group_id = DEFAULT_GROUP; |
1193 } |
1182 } |
1194 } else { |
1183 } else { |
1195 SetFreeWagon(src); |
1184 SetFreeWagon(src); |
1196 } |
1185 } |
1242 if (src_head != NULL) { |
1231 if (src_head != NULL) { |
1243 NormaliseTrainConsist(src_head); |
1232 NormaliseTrainConsist(src_head); |
1244 TrainConsistChanged(src_head); |
1233 TrainConsistChanged(src_head); |
1245 UpdateTrainGroupID(src_head); |
1234 UpdateTrainGroupID(src_head); |
1246 if (IsFrontEngine(src_head)) { |
1235 if (IsFrontEngine(src_head)) { |
1247 UpdateTrainAcceleration(src_head); |
|
1248 InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index); |
|
1249 /* Update the refit button and window */ |
1236 /* Update the refit button and window */ |
1250 InvalidateWindow(WC_VEHICLE_REFIT, src_head->index); |
1237 InvalidateWindow(WC_VEHICLE_REFIT, src_head->index); |
1251 InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, VVW_WIDGET_REFIT_VEH); |
1238 InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, VVW_WIDGET_REFIT_VEH); |
1252 } |
1239 } |
1253 /* Update the depot window */ |
1240 /* Update the depot window */ |
1257 if (dst_head != NULL) { |
1244 if (dst_head != NULL) { |
1258 NormaliseTrainConsist(dst_head); |
1245 NormaliseTrainConsist(dst_head); |
1259 TrainConsistChanged(dst_head); |
1246 TrainConsistChanged(dst_head); |
1260 UpdateTrainGroupID(dst_head); |
1247 UpdateTrainGroupID(dst_head); |
1261 if (IsFrontEngine(dst_head)) { |
1248 if (IsFrontEngine(dst_head)) { |
1262 UpdateTrainAcceleration(dst_head); |
|
1263 InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index); |
|
1264 /* Update the refit button and window */ |
1249 /* Update the refit button and window */ |
1265 InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, VVW_WIDGET_REFIT_VEH); |
1250 InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, VVW_WIDGET_REFIT_VEH); |
1266 InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index); |
1251 InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index); |
1267 } |
1252 } |
1268 /* Update the depot window */ |
1253 /* Update the depot window */ |
1423 first = UnlinkWagon(v, first); |
1408 first = UnlinkWagon(v, first); |
1424 DeleteDepotHighlightOfVehicle(v); |
1409 DeleteDepotHighlightOfVehicle(v); |
1425 delete v; |
1410 delete v; |
1426 |
1411 |
1427 /* 4 If the second wagon was an engine, update it to front_engine |
1412 /* 4 If the second wagon was an engine, update it to front_engine |
1428 * which UnlinkWagon() has changed to TS_Free_Car */ |
1413 * which UnlinkWagon() has changed to TS_Free_Car */ |
1429 if (switch_engine) SetFrontEngine(first); |
1414 if (switch_engine) SetFrontEngine(first); |
1430 |
1415 |
1431 /* 5. If the train still exists, update its acceleration, window, etc. */ |
1416 /* 5. If the train still exists, update its acceleration, window, etc. */ |
1432 if (first != NULL) { |
1417 if (first != NULL) { |
1433 NormaliseTrainConsist(first); |
1418 NormaliseTrainConsist(first); |
1434 TrainConsistChanged(first); |
1419 TrainConsistChanged(first); |
1435 UpdateTrainGroupID(first); |
1420 UpdateTrainGroupID(first); |
1436 if (IsFrontEngine(first)) { |
1421 if (IsFrontEngine(first)) InvalidateWindow(WC_VEHICLE_REFIT, first->index); |
1437 InvalidateWindow(WC_VEHICLE_DETAILS, first->index); |
|
1438 InvalidateWindow(WC_VEHICLE_REFIT, first->index); |
|
1439 UpdateTrainAcceleration(first); |
|
1440 } |
|
1441 } |
1422 } |
1442 |
1423 |
1443 |
1424 |
1444 /* (6.) Borked AI. If it sells an engine it expects all wagons lined |
1425 /* (6.) Borked AI. If it sells an engine it expects all wagons lined |
1445 * up on a new line to be added to the newly built loco. Replace it is. |
1426 * up on a new line to be added to the newly built loco. Replace it is. |
1446 * Totally braindead cause building a new engine adds all loco-less |
1427 * Totally braindead cause building a new engine adds all loco-less |
1447 * engines to its train anyways */ |
1428 * engines to its train anyways */ |
1448 if (p2 == 2 && HasBit(ori_subtype, TS_FRONT)) { |
1429 if (p2 == 2 && HasBit(ori_subtype, TS_FRONT)) { |
1449 Vehicle *tmp; |
1430 for (v = first; v != NULL;) { |
1450 for (v = first; v != NULL; v = tmp) { |
1431 Vehicle *tmp = GetNextVehicle(v); |
1451 tmp = GetNextVehicle(v); |
|
1452 DoCommand(v->tile, v->index | INVALID_VEHICLE << 16, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
1432 DoCommand(v->tile, v->index | INVALID_VEHICLE << 16, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
|
1433 v = tmp; |
1453 } |
1434 } |
1454 } |
1435 } |
1455 } |
1436 } |
1456 } break; |
1437 } break; |
1457 case 1: { /* Delete wagon and all wagons after it given certain criteria */ |
1438 case 1: { /* Delete wagon and all wagons after it given certain criteria */ |
1458 /* Start deleting every vehicle after the selected one |
1439 /* Start deleting every vehicle after the selected one |
1459 * If we encounter a matching rear-engine to a front-engine |
1440 * If we encounter a matching rear-engine to a front-engine |
1460 * earlier in the chain (before deletion), leave it alone */ |
1441 * earlier in the chain (before deletion), leave it alone */ |
1461 Vehicle *tmp; |
1442 for (Vehicle *tmp; v != NULL; v = tmp) { |
1462 for (; v != NULL; v = tmp) { |
|
1463 tmp = GetNextVehicle(v); |
1443 tmp = GetNextVehicle(v); |
1464 |
1444 |
1465 if (IsMultiheaded(v)) { |
1445 if (IsMultiheaded(v)) { |
1466 if (IsTrainEngine(v)) { |
1446 if (IsTrainEngine(v)) { |
1467 /* We got a front engine of a multiheaded set. Now we will sell the rear end too */ |
1447 /* We got a front engine of a multiheaded set. Now we will sell the rear end too */ |
1528 #undef MKIT |
1506 #undef MKIT |
1529 |
1507 |
1530 uint32 x = _delta_xy_table[direction]; |
1508 uint32 x = _delta_xy_table[direction]; |
1531 this->x_offs = GB(x, 0, 8); |
1509 this->x_offs = GB(x, 0, 8); |
1532 this->y_offs = GB(x, 8, 8); |
1510 this->y_offs = GB(x, 8, 8); |
1533 this->sprite_width = GB(x, 16, 8); |
1511 this->x_extent = GB(x, 16, 8); |
1534 this->sprite_height = GB(x, 24, 8); |
1512 this->y_extent = GB(x, 24, 8); |
1535 this->z_height = 6; |
1513 this->z_extent = 6; |
1536 } |
1514 } |
1537 |
1515 |
1538 static void UpdateVarsAfterSwap(Vehicle *v) |
1516 static void UpdateVarsAfterSwap(Vehicle *v) |
1539 { |
1517 { |
1540 v->UpdateDeltaXY(v->direction); |
1518 v->UpdateDeltaXY(v->direction); |
1542 BeginVehicleMove(v); |
1520 BeginVehicleMove(v); |
1543 VehiclePositionChanged(v); |
1521 VehiclePositionChanged(v); |
1544 EndVehicleMove(v); |
1522 EndVehicleMove(v); |
1545 } |
1523 } |
1546 |
1524 |
1547 static inline void SetLastSpeed(Vehicle* v, int spd) |
1525 static inline void SetLastSpeed(Vehicle *v, int spd) |
1548 { |
1526 { |
1549 int old = v->u.rail.last_speed; |
1527 int old = v->u.rail.last_speed; |
1550 if (spd != old) { |
1528 if (spd != old) { |
1551 v->u.rail.last_speed = spd; |
1529 v->u.rail.last_speed = spd; |
1552 if (_patches.vehicle_speed || (old == 0) != (spd == 0)) |
1530 if (_patches.vehicle_speed || (old == 0) != (spd == 0)) { |
1553 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
1531 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
|
1532 } |
1554 } |
1533 } |
1555 } |
1534 } |
1556 |
1535 |
1557 static void SwapTrainFlags(byte *swap_flag1, byte *swap_flag2) |
1536 static void SwapTrainFlags(byte *swap_flag1, byte *swap_flag2) |
1558 { |
1537 { |
1668 assert(IsLevelCrossingTile(tile)); |
1647 assert(IsLevelCrossingTile(tile)); |
1669 |
1648 |
1670 DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile)); |
1649 DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile)); |
1671 TileIndex tile_from = tile + TileOffsByDiagDir(dir); |
1650 TileIndex tile_from = tile + TileOffsByDiagDir(dir); |
1672 |
1651 |
1673 Vehicle *v = (Vehicle *)VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum); |
1652 Vehicle *v = (Vehicle*)VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum); |
1674 |
1653 |
1675 if (v != NULL) return v; |
1654 if (v != NULL) return v; |
1676 |
1655 |
1677 dir = ReverseDiagDir(dir); |
1656 dir = ReverseDiagDir(dir); |
1678 tile_from = tile + TileOffsByDiagDir(dir); |
1657 tile_from = tile + TileOffsByDiagDir(dir); |
1679 |
1658 |
1680 return (Vehicle *)VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum); |
1659 return (Vehicle*)VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum); |
1681 } |
1660 } |
1682 |
1661 |
1683 |
1662 |
1684 /** |
1663 /** |
1685 * Sets correct crossing state |
1664 * Sets correct crossing state |
1719 } |
1698 } |
1720 |
1699 |
1721 |
1700 |
1722 /** |
1701 /** |
1723 * Advances wagons for train reversing, needed for variable length wagons. |
1702 * Advances wagons for train reversing, needed for variable length wagons. |
1724 * Needs to be called once before the train is reversed, and once after it. |
1703 * This one is called before the train is reversed. |
1725 * @param v First vehicle in chain |
1704 * @param v First vehicle in chain |
1726 * @param before Set to true for the call before reversing, false otherwise |
|
1727 */ |
1705 */ |
1728 static void AdvanceWagons(Vehicle *v, bool before) |
1706 static void AdvanceWagonsBeforeSwap(Vehicle *v) |
1729 { |
1707 { |
1730 Vehicle *base = v; |
1708 Vehicle *base = v; |
1731 Vehicle *first = base->Next(); |
1709 Vehicle *first = base; // first vehicle to move |
|
1710 Vehicle *last = GetLastVehicleInChain(v); // last vehicle to move |
1732 uint length = CountVehiclesInChain(v); |
1711 uint length = CountVehiclesInChain(v); |
1733 |
1712 |
1734 while (length > 2) { |
1713 while (length > 2) { |
1735 /* find pairwise matching wagon |
1714 last = last->Previous(); |
1736 * start<>end, start+1<>end-1, ... */ |
1715 first = first->Next(); |
1737 Vehicle *last = first; |
1716 |
1738 for (uint i = length - 3; i > 0; i--) last = last->Next(); |
1717 int differential = base->u.rail.cached_veh_length - last->u.rail.cached_veh_length; |
|
1718 |
|
1719 /* do not update images now |
|
1720 * negative differential will be handled in AdvanceWagonsAfterSwap() */ |
|
1721 for (int i = 0; i < differential; i++) TrainController(first, last->Next(), false); |
|
1722 |
|
1723 base = first; // == base->Next() |
|
1724 length -= 2; |
|
1725 } |
|
1726 } |
|
1727 |
|
1728 |
|
1729 /** |
|
1730 * Advances wagons for train reversing, needed for variable length wagons. |
|
1731 * This one is called after the train is reversed. |
|
1732 * @param v First vehicle in chain |
|
1733 */ |
|
1734 static void AdvanceWagonsAfterSwap(Vehicle *v) |
|
1735 { |
|
1736 /* first of all, fix the situation when the train was entering a depot */ |
|
1737 Vehicle *dep = v; // last vehicle in front of just left depot |
|
1738 while (dep->Next() != NULL && (dep->u.rail.track == TRACK_BIT_DEPOT || dep->Next()->u.rail.track != TRACK_BIT_DEPOT)) { |
|
1739 dep = dep->Next(); // find first vehicle outside of a depot, with next vehicle inside a depot |
|
1740 } |
|
1741 |
|
1742 Vehicle *leave = dep->Next(); // first vehicle in a depot we are leaving now |
|
1743 |
|
1744 if (leave != NULL) { |
|
1745 /* 'pull' next wagon out of the depot, so we won't miss it (it could stay in depot forever) */ |
|
1746 int d = TicksToLeaveDepot(dep); |
|
1747 |
|
1748 if (d <= 0) { |
|
1749 leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot |
|
1750 leave->u.rail.track = AxisToTrackBits(DiagDirToAxis(GetRailDepotDirection(leave->tile))); |
|
1751 for (int i = 0; i >= d; i--) TrainController(leave, NULL, false); // maybe move it, and maybe let another wagon leave |
|
1752 } |
|
1753 } else { |
|
1754 dep = NULL; // no vehicle in a depot, so no vehicle leaving a depot |
|
1755 } |
|
1756 |
|
1757 Vehicle *base = v; |
|
1758 Vehicle *first = base; // first vehicle to move |
|
1759 Vehicle *last = GetLastVehicleInChain(v); // last vehicle to move |
|
1760 uint length = CountVehiclesInChain(v); |
|
1761 |
|
1762 /* we have to make sure all wagons that leave a depot because of train reversing are moved coorectly |
|
1763 * they have already correct spacing, so we have to make sure they are moved how they should */ |
|
1764 bool nomove = (dep == NULL); // if there is no vehicle leaving a depot, limit the number of wagons moved immediatelly |
|
1765 |
|
1766 while (length > 2) { |
|
1767 /* we reached vehicle (originally) in front of a depot, stop now |
|
1768 * (we would move wagons that are alredy moved with new wagon length) */ |
|
1769 if (base == dep) break; |
|
1770 |
|
1771 /* the last wagon was that one leaving a depot, so do not move it anymore */ |
|
1772 if (last == dep) nomove = true; |
|
1773 |
|
1774 last = last->Previous(); |
|
1775 first = first->Next(); |
1739 |
1776 |
1740 int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length; |
1777 int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length; |
1741 if (before) differential *= -1; |
1778 |
1742 |
1779 /* do not update images now */ |
1743 if (differential > 0) { |
1780 for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : NULL), false); |
1744 /* disconnect last car to make sure only this subset moves */ |
1781 |
1745 Vehicle *tempnext = last->Next(); |
1782 base = first; // == base->Next() |
1746 last->SetNext(NULL); |
|
1747 |
|
1748 /* do not update images now because the wagons are disconnected |
|
1749 * and that could cause problems with NewGRFs */ |
|
1750 for (int i = 0; i < differential; i++) TrainController(first, false); |
|
1751 |
|
1752 last->SetNext(tempnext); |
|
1753 } |
|
1754 |
|
1755 base = first; |
|
1756 first = first->Next(); |
|
1757 length -= 2; |
1783 length -= 2; |
1758 } |
1784 } |
1759 } |
1785 } |
1760 |
1786 |
1761 |
1787 |
1767 |
1793 |
1768 /* Check if we were approaching a rail/road-crossing */ |
1794 /* Check if we were approaching a rail/road-crossing */ |
1769 TileIndex crossing = TrainApproachingCrossingTile(v); |
1795 TileIndex crossing = TrainApproachingCrossingTile(v); |
1770 |
1796 |
1771 /* count number of vehicles */ |
1797 /* count number of vehicles */ |
1772 int r = 0; ///< number of vehicles - 1 |
1798 int r = CountVehiclesInChain(v) - 1; // number of vehicles - 1 |
1773 for (const Vehicle *u = v; (u = u->Next()) != NULL;) { r++; } |
1799 |
1774 |
1800 AdvanceWagonsBeforeSwap(v); |
1775 AdvanceWagons(v, true); |
|
1776 |
1801 |
1777 /* swap start<>end, start+1<>end-1, ... */ |
1802 /* swap start<>end, start+1<>end-1, ... */ |
1778 int l = 0; |
1803 int l = 0; |
1779 do { |
1804 do { |
1780 ReverseTrainSwapVeh(v, l++, r--); |
1805 ReverseTrainSwapVeh(v, l++, r--); |
1781 } while (l <= r); |
1806 } while (l <= r); |
1782 |
1807 |
1783 AdvanceWagons(v, false); |
1808 AdvanceWagonsAfterSwap(v); |
1784 |
1809 |
1785 if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) { |
1810 if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) { |
1786 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
1811 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
1787 } |
1812 } |
1788 |
1813 |
2022 bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse); |
2047 bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse); |
2023 tfdd.best_length = found ? max_distance / 2 : UINT_MAX; // some fake distance or NOT_FOUND |
2048 tfdd.best_length = found ? max_distance / 2 : UINT_MAX; // some fake distance or NOT_FOUND |
2024 } break; |
2049 } break; |
2025 |
2050 |
2026 case VPF_NPF: { /* NPF */ |
2051 case VPF_NPF: { /* NPF */ |
2027 Vehicle* last = GetLastVehicleInChain(v); |
2052 const Vehicle *last = GetLastVehicleInChain(v); |
2028 Trackdir trackdir = GetVehicleTrackdir(v); |
2053 Trackdir trackdir = GetVehicleTrackdir(v); |
2029 Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last)); |
2054 Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last)); |
2030 |
2055 |
2031 assert(trackdir != INVALID_TRACKDIR); |
2056 assert(trackdir != INVALID_TRACKDIR); |
2032 NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY); |
2057 NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY); |
2033 if (ftd.best_bird_dist == 0) { |
2058 if (ftd.best_bird_dist == 0) { |
2034 /* Found target */ |
2059 /* Found target */ |
2035 tfdd.tile = ftd.node.tile; |
2060 tfdd.tile = ftd.node.tile; |
2036 /* Our caller expects a number of tiles, so we just approximate that |
2061 /* Our caller expects a number of tiles, so we just approximate that |
2037 * number by this. It might not be completely what we want, but it will |
2062 * number by this. It might not be completely what we want, but it will |
2038 * work for now :-) We can possibly change this when the old pathfinder |
2063 * work for now :-) We can possibly change this when the old pathfinder |
2039 * is removed. */ |
2064 * is removed. */ |
2040 tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH; |
2065 tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH; |
2041 if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true; |
2066 if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true; |
2042 } |
2067 } |
2043 } break; |
2068 } break; |
2044 |
2069 |
2081 |
2106 |
2082 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
2107 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
2083 |
2108 |
2084 if (v->vehstatus & VS_CRASHED) return CMD_ERROR; |
2109 if (v->vehstatus & VS_CRASHED) return CMD_ERROR; |
2085 |
2110 |
2086 if (v->current_order.type == OT_GOTO_DEPOT) { |
2111 if (v->current_order.IsType(OT_GOTO_DEPOT)) { |
2087 if (!!(p2 & DEPOT_SERVICE) == HasBit(v->current_order.flags, OF_HALT_IN_DEPOT)) { |
2112 bool halt_in_depot = v->current_order.GetDepotActionType() & ODATFB_HALT; |
|
2113 if (!!(p2 & DEPOT_SERVICE) == halt_in_depot) { |
2088 /* We called with a different DEPOT_SERVICE setting. |
2114 /* We called with a different DEPOT_SERVICE setting. |
2089 * Now we change the setting to apply the new one and let the vehicle head for the same depot. |
2115 * Now we change the setting to apply the new one and let the vehicle head for the same depot. |
2090 * Note: the if is (true for requesting service == true for ordered to stop in depot) */ |
2116 * Note: the if is (true for requesting service == true for ordered to stop in depot) */ |
2091 if (flags & DC_EXEC) { |
2117 if (flags & DC_EXEC) { |
2092 ClrBit(v->current_order.flags, OF_PART_OF_ORDERS); |
2118 v->current_order.SetDepotOrderType(ODTF_MANUAL); |
2093 ToggleBit(v->current_order.flags, OF_HALT_IN_DEPOT); |
2119 v->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT); |
2094 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
2120 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
2095 } |
2121 } |
2096 return CommandCost(); |
2122 return CommandCost(); |
2097 } |
2123 } |
2098 |
2124 |
2099 if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders |
2125 if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders |
2100 if (flags & DC_EXEC) { |
2126 if (flags & DC_EXEC) { |
2101 if (HasBit(v->current_order.flags, OF_PART_OF_ORDERS)) { |
2127 /* If the orders to 'goto depot' are in the orders list (forced servicing), |
2102 v->cur_order_index++; |
2128 * then skip to the next order; effectively cancelling this forced service */ |
2103 } |
2129 if (v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) v->cur_order_index++; |
2104 |
2130 |
2105 v->current_order.type = OT_DUMMY; |
2131 v->current_order.MakeDummy(); |
2106 v->current_order.flags = 0; |
|
2107 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
2132 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
2108 } |
2133 } |
2109 return CommandCost(); |
2134 return CommandCost(); |
2110 } |
2135 } |
2111 |
2136 |
2115 |
2140 |
2116 TrainFindDepotData tfdd = FindClosestTrainDepot(v, 0); |
2141 TrainFindDepotData tfdd = FindClosestTrainDepot(v, 0); |
2117 if (tfdd.best_length == (uint)-1) return_cmd_error(STR_883A_UNABLE_TO_FIND_ROUTE_TO); |
2142 if (tfdd.best_length == (uint)-1) return_cmd_error(STR_883A_UNABLE_TO_FIND_ROUTE_TO); |
2118 |
2143 |
2119 if (flags & DC_EXEC) { |
2144 if (flags & DC_EXEC) { |
2120 if (v->current_order.type == OT_LOADING) v->LeaveStation(); |
2145 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation(); |
2121 |
2146 |
2122 v->dest_tile = tfdd.tile; |
2147 v->dest_tile = tfdd.tile; |
2123 v->current_order.type = OT_GOTO_DEPOT; |
2148 v->current_order.MakeGoToDepot(GetDepotByTile(tfdd.tile)->index, ODTF_MANUAL); |
2124 v->current_order.flags = OFB_NON_STOP; |
2149 if (!(p2 & DEPOT_SERVICE)) v->current_order.SetDepotActionType(ODATFB_HALT); |
2125 if (!(p2 & DEPOT_SERVICE)) SetBit(v->current_order.flags, OF_HALT_IN_DEPOT); |
|
2126 v->current_order.dest = GetDepotByTile(tfdd.tile)->index; |
|
2127 v->current_order.refit_cargo = CT_INVALID; |
|
2128 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
2150 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
2129 /* If there is no depot in front, reverse automatically */ |
2151 /* If there is no depot in front, reverse automatically */ |
2130 if (tfdd.reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION); |
2152 if (tfdd.reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION); |
2131 } |
2153 } |
2132 |
2154 |
2141 |
2163 |
2142 static const int8 _vehicle_smoke_pos[8] = { |
2164 static const int8 _vehicle_smoke_pos[8] = { |
2143 1, 1, 1, 0, -1, -1, -1, 0 |
2165 1, 1, 1, 0, -1, -1, -1, 0 |
2144 }; |
2166 }; |
2145 |
2167 |
2146 static void HandleLocomotiveSmokeCloud(const Vehicle* v) |
2168 static void HandleLocomotiveSmokeCloud(const Vehicle *v) |
2147 { |
2169 { |
2148 bool sound = false; |
2170 bool sound = false; |
2149 |
2171 |
2150 if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2) |
2172 if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2) { |
2151 return; |
2173 return; |
2152 |
2174 } |
2153 const Vehicle* u = v; |
2175 |
|
2176 const Vehicle *u = v; |
2154 |
2177 |
2155 do { |
2178 do { |
2156 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); |
2179 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); |
2157 int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8; |
2180 int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8; |
2158 byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2); |
2181 byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2); |
2185 x = -x; |
2208 x = -x; |
2186 y = -y; |
2209 y = -y; |
2187 } |
2210 } |
2188 |
2211 |
2189 switch (effect_type) { |
2212 switch (effect_type) { |
2190 case 0: |
2213 case 0: |
2191 /* steam smoke. */ |
2214 /* steam smoke. */ |
2192 if (GB(v->tick_counter, 0, 4) == 0) { |
2215 if (GB(v->tick_counter, 0, 4) == 0) { |
2193 CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE); |
2216 CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE); |
2194 sound = true; |
2217 sound = true; |
2195 } |
2218 } |
2196 break; |
2219 break; |
2197 |
2220 |
2198 case 1: |
2221 case 1: |
2199 /* diesel smoke */ |
2222 /* diesel smoke */ |
2200 if (u->cur_speed <= 40 && Chance16(15, 128)) { |
2223 if (u->cur_speed <= 40 && Chance16(15, 128)) { |
2201 CreateEffectVehicleRel(v, 0, 0, 10, EV_DIESEL_SMOKE); |
2224 CreateEffectVehicleRel(v, 0, 0, 10, EV_DIESEL_SMOKE); |
2202 sound = true; |
2225 sound = true; |
2203 } |
2226 } |
2204 break; |
2227 break; |
2205 |
2228 |
2206 case 2: |
2229 case 2: |
2207 /* blue spark */ |
2230 /* blue spark */ |
2208 if (GB(v->tick_counter, 0, 2) == 0 && Chance16(1, 45)) { |
2231 if (GB(v->tick_counter, 0, 2) == 0 && Chance16(1, 45)) { |
2209 CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK); |
2232 CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK); |
2210 sound = true; |
2233 sound = true; |
2211 } |
2234 } |
2212 break; |
2235 break; |
|
2236 |
|
2237 default: |
|
2238 break; |
2213 } |
2239 } |
2214 } while ((v = v->Next()) != NULL); |
2240 } while ((v = v->Next()) != NULL); |
2215 |
2241 |
2216 if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT); |
2242 if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT); |
2217 } |
2243 } |
2317 } |
2343 } |
2318 return false; |
2344 return false; |
2319 } |
2345 } |
2320 } |
2346 } |
2321 |
2347 |
2322 static void FillWithStationData(TrainTrackFollowerData* fd, const Vehicle* v) |
2348 static void FillWithStationData(TrainTrackFollowerData *fd, const Vehicle *v) |
2323 { |
2349 { |
2324 fd->dest_coords = v->dest_tile; |
2350 fd->dest_coords = v->dest_tile; |
2325 if (v->current_order.type == OT_GOTO_STATION) { |
2351 fd->station_index = v->current_order.IsType(OT_GOTO_STATION) ? v->current_order.GetDestination() : INVALID_STATION; |
2326 fd->station_index = v->current_order.dest; |
|
2327 } else { |
|
2328 fd->station_index = INVALID_STATION; |
|
2329 } |
|
2330 } |
2352 } |
2331 |
2353 |
2332 static const byte _initial_tile_subcoord[6][4][3] = { |
2354 static const byte _initial_tile_subcoord[6][4][3] = { |
2333 {{ 15, 8, 1 }, { 0, 0, 0 }, { 0, 8, 5 }, { 0, 0, 0 }}, |
2355 {{ 15, 8, 1 }, { 0, 0, 0 }, { 0, 8, 5 }, { 0, 0, 0 }}, |
2334 {{ 0, 0, 0 }, { 8, 0, 3 }, { 0, 0, 0 }, { 8, 15, 7 }}, |
2356 {{ 0, 0, 0 }, { 8, 0, 3 }, { 0, 0, 0 }, { 8, 15, 7 }}, |
2336 {{ 15, 8, 2 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 15, 6 }}, |
2358 {{ 15, 8, 2 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 15, 6 }}, |
2337 {{ 15, 7, 0 }, { 8, 0, 4 }, { 0, 0, 0 }, { 0, 0, 0 }}, |
2359 {{ 15, 7, 0 }, { 8, 0, 4 }, { 0, 0, 0 }, { 0, 0, 0 }}, |
2338 {{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 4 }, { 7, 15, 0 }}, |
2360 {{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 4 }, { 7, 15, 0 }}, |
2339 }; |
2361 }; |
2340 |
2362 |
2341 static const uint32 _reachable_tracks[4] = { |
|
2342 0x10091009, |
|
2343 0x00160016, |
|
2344 0x05200520, |
|
2345 0x2A002A00, |
|
2346 }; |
|
2347 |
|
2348 static const byte _search_directions[6][4] = { |
2363 static const byte _search_directions[6][4] = { |
2349 { 0, 9, 2, 9 }, ///< track 1 |
2364 { 0, 9, 2, 9 }, ///< track 1 |
2350 { 9, 1, 9, 3 }, ///< track 2 |
2365 { 9, 1, 9, 3 }, ///< track 2 |
2351 { 9, 0, 3, 9 }, ///< track upper |
2366 { 9, 0, 3, 9 }, ///< track upper |
2352 { 1, 9, 9, 2 }, ///< track lower |
2367 { 1, 9, 9, 2 }, ///< track lower |
2477 |
2492 |
2478 static bool CheckReverseTrain(Vehicle *v) |
2493 static bool CheckReverseTrain(Vehicle *v) |
2479 { |
2494 { |
2480 if (_opt.diff.line_reverse_mode != 0 || |
2495 if (_opt.diff.line_reverse_mode != 0 || |
2481 v->u.rail.track == TRACK_BIT_DEPOT || v->u.rail.track == TRACK_BIT_WORMHOLE || |
2496 v->u.rail.track == TRACK_BIT_DEPOT || v->u.rail.track == TRACK_BIT_WORMHOLE || |
2482 !(v->direction & 1)) |
2497 !(v->direction & 1)) { |
2483 return false; |
2498 return false; |
|
2499 } |
2484 |
2500 |
2485 TrainTrackFollowerData fd; |
2501 TrainTrackFollowerData fd; |
2486 FillWithStationData(&fd, v); |
2502 FillWithStationData(&fd, v); |
2487 |
2503 |
2488 uint reverse_best = 0; |
2504 uint reverse_best = 0; |
2489 |
2505 |
2490 assert(v->u.rail.track); |
2506 assert(v->u.rail.track); |
2491 |
2507 |
2492 int i = _search_directions[FIND_FIRST_BIT(v->u.rail.track)][DirToDiagDir(v->direction)]; |
|
2493 |
|
2494 switch (_patches.pathfinder_for_trains) { |
2508 switch (_patches.pathfinder_for_trains) { |
2495 case VPF_YAPF: { /* YAPF */ |
2509 case VPF_YAPF: /* YAPF */ |
2496 reverse_best = YapfCheckReverseTrain(v); |
2510 reverse_best = YapfCheckReverseTrain(v); |
2497 } break; |
2511 break; |
2498 |
2512 |
2499 case VPF_NPF: { /* NPF */ |
2513 case VPF_NPF: { /* NPF */ |
2500 NPFFindStationOrTileData fstd; |
2514 NPFFindStationOrTileData fstd; |
2501 NPFFoundTargetData ftd; |
2515 NPFFoundTargetData ftd; |
2502 Vehicle* last = GetLastVehicleInChain(v); |
2516 Vehicle *last = GetLastVehicleInChain(v); |
2503 |
2517 |
2504 NPFFillWithOrderData(&fstd, v); |
2518 NPFFillWithOrderData(&fstd, v); |
2505 |
2519 |
2506 Trackdir trackdir = GetVehicleTrackdir(v); |
2520 Trackdir trackdir = GetVehicleTrackdir(v); |
2507 Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last)); |
2521 Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last)); |
2575 } |
2591 } |
2576 |
2592 |
2577 return reverse_best != 0; |
2593 return reverse_best != 0; |
2578 } |
2594 } |
2579 |
2595 |
2580 static bool ProcessTrainOrder(Vehicle *v) |
2596 TileIndex Train::GetOrderStationLocation(StationID station) |
2581 { |
2597 { |
2582 switch (v->current_order.type) { |
2598 if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION; |
2583 case OT_GOTO_DEPOT: |
2599 |
2584 if (!(v->current_order.flags & OFB_PART_OF_ORDERS)) return false; |
2600 return GetStation(station)->xy; |
2585 if ((v->current_order.flags & OFB_SERVICE_IF_NEEDED) && |
|
2586 !VehicleNeedsService(v)) { |
|
2587 UpdateVehicleTimetable(v, true); |
|
2588 v->cur_order_index++; |
|
2589 } |
|
2590 break; |
|
2591 |
|
2592 case OT_LOADING: |
|
2593 case OT_LEAVESTATION: |
|
2594 return false; |
|
2595 |
|
2596 default: break; |
|
2597 } |
|
2598 |
|
2599 /** |
|
2600 * Reversing because of order change is allowed only just after leaving a |
|
2601 * station (and the difficulty setting to allowed, of course) |
|
2602 * this can be detected because only after OT_LEAVESTATION, current_order |
|
2603 * will be reset to nothing. (That also happens if no order, but in that case |
|
2604 * it won't hit the point in code where may_reverse is checked) |
|
2605 */ |
|
2606 bool may_reverse = v->current_order.type == OT_NOTHING; |
|
2607 |
|
2608 /* check if we've reached the waypoint? */ |
|
2609 if (v->current_order.type == OT_GOTO_WAYPOINT && v->tile == v->dest_tile) { |
|
2610 UpdateVehicleTimetable(v, true); |
|
2611 v->cur_order_index++; |
|
2612 } |
|
2613 |
|
2614 /* check if we've reached a non-stop station while TTDPatch nonstop is enabled.. */ |
|
2615 if (_patches.new_nonstop && |
|
2616 v->current_order.flags & OFB_NON_STOP && |
|
2617 IsTileType(v->tile, MP_STATION) && |
|
2618 v->current_order.dest == GetStationIndex(v->tile)) { |
|
2619 UpdateVehicleTimetable(v, true); |
|
2620 v->cur_order_index++; |
|
2621 } |
|
2622 |
|
2623 /* Get the current order */ |
|
2624 if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; |
|
2625 |
|
2626 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
|
2627 |
|
2628 /* If no order, do nothing. */ |
|
2629 if (order == NULL) { |
|
2630 v->current_order.Free(); |
|
2631 v->dest_tile = 0; |
|
2632 return false; |
|
2633 } |
|
2634 |
|
2635 /* If it is unchanged, keep it. */ |
|
2636 if (order->type == v->current_order.type && |
|
2637 order->flags == v->current_order.flags && |
|
2638 order->dest == v->current_order.dest) |
|
2639 return false; |
|
2640 |
|
2641 /* Otherwise set it, and determine the destination tile. */ |
|
2642 v->current_order = *order; |
|
2643 |
|
2644 v->dest_tile = 0; |
|
2645 |
|
2646 InvalidateVehicleOrder(v); |
|
2647 |
|
2648 switch (order->type) { |
|
2649 case OT_GOTO_STATION: |
|
2650 if (order->dest == v->last_station_visited) |
|
2651 v->last_station_visited = INVALID_STATION; |
|
2652 v->dest_tile = GetStation(order->dest)->xy; |
|
2653 break; |
|
2654 |
|
2655 case OT_GOTO_DEPOT: |
|
2656 v->dest_tile = GetDepot(order->dest)->xy; |
|
2657 break; |
|
2658 |
|
2659 case OT_GOTO_WAYPOINT: |
|
2660 v->dest_tile = GetWaypoint(order->dest)->xy; |
|
2661 break; |
|
2662 |
|
2663 default: |
|
2664 return false; |
|
2665 } |
|
2666 |
|
2667 return may_reverse && CheckReverseTrain(v); |
|
2668 } |
2601 } |
2669 |
2602 |
2670 void Train::MarkDirty() |
2603 void Train::MarkDirty() |
2671 { |
2604 { |
2672 Vehicle *v = this; |
2605 Vehicle *v = this; |
2721 /* check if a train ever visited this station before */ |
2654 /* check if a train ever visited this station before */ |
2722 Station *st = GetStation(station); |
2655 Station *st = GetStation(station); |
2723 if (!(st->had_vehicle_of_type & HVOT_TRAIN)) { |
2656 if (!(st->had_vehicle_of_type & HVOT_TRAIN)) { |
2724 st->had_vehicle_of_type |= HVOT_TRAIN; |
2657 st->had_vehicle_of_type |= HVOT_TRAIN; |
2725 SetDParam(0, st->index); |
2658 SetDParam(0, st->index); |
2726 uint32 flags = v->owner == _local_player ? |
|
2727 NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : |
|
2728 NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ARRIVAL_OTHER, 0); |
|
2729 AddNewsItem( |
2659 AddNewsItem( |
2730 STR_8801_CITIZENS_CELEBRATE_FIRST, |
2660 STR_8801_CITIZENS_CELEBRATE_FIRST, |
2731 flags, |
2661 NM_THIN, NF_VIEWPORT | NF_VEHICLE, v->owner == _local_player ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE, |
2732 v->index, |
2662 v->index, |
2733 0 |
2663 0 |
2734 ); |
2664 ); |
2735 } |
2665 } |
2736 |
2666 |
2737 v->BeginLoading(); |
2667 v->BeginLoading(); |
2738 v->current_order.dest = 0; |
|
2739 } |
2668 } |
2740 |
2669 |
2741 static byte AfterSetTrainPos(Vehicle *v, bool new_tile) |
2670 static byte AfterSetTrainPos(Vehicle *v, bool new_tile) |
2742 { |
2671 { |
2743 byte old_z = v->z_pos; |
2672 byte old_z = v->z_pos; |
2830 {256 / 4, 256 / 2, 256 / 4, 2}, ///< monorail |
2759 {256 / 4, 256 / 2, 256 / 4, 2}, ///< monorail |
2831 {0, 256 / 2, 256 / 4, 2}, ///< maglev |
2760 {0, 256 / 2, 256 / 4, 2}, ///< maglev |
2832 }; |
2761 }; |
2833 |
2762 |
2834 /** Modify the speed of the vehicle due to a turn */ |
2763 /** Modify the speed of the vehicle due to a turn */ |
2835 static inline void AffectSpeedByDirChange(Vehicle* v, Direction new_dir) |
2764 static inline void AffectSpeedByDirChange(Vehicle *v, Direction new_dir) |
2836 { |
2765 { |
2837 if (_patches.realistic_acceleration) return; |
2766 if (_patches.realistic_acceleration) return; |
2838 |
2767 |
2839 DirDiff diff = DirDifference(v->direction, new_dir); |
2768 DirDiff diff = DirDifference(v->direction, new_dir); |
2840 if (diff == DIRDIFF_SAME) return; |
2769 if (diff == DIRDIFF_SAME) return; |
2856 uint16 spd = v->cur_speed + rsp->z_down; |
2785 uint16 spd = v->cur_speed + rsp->z_down; |
2857 if (spd <= v->max_speed) v->cur_speed = spd; |
2786 if (spd <= v->max_speed) v->cur_speed = spd; |
2858 } |
2787 } |
2859 } |
2788 } |
2860 |
2789 |
2861 static const DiagDirection _otherside_signal_directions[] = { |
|
2862 DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, INVALID_DIAGDIR, INVALID_DIAGDIR, |
|
2863 DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE |
|
2864 }; |
|
2865 |
|
2866 static void TrainMovedChangeSignals(TileIndex tile, DiagDirection dir) |
2790 static void TrainMovedChangeSignals(TileIndex tile, DiagDirection dir) |
2867 { |
2791 { |
2868 if (IsTileType(tile, MP_RAILWAY) && |
2792 if (IsTileType(tile, MP_RAILWAY) && |
2869 GetRailTileType(tile) == RAIL_TILE_SIGNALS) { |
2793 GetRailTileType(tile) == RAIL_TILE_SIGNALS) { |
2870 uint i = FindFirstBit2x64(GetTrackBits(tile) * 0x101 & _reachable_tracks[dir]); |
2794 TrackdirBits tracks = TrackBitsToTrackdirBits(GetTrackBits(tile)) & DiagdirReachesTrackdirs(dir); |
2871 UpdateSignalsOnSegment(tile, _otherside_signal_directions[i], GetTileOwner(tile)); |
2795 Trackdir trackdir = FindFirstTrackdir(tracks); |
|
2796 UpdateSignalsOnSegment(tile, TrackdirToExitdir(trackdir), GetTileOwner(tile)); |
2872 } |
2797 } |
2873 } |
2798 } |
2874 |
2799 |
2875 |
2800 |
2876 static void SetVehicleCrashed(Vehicle *v) |
2801 static void SetVehicleCrashed(Vehicle *v) |
2898 |
2823 |
2899 /* must be updated after the train has been marked crashed */ |
2824 /* must be updated after the train has been marked crashed */ |
2900 if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing); |
2825 if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing); |
2901 } |
2826 } |
2902 |
2827 |
2903 static uint CountPassengersInTrain(const Vehicle* v) |
2828 static uint CountPassengersInTrain(const Vehicle *v) |
2904 { |
2829 { |
2905 uint num = 0; |
2830 uint num = 0; |
2906 BEGIN_ENUM_WAGONS(v) |
2831 BEGIN_ENUM_WAGONS(v) |
2907 if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo.Count(); |
2832 if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo.Count(); |
2908 END_ENUM_WAGONS(v) |
2833 END_ENUM_WAGONS(v) |
2909 return num; |
2834 return num; |
2910 } |
2835 } |
2911 |
2836 |
2912 struct TrainCollideChecker { |
2837 struct TrainCollideChecker { |
2913 Vehicle *v; |
2838 Vehicle *v; ///< vehicle we are testing for collision |
2914 uint num; |
2839 uint num; ///< number of dead if train collided |
2915 }; |
2840 }; |
2916 |
2841 |
2917 static void *FindTrainCollideEnum(Vehicle *v, void *data) |
2842 static void *FindTrainCollideEnum(Vehicle *v, void *data) |
2918 { |
2843 { |
2919 TrainCollideChecker* tcc = (TrainCollideChecker*)data; |
2844 TrainCollideChecker *tcc = (TrainCollideChecker*)data; |
2920 |
2845 |
2921 if (v->type != VEH_TRAIN) return NULL; |
2846 if (v->type != VEH_TRAIN) return NULL; |
2922 |
2847 |
2923 /* get first vehicle now to make most usual checks faster */ |
2848 /* get first vehicle now to make most usual checks faster */ |
2924 Vehicle *coll = v->First(); |
2849 Vehicle *coll = v->First(); |
2975 /* any dead -> no crash */ |
2900 /* any dead -> no crash */ |
2976 if (tcc.num == 0) return; |
2901 if (tcc.num == 0) return; |
2977 |
2902 |
2978 SetDParam(0, tcc.num); |
2903 SetDParam(0, tcc.num); |
2979 AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL, |
2904 AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL, |
2980 NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, 0), |
2905 NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE, |
2981 v->index, |
2906 v->index, |
2982 0 |
2907 0 |
2983 ); |
2908 ); |
2984 |
2909 |
2985 ModifyStationRatingAround(v->tile, v->owner, -160, 30); |
2910 ModifyStationRatingAround(v->tile, v->owner, -160, 30); |
2996 if (diff == DIRDIFF_90RIGHT || (v->cur_speed <= 5 && diff <= DIRDIFF_REVERSE)) return v; |
2921 if (diff == DIRDIFF_90RIGHT || (v->cur_speed <= 5 && diff <= DIRDIFF_REVERSE)) return v; |
2997 } |
2922 } |
2998 return NULL; |
2923 return NULL; |
2999 } |
2924 } |
3000 |
2925 |
3001 static void TrainController(Vehicle *v, bool update_image) |
2926 static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image) |
3002 { |
2927 { |
3003 Vehicle *prev; |
2928 Vehicle *prev; |
3004 |
2929 |
3005 /* For every vehicle after and including the given vehicle */ |
2930 /* For every vehicle after and including the given vehicle */ |
3006 for (prev = v->Previous(); v != NULL; prev = v, v = v->Next()) { |
2931 for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) { |
3007 DiagDirection enterdir = DIAGDIR_BEGIN; |
2932 DiagDirection enterdir = DIAGDIR_BEGIN; |
3008 bool update_signals_crossing = false; // will we update signals or crossing state? |
2933 bool update_signals_crossing = false; // will we update signals or crossing state? |
3009 BeginVehicleMove(v); |
2934 BeginVehicleMove(v); |
3010 |
2935 |
3011 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
2936 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
3044 enterdir = DirToDiagDir(dir); |
2969 enterdir = DirToDiagDir(dir); |
3045 assert(IsValidDiagDirection(enterdir)); |
2970 assert(IsValidDiagDirection(enterdir)); |
3046 |
2971 |
3047 /* Get the status of the tracks in the new tile and mask |
2972 /* Get the status of the tracks in the new tile and mask |
3048 * away the bits that aren't reachable. */ |
2973 * away the bits that aren't reachable. */ |
3049 TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir)) & _reachable_tracks[enterdir]; |
2974 TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir)); |
3050 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts); |
2975 TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(enterdir); |
3051 TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts)); |
2976 |
|
2977 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs; |
|
2978 TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs); |
3052 |
2979 |
3053 TrackBits bits = TrackdirBitsToTrackBits(trackdirbits); |
2980 TrackBits bits = TrackdirBitsToTrackBits(trackdirbits); |
3054 if (_patches.pathfinder_for_trains != VPF_NTP && _patches.forbid_90_deg && prev == NULL) { |
2981 if (_patches.pathfinder_for_trains != VPF_NTP && _patches.forbid_90_deg && prev == NULL) { |
3055 /* We allow wagons to make 90 deg turns, because forbid_90_deg |
2982 /* We allow wagons to make 90 deg turns, because forbid_90_deg |
3056 * can be switched on halfway a turn */ |
2983 * can be switched on halfway a turn */ |
3225 DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
3152 DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
3226 InvalidateWindow(WC_COMPANY, v->owner); |
3153 InvalidateWindow(WC_COMPANY, v->owner); |
3227 } else { |
3154 } else { |
3228 /* Recalculate cached train properties */ |
3155 /* Recalculate cached train properties */ |
3229 TrainConsistChanged(first); |
3156 TrainConsistChanged(first); |
3230 InvalidateWindow(WC_VEHICLE_DETAILS, first->index); |
|
3231 /* Update the depot window if the first vehicle is in depot - |
3157 /* Update the depot window if the first vehicle is in depot - |
3232 * if v == first, then it is updated in PreDestructor() */ |
3158 * if v == first, then it is updated in PreDestructor() */ |
3233 if (first->u.rail.track == TRACK_BIT_DEPOT) { |
3159 if (first->u.rail.track == TRACK_BIT_DEPOT) { |
3234 InvalidateWindow(WC_VEHICLE_DEPOT, first->tile); |
3160 InvalidateWindow(WC_VEHICLE_DEPOT, first->tile); |
3235 } |
3161 } |
3270 v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]); |
3196 v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]); |
3271 BeginVehicleMove(v); |
3197 BeginVehicleMove(v); |
3272 v->UpdateDeltaXY(v->direction); |
3198 v->UpdateDeltaXY(v->direction); |
3273 v->cur_image = v->GetImage(v->direction); |
3199 v->cur_image = v->GetImage(v->direction); |
3274 /* Refrain from updating the z position of the vehicle when on |
3200 /* Refrain from updating the z position of the vehicle when on |
3275 a bridge, because AfterSetTrainPos will put the vehicle under |
3201 * a bridge, because AfterSetTrainPos will put the vehicle under |
3276 the bridge in that case */ |
3202 * the bridge in that case */ |
3277 if (v->u.rail.track != TRACK_BIT_WORMHOLE) AfterSetTrainPos(v, false); |
3203 if (v->u.rail.track != TRACK_BIT_WORMHOLE) AfterSetTrainPos(v, false); |
3278 } |
3204 } |
3279 } while ((v = v->Next()) != NULL); |
3205 } while ((v = v->Next()) != NULL); |
3280 } |
3206 } |
3281 |
3207 |
3475 DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); |
3401 DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); |
3476 /* Calculate next tile */ |
3402 /* Calculate next tile */ |
3477 TileIndex tile = v->tile + TileOffsByDiagDir(dir); |
3403 TileIndex tile = v->tile + TileOffsByDiagDir(dir); |
3478 |
3404 |
3479 /* Determine the track status on the next tile */ |
3405 /* Determine the track status on the next tile */ |
3480 TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0, ReverseDiagDir(dir)) & _reachable_tracks[dir]; |
3406 TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0, ReverseDiagDir(dir)); |
3481 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts); |
3407 TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(dir); |
3482 TrackdirBits red_signals = TrackStatusToRedSignals(ts); |
3408 |
|
3409 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs; |
|
3410 TrackdirBits red_signals = TrackStatusToRedSignals(ts) & reachable_trackdirs; |
3483 |
3411 |
3484 /* We are sure the train is not entering a depot, it is detected above */ |
3412 /* We are sure the train is not entering a depot, it is detected above */ |
3485 |
3413 |
3486 /* mask unreachable track bits if we are forbidden to do 90deg turns */ |
3414 /* mask unreachable track bits if we are forbidden to do 90deg turns */ |
3487 TrackBits bits = TrackdirBitsToTrackBits(trackdirbits); |
3415 TrackBits bits = TrackdirBitsToTrackBits(trackdirbits); |
3609 /* Delete flooded standalone wagon chain */ |
3537 /* Delete flooded standalone wagon chain */ |
3610 if (++this->u.rail.crash_anim_pos >= 4400) DeleteVehicleChain(this); |
3538 if (++this->u.rail.crash_anim_pos >= 4400) DeleteVehicleChain(this); |
3611 } |
3539 } |
3612 } |
3540 } |
3613 |
3541 |
3614 #define MAX_ACCEPTABLE_DEPOT_DIST 16 |
|
3615 |
|
3616 static void CheckIfTrainNeedsService(Vehicle *v) |
3542 static void CheckIfTrainNeedsService(Vehicle *v) |
3617 { |
3543 { |
3618 if (_patches.servint_trains == 0 || !VehicleNeedsService(v)) return; |
3544 static const uint MAX_ACCEPTABLE_DEPOT_DIST = 16; |
|
3545 |
|
3546 if (_patches.servint_trains == 0 || !v->NeedsAutomaticServicing()) return; |
3619 if (v->IsInDepot()) { |
3547 if (v->IsInDepot()) { |
3620 VehicleServiceInDepot(v); |
3548 VehicleServiceInDepot(v); |
3621 return; |
3549 return; |
3622 } |
3550 } |
3623 |
3551 |
3624 TrainFindDepotData tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST); |
3552 TrainFindDepotData tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST); |
3625 /* Only go to the depot if it is not too far out of our way. */ |
3553 /* Only go to the depot if it is not too far out of our way. */ |
3626 if (tfdd.best_length == (uint)-1 || tfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) { |
3554 if (tfdd.best_length == (uint)-1 || tfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) { |
3627 if (v->current_order.type == OT_GOTO_DEPOT) { |
3555 if (v->current_order.IsType(OT_GOTO_DEPOT)) { |
3628 /* If we were already heading for a depot but it has |
3556 /* If we were already heading for a depot but it has |
3629 * suddenly moved farther away, we continue our normal |
3557 * suddenly moved farther away, we continue our normal |
3630 * schedule? */ |
3558 * schedule? */ |
3631 v->current_order.type = OT_DUMMY; |
3559 v->current_order.MakeDummy(); |
3632 v->current_order.flags = 0; |
|
3633 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
3560 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
3634 } |
3561 } |
3635 return; |
3562 return; |
3636 } |
3563 } |
3637 |
3564 |
3638 const Depot* depot = GetDepotByTile(tfdd.tile); |
3565 const Depot *depot = GetDepotByTile(tfdd.tile); |
3639 |
3566 |
3640 if (v->current_order.type == OT_GOTO_DEPOT && |
3567 if (v->current_order.IsType(OT_GOTO_DEPOT) && |
3641 v->current_order.dest != depot->index && |
3568 v->current_order.GetDestination() != depot->index && |
3642 !Chance16(3, 16)) { |
3569 !Chance16(3, 16)) { |
3643 return; |
3570 return; |
3644 } |
3571 } |
3645 |
3572 |
3646 v->current_order.type = OT_GOTO_DEPOT; |
3573 v->current_order.MakeGoToDepot(depot->index, ODTFB_SERVICE); |
3647 v->current_order.flags = OFB_NON_STOP; |
|
3648 v->current_order.dest = depot->index; |
|
3649 v->dest_tile = tfdd.tile; |
3574 v->dest_tile = tfdd.tile; |
3650 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
3575 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
3651 } |
3576 } |
3652 |
3577 |
3653 void Train::OnNewDay() |
3578 void Train::OnNewDay() |
3696 if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->GetDisplayProfitThisYear() < 0) { |
3621 if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->GetDisplayProfitThisYear() < 0) { |
3697 SetDParam(1, v->GetDisplayProfitThisYear()); |
3622 SetDParam(1, v->GetDisplayProfitThisYear()); |
3698 SetDParam(0, v->unitnumber); |
3623 SetDParam(0, v->unitnumber); |
3699 AddNewsItem( |
3624 AddNewsItem( |
3700 STR_TRAIN_IS_UNPROFITABLE, |
3625 STR_TRAIN_IS_UNPROFITABLE, |
3701 NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), |
3626 NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, |
3702 v->index, |
3627 v->index, |
3703 0); |
3628 0); |
3704 } |
3629 } |
3705 |
3630 |
3706 v->profit_last_year = v->profit_this_year; |
3631 v->profit_last_year = v->profit_this_year; |