branch | gamebalance |
changeset 9895 | 7bd07f43b0e3 |
parent 6524 | 44e22a9b2c97 |
child 9903 | dc85aaa556ae |
9894:70d78ac95d6c | 9895:7bd07f43b0e3 |
---|---|
35 #include "date.h" |
35 #include "date.h" |
36 #include "newgrf_callbacks.h" |
36 #include "newgrf_callbacks.h" |
37 #include "newgrf_engine.h" |
37 #include "newgrf_engine.h" |
38 #include "newgrf_sound.h" |
38 #include "newgrf_sound.h" |
39 #include "helpers.hpp" |
39 #include "helpers.hpp" |
40 #include "cargotype.h" |
|
41 |
40 |
42 #define INVALID_COORD (-0x8000) |
41 #define INVALID_COORD (-0x8000) |
43 #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6)) |
42 #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6)) |
44 |
43 |
45 |
44 |
85 |
84 |
86 /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. |
85 /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. |
87 * TODO - This is just a temporary stage, this will be removed. */ |
86 * TODO - This is just a temporary stage, this will be removed. */ |
88 for (v = GetVehicle(start_item); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) { |
87 for (v = GetVehicle(start_item); v != NULL; v = (v->index + 1U < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) { |
89 v->index = start_item++; |
88 v->index = start_item++; |
90 v->type = VEH_Invalid; |
89 v->type = VEH_INVALID; |
91 } |
90 } |
92 } |
91 } |
93 |
92 |
94 /* Initialize the vehicle-pool */ |
93 /* Initialize the vehicle-pool */ |
95 DEFINE_OLD_POOL(Vehicle, Vehicle, VehiclePoolNewBlock, NULL) |
94 DEFINE_OLD_POOL(Vehicle, Vehicle, VehiclePoolNewBlock, NULL) |
117 } |
116 } |
118 |
117 |
119 StringID VehicleInTheWayErrMsg(const Vehicle* v) |
118 StringID VehicleInTheWayErrMsg(const Vehicle* v) |
120 { |
119 { |
121 switch (v->type) { |
120 switch (v->type) { |
122 case VEH_Train: return STR_8803_TRAIN_IN_THE_WAY; |
121 case VEH_TRAIN: return STR_8803_TRAIN_IN_THE_WAY; |
123 case VEH_Road: return STR_9000_ROAD_VEHICLE_IN_THE_WAY; |
122 case VEH_ROAD: return STR_9000_ROAD_VEHICLE_IN_THE_WAY; |
124 case VEH_Aircraft: return STR_A015_AIRCRAFT_IN_THE_WAY; |
123 case VEH_AIRCRAFT: return STR_A015_AIRCRAFT_IN_THE_WAY; |
125 default: return STR_980E_SHIP_IN_THE_WAY; |
124 default: return STR_980E_SHIP_IN_THE_WAY; |
126 } |
125 } |
127 } |
126 } |
128 |
127 |
129 static void *EnsureNoVehicleProc(Vehicle *v, void *data) |
128 static void *EnsureNoVehicleProc(Vehicle *v, void *data) |
130 { |
129 { |
131 if (v->tile != *(const TileIndex*)data || v->type == VEH_Disaster) |
130 if (v->tile != *(const TileIndex*)data || v->type == VEH_DISASTER) |
132 return NULL; |
131 return NULL; |
133 |
132 |
134 _error_message = VehicleInTheWayErrMsg(v); |
133 _error_message = VehicleInTheWayErrMsg(v); |
135 return v; |
134 return v; |
136 } |
135 } |
142 |
141 |
143 static void *EnsureNoVehicleProcZ(Vehicle *v, void *data) |
142 static void *EnsureNoVehicleProcZ(Vehicle *v, void *data) |
144 { |
143 { |
145 const TileInfo *ti = (const TileInfo*)data; |
144 const TileInfo *ti = (const TileInfo*)data; |
146 |
145 |
147 if (v->tile != ti->tile || v->type == VEH_Disaster) return NULL; |
146 if (v->tile != ti->tile || v->type == VEH_DISASTER) return NULL; |
148 if (v->z_pos > ti->z) return NULL; |
147 if (v->z_pos > ti->z) return NULL; |
149 |
148 |
150 _error_message = VehicleInTheWayErrMsg(v); |
149 _error_message = VehicleInTheWayErrMsg(v); |
151 return v; |
150 return v; |
152 } |
151 } |
184 Swap(x1, x2); |
183 Swap(x1, x2); |
185 Swap(y1, y2); |
184 Swap(y1, y2); |
186 } |
185 } |
187 FOR_ALL_VEHICLES(veh) { |
186 FOR_ALL_VEHICLES(veh) { |
188 if (without_crashed && (veh->vehstatus & VS_CRASHED) != 0) continue; |
187 if (without_crashed && (veh->vehstatus & VS_CRASHED) != 0) continue; |
189 if ((veh->type == VEH_Train || veh->type == VEH_Road) && (z==0xFF || veh->z_pos == z)) { |
188 if ((veh->type == VEH_TRAIN || veh->type == VEH_ROAD) && (z==0xFF || veh->z_pos == z)) { |
190 if ((veh->x_pos>>4) >= x1 && (veh->x_pos>>4) <= x2 && |
189 if ((veh->x_pos>>4) >= x1 && (veh->x_pos>>4) <= x2 && |
191 (veh->y_pos>>4) >= y1 && (veh->y_pos>>4) <= y2) { |
190 (veh->y_pos>>4) >= y1 && (veh->y_pos>>4) <= y2) { |
192 return veh; |
191 return veh; |
193 } |
192 } |
194 } |
193 } |
215 v->right_coord = pt.x + spr->width + 2; |
214 v->right_coord = pt.x + spr->width + 2; |
216 v->bottom_coord = pt.y + spr->height + 2; |
215 v->bottom_coord = pt.y + spr->height + 2; |
217 } |
216 } |
218 |
217 |
219 // Called after load to update coordinates |
218 // Called after load to update coordinates |
220 void AfterLoadVehicles(void) |
219 void AfterLoadVehicles() |
221 { |
220 { |
222 Vehicle *v; |
221 Vehicle *v; |
223 |
222 |
224 FOR_ALL_VEHICLES(v) { |
223 FOR_ALL_VEHICLES(v) { |
225 v->first = NULL; |
224 v->first = NULL; |
226 if (v->type == VEH_Train) v->u.rail.first_engine = INVALID_ENGINE; |
225 if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE; |
227 } |
226 } |
228 |
227 |
229 FOR_ALL_VEHICLES(v) { |
228 FOR_ALL_VEHICLES(v) { |
230 if (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v))) |
229 if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) |
231 TrainConsistChanged(v); |
230 TrainConsistChanged(v); |
232 } |
231 } |
233 |
232 |
234 FOR_ALL_VEHICLES(v) { |
233 FOR_ALL_VEHICLES(v) { |
235 switch (v->type) { |
234 switch (v->type) { |
236 case VEH_Train: v->cur_image = GetTrainImage(v, v->direction); break; |
235 case VEH_TRAIN: v->cur_image = GetTrainImage(v, v->direction); break; |
237 case VEH_Road: v->cur_image = GetRoadVehImage(v, v->direction); break; |
236 case VEH_ROAD: v->cur_image = GetRoadVehImage(v, v->direction); break; |
238 case VEH_Ship: v->cur_image = GetShipImage(v, v->direction); break; |
237 case VEH_SHIP: v->cur_image = GetShipImage(v, v->direction); break; |
239 case VEH_Aircraft: |
238 case VEH_AIRCRAFT: |
240 if (IsNormalAircraft(v)) { |
239 if (IsNormalAircraft(v)) { |
241 v->cur_image = GetAircraftImage(v, v->direction); |
240 v->cur_image = GetAircraftImage(v, v->direction); |
242 |
241 |
243 /* The plane's shadow will have the same image as the plane */ |
242 /* The plane's shadow will have the same image as the plane */ |
244 Vehicle *shadow = v->next; |
243 Vehicle *shadow = v->next; |
265 memset(v, 0, sizeof(Vehicle)); |
264 memset(v, 0, sizeof(Vehicle)); |
266 v->index = index; |
265 v->index = index; |
267 |
266 |
268 assert(v->orders == NULL); |
267 assert(v->orders == NULL); |
269 |
268 |
270 v->type = VEH_Invalid; |
269 v->type = VEH_INVALID; |
271 v->left_coord = INVALID_COORD; |
270 v->left_coord = INVALID_COORD; |
272 v->first = NULL; |
271 v->first = NULL; |
273 v->next = NULL; |
272 v->next = NULL; |
274 v->next_hash = NULL; |
273 v->next_hash = NULL; |
275 v->string_id = 0; |
274 v->string_id = 0; |
282 |
281 |
283 /** |
282 /** |
284 * Get a value for a vehicle's random_bits. |
283 * Get a value for a vehicle's random_bits. |
285 * @return A random value from 0 to 255. |
284 * @return A random value from 0 to 255. |
286 */ |
285 */ |
287 byte VehicleRandomBits(void) |
286 byte VehicleRandomBits() |
288 { |
287 { |
289 return GB(Random(), 0, 8); |
288 return GB(Random(), 0, 8); |
290 } |
289 } |
291 |
290 |
292 Vehicle *ForceAllocateSpecialVehicle(void) |
291 Vehicle *ForceAllocateSpecialVehicle() |
293 { |
292 { |
294 /* This stays a strange story.. there should always be room for special |
293 /* This stays a strange story.. there should always be room for special |
295 * vehicles (special effects all over the map), but with 65k of vehicles |
294 * vehicles (special effects all over the map), but with 65k of vehicles |
296 * is this realistic to double-check for that? For now we just reserve |
295 * is this realistic to double-check for that? For now we just reserve |
297 * BLOCKS_FOR_SPECIAL_VEHICLES times block_size vehicles that may only |
296 * BLOCKS_FOR_SPECIAL_VEHICLES times block_size vehicles that may only |
342 |
341 |
343 return NULL; |
342 return NULL; |
344 } |
343 } |
345 |
344 |
346 |
345 |
347 Vehicle *AllocateVehicle(void) |
346 Vehicle *AllocateVehicle() |
348 { |
347 { |
349 VehicleID counter = 0; |
348 VehicleID counter = 0; |
350 return AllocateSingleVehicle(&counter); |
349 return AllocateSingleVehicle(&counter); |
351 } |
350 } |
352 |
351 |
444 v->next_hash = *new_hash; |
443 v->next_hash = *new_hash; |
445 *new_hash = v; |
444 *new_hash = v; |
446 } |
445 } |
447 } |
446 } |
448 |
447 |
449 void ResetVehiclePosHash(void) |
448 void ResetVehiclePosHash() |
450 { |
449 { |
451 memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash)); |
450 memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash)); |
452 } |
451 } |
453 |
452 |
454 void InitializeVehicles(void) |
453 void InitializeVehicles() |
455 { |
454 { |
456 uint i; |
455 uint i; |
457 |
456 |
458 /* Clean the vehicle pool, and reserve enough blocks |
457 /* Clean the vehicle pool, and reserve enough blocks |
459 * for the special vehicles, plus one for all the other |
458 * for the special vehicles, plus one for all the other |
481 */ |
480 */ |
482 static Vehicle *GetPrevVehicleInChain_bruteforce(const Vehicle *v) |
481 static Vehicle *GetPrevVehicleInChain_bruteforce(const Vehicle *v) |
483 { |
482 { |
484 Vehicle *u; |
483 Vehicle *u; |
485 |
484 |
486 FOR_ALL_VEHICLES(u) if (u->type == VEH_Train && u->next == v) return u; |
485 FOR_ALL_VEHICLES(u) if (u->type == VEH_TRAIN && u->next == v) return u; |
487 |
486 |
488 return NULL; |
487 return NULL; |
489 } |
488 } |
490 |
489 |
491 /** Find the previous vehicle in a chain, by using the v->first cache. |
490 /** Find the previous vehicle in a chain, by using the v->first cache. |
514 Vehicle *GetFirstVehicleInChain(const Vehicle *v) |
513 Vehicle *GetFirstVehicleInChain(const Vehicle *v) |
515 { |
514 { |
516 Vehicle* u; |
515 Vehicle* u; |
517 |
516 |
518 assert(v != NULL); |
517 assert(v != NULL); |
519 assert(v->type == VEH_Train); |
518 assert(v->type == VEH_TRAIN); |
520 |
519 |
521 if (v->first != NULL) { |
520 if (v->first != NULL) { |
522 if (IsFrontEngine(v->first) || IsFreeWagon(v->first)) return v->first; |
521 if (IsFrontEngine(v->first) || IsFreeWagon(v->first)) return v->first; |
523 |
522 |
524 DEBUG(misc, 0, "v->first cache faulty. We shouldn't be here, rebuilding cache!"); |
523 DEBUG(misc, 0, "v->first cache faulty. We shouldn't be here, rebuilding cache!"); |
551 * @return true if the vehicle is counted in num_engines |
550 * @return true if the vehicle is counted in num_engines |
552 */ |
551 */ |
553 bool IsEngineCountable(const Vehicle *v) |
552 bool IsEngineCountable(const Vehicle *v) |
554 { |
553 { |
555 switch (v->type) { |
554 switch (v->type) { |
556 case VEH_Aircraft: return IsNormalAircraft(v); // don't count plane shadows and helicopter rotors |
555 case VEH_AIRCRAFT: return IsNormalAircraft(v); // don't count plane shadows and helicopter rotors |
557 case VEH_Train: |
556 case VEH_TRAIN: |
558 return !IsArticulatedPart(v) && // tenders and other articulated parts |
557 return !IsArticulatedPart(v) && // tenders and other articulated parts |
559 (!IsMultiheaded(v) || IsTrainEngine(v)); // rear parts of multiheaded engines |
558 (!IsMultiheaded(v) || IsTrainEngine(v)); // rear parts of multiheaded engines |
560 case VEH_Road: |
559 case VEH_ROAD: |
561 case VEH_Ship: |
560 case VEH_SHIP: |
562 return true; |
561 return true; |
563 default: return false; // Only count player buildable vehicles |
562 default: return false; // Only count player buildable vehicles |
564 } |
563 } |
565 } |
564 } |
566 |
565 |
572 } |
571 } |
573 |
572 |
574 DeleteVehicleNews(v->index, INVALID_STRING_ID); |
573 DeleteVehicleNews(v->index, INVALID_STRING_ID); |
575 |
574 |
576 DeleteName(v->string_id); |
575 DeleteName(v->string_id); |
577 if (v->type == VEH_Road) ClearSlot(v); |
576 if (v->type == VEH_ROAD) ClearSlot(v); |
578 |
577 |
579 if (v->type != VEH_Train || (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v)))) { |
578 if (v->type != VEH_TRAIN || (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v)))) { |
580 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
579 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
581 } |
580 } |
582 |
581 |
583 UpdateVehiclePosHash(v, INVALID_COORD, 0); |
582 UpdateVehiclePosHash(v, INVALID_COORD, 0); |
584 v->next_hash = NULL; |
583 v->next_hash = NULL; |
604 void RoadVeh_Tick(Vehicle *v); |
603 void RoadVeh_Tick(Vehicle *v); |
605 void Ship_Tick(Vehicle *v); |
604 void Ship_Tick(Vehicle *v); |
606 void Train_Tick(Vehicle *v); |
605 void Train_Tick(Vehicle *v); |
607 static void EffectVehicle_Tick(Vehicle *v); |
606 static void EffectVehicle_Tick(Vehicle *v); |
608 void DisasterVehicle_Tick(Vehicle *v); |
607 void DisasterVehicle_Tick(Vehicle *v); |
609 static int32 MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs); |
|
610 |
608 |
611 // head of the linked list to tell what vehicles that visited a depot in a tick |
609 // head of the linked list to tell what vehicles that visited a depot in a tick |
612 static Vehicle* _first_veh_in_depot_list; |
610 static Vehicle* _first_veh_in_depot_list; |
613 |
611 |
614 /** Adds a vehicle to the list of vehicles, that visited a depot this tick |
612 /** Adds a vehicle to the list of vehicles, that visited a depot this tick |
645 Aircraft_Tick, |
643 Aircraft_Tick, |
646 EffectVehicle_Tick, |
644 EffectVehicle_Tick, |
647 DisasterVehicle_Tick, |
645 DisasterVehicle_Tick, |
648 }; |
646 }; |
649 |
647 |
650 void CallVehicleTicks(void) |
648 void CallVehicleTicks() |
651 { |
649 { |
652 Vehicle *v; |
650 Vehicle *v; |
653 |
651 |
654 #ifdef ENABLE_NETWORK |
652 #ifdef ENABLE_NETWORK |
655 // hotfix for desync problem: |
653 // hotfix for desync problem: |
663 |
661 |
664 FOR_ALL_VEHICLES(v) { |
662 FOR_ALL_VEHICLES(v) { |
665 _vehicle_tick_procs[v->type](v); |
663 _vehicle_tick_procs[v->type](v); |
666 |
664 |
667 switch (v->type) { |
665 switch (v->type) { |
668 case VEH_Train: |
666 case VEH_TRAIN: |
669 case VEH_Road: |
667 case VEH_ROAD: |
670 case VEH_Aircraft: |
668 case VEH_AIRCRAFT: |
671 case VEH_Ship: |
669 case VEH_SHIP: |
672 if (v->type == VEH_Train && IsTrainWagon(v)) continue; |
670 if (v->type == VEH_TRAIN && IsTrainWagon(v)) continue; |
673 if (v->type == VEH_Aircraft && v->subtype != AIR_HELICOPTER) continue; |
671 if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue; |
674 |
672 |
675 v->motion_counter += (v->direction & 1) ? (v->cur_speed * 3) / 4 : v->cur_speed; |
673 v->motion_counter += (v->direction & 1) ? (v->cur_speed * 3) / 4 : v->cur_speed; |
676 /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */ |
674 /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */ |
677 if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING); |
675 if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING); |
678 |
676 |
699 |
697 |
700 //special handling of aircraft |
698 //special handling of aircraft |
701 |
699 |
702 //if the aircraft carries passengers and is NOT full, then |
700 //if the aircraft carries passengers and is NOT full, then |
703 //continue loading, no matter how much mail is in |
701 //continue loading, no matter how much mail is in |
704 if (v->type == VEH_Aircraft && |
702 if (v->type == VEH_AIRCRAFT && |
705 v->cargo_type == CT_PASSENGERS && |
703 IsCargoInClass(v->cargo_type, CC_PASSENGERS) && |
706 v->cargo_cap != v->cargo_count) { |
704 v->cargo_cap != v->cargo_count) { |
707 return true; |
705 return true; |
708 } |
706 } |
709 |
707 |
710 // patch should return "true" to continue loading, i.e. when there is no cargo type that is fully loaded. |
708 // patch should return "true" to continue loading, i.e. when there is no cargo type that is fully loaded. |
735 bool CanFillVehicle(Vehicle *v) |
733 bool CanFillVehicle(Vehicle *v) |
736 { |
734 { |
737 TileIndex tile = v->tile; |
735 TileIndex tile = v->tile; |
738 |
736 |
739 if (IsTileType(tile, MP_STATION) || |
737 if (IsTileType(tile, MP_STATION) || |
740 (v->type == VEH_Ship && ( |
738 (v->type == VEH_SHIP && ( |
741 IsTileType(TILE_ADDXY(tile, 1, 0), MP_STATION) || |
739 IsTileType(TILE_ADDXY(tile, 1, 0), MP_STATION) || |
742 IsTileType(TILE_ADDXY(tile, -1, 0), MP_STATION) || |
740 IsTileType(TILE_ADDXY(tile, -1, 0), MP_STATION) || |
743 IsTileType(TILE_ADDXY(tile, 0, 1), MP_STATION) || |
741 IsTileType(TILE_ADDXY(tile, 0, 1), MP_STATION) || |
744 IsTileType(TILE_ADDXY(tile, 0, -1), MP_STATION) || |
742 IsTileType(TILE_ADDXY(tile, 0, -1), MP_STATION) || |
745 IsTileType(TILE_ADDXY(tile, -2, 0), MP_STATION) |
743 IsTileType(TILE_ADDXY(tile, -2, 0), MP_STATION) |
789 int32 GetRefitCost(EngineID engine_type) |
787 int32 GetRefitCost(EngineID engine_type) |
790 { |
788 { |
791 int32 base_cost = 0; |
789 int32 base_cost = 0; |
792 |
790 |
793 switch (GetEngine(engine_type)->type) { |
791 switch (GetEngine(engine_type)->type) { |
794 case VEH_Ship: base_cost = _price.ship_base; break; |
792 case VEH_SHIP: base_cost = _price.ship_base; break; |
795 case VEH_Road: base_cost = _price.roadveh_base; break; |
793 case VEH_ROAD: base_cost = _price.roadveh_base; break; |
796 case VEH_Aircraft: base_cost = _price.aircraft_base; break; |
794 case VEH_AIRCRAFT: base_cost = _price.aircraft_base; break; |
797 case VEH_Train: |
795 case VEH_TRAIN: |
798 base_cost = 2 * ((RailVehInfo(engine_type)->railveh_type == RAILVEH_WAGON) ? |
796 base_cost = 2 * ((RailVehInfo(engine_type)->railveh_type == RAILVEH_WAGON) ? |
799 _price.build_railwagon : _price.build_railvehicle); |
797 _price.build_railwagon : _price.build_railvehicle); |
800 break; |
798 break; |
801 default: NOT_REACHED(); break; |
799 default: NOT_REACHED(); break; |
802 } |
800 } |
1096 v->progress = 0; |
1094 v->progress = 0; |
1097 v->u.special.unk0 = 0; |
1095 v->u.special.unk0 = 0; |
1098 v->u.special.unk2 = 0; |
1096 v->u.special.unk2 = 0; |
1099 } |
1097 } |
1100 |
1098 |
1101 typedef struct BulldozerMovement { |
1099 struct BulldozerMovement { |
1102 byte direction:2; |
1100 byte direction:2; |
1103 byte image:2; |
1101 byte image:2; |
1104 byte duration:3; |
1102 byte duration:3; |
1105 } BulldozerMovement; |
1103 }; |
1106 |
1104 |
1107 static const BulldozerMovement _bulldozer_movement[] = { |
1105 static const BulldozerMovement _bulldozer_movement[] = { |
1108 { 0, 0, 4 }, |
1106 { 0, 0, 4 }, |
1109 { 3, 3, 4 }, |
1107 { 3, 3, 4 }, |
1110 { 2, 2, 7 }, |
1108 { 2, 2, 7 }, |
1170 v->cur_image = SPR_BUBBLE_GENERATE_0; |
1168 v->cur_image = SPR_BUBBLE_GENERATE_0; |
1171 v->spritenum = 0; |
1169 v->spritenum = 0; |
1172 v->progress = 0; |
1170 v->progress = 0; |
1173 } |
1171 } |
1174 |
1172 |
1175 typedef struct BubbleMovement { |
1173 struct BubbleMovement { |
1176 int8 x:4; |
1174 int8 x:4; |
1177 int8 y:4; |
1175 int8 y:4; |
1178 int8 z:4; |
1176 int8 z:4; |
1179 byte image:4; |
1177 byte image:4; |
1180 } BubbleMovement; |
1178 }; |
1181 |
1179 |
1182 #define MK(x, y, z, i) { x, y, z, i } |
1180 #define MK(x, y, z, i) { x, y, z, i } |
1183 #define ME(i) { i, 4, 0, 0 } |
1181 #define ME(i) { i, 4, 0, 0 } |
1184 |
1182 |
1185 static const BubbleMovement _bubble_float_sw[] = { |
1183 static const BubbleMovement _bubble_float_sw[] = { |
1429 { |
1427 { |
1430 Vehicle *v; |
1428 Vehicle *v; |
1431 |
1429 |
1432 v = ForceAllocateSpecialVehicle(); |
1430 v = ForceAllocateSpecialVehicle(); |
1433 if (v != NULL) { |
1431 if (v != NULL) { |
1434 v->type = VEH_Special; |
1432 v->type = VEH_SPECIAL; |
1435 v->subtype = type; |
1433 v->subtype = type; |
1436 v->x_pos = x; |
1434 v->x_pos = x; |
1437 v->y_pos = y; |
1435 v->y_pos = y; |
1438 v->z_pos = z; |
1436 v->z_pos = z; |
1439 v->z_height = v->sprite_width = v->sprite_height = 1; |
1437 v->z_height = v->sprite_width = v->sprite_height = 1; |
1540 if (CHANCE16I(1,25,r)) chance += 25; |
1538 if (CHANCE16I(1,25,r)) chance += 25; |
1541 v->breakdown_chance = min(255, chance); |
1539 v->breakdown_chance = min(255, chance); |
1542 |
1540 |
1543 /* calculate reliability value to use in comparison */ |
1541 /* calculate reliability value to use in comparison */ |
1544 rel = v->reliability; |
1542 rel = v->reliability; |
1545 if (v->type == VEH_Ship) rel += 0x6666; |
1543 if (v->type == VEH_SHIP) rel += 0x6666; |
1546 |
1544 |
1547 /* disabled breakdowns? */ |
1545 /* disabled breakdowns? */ |
1548 if (_opt.diff.vehicle_breakdowns < 1) return; |
1546 if (_opt.diff.vehicle_breakdowns < 1) return; |
1549 |
1547 |
1550 /* reduced breakdowns? */ |
1548 /* reduced breakdowns? */ |
1619 byte vehicle_type = GB(p2, 0, 5); |
1617 byte vehicle_type = GB(p2, 0, 5); |
1620 bool start_stop = HASBIT(p2, 5); |
1618 bool start_stop = HASBIT(p2, 5); |
1621 bool vehicle_list_window = HASBIT(p2, 6); |
1619 bool vehicle_list_window = HASBIT(p2, 6); |
1622 |
1620 |
1623 switch (vehicle_type) { |
1621 switch (vehicle_type) { |
1624 case VEH_Train: stop_command = CMD_START_STOP_TRAIN; break; |
1622 case VEH_TRAIN: stop_command = CMD_START_STOP_TRAIN; break; |
1625 case VEH_Road: stop_command = CMD_START_STOP_ROADVEH; break; |
1623 case VEH_ROAD: stop_command = CMD_START_STOP_ROADVEH; break; |
1626 case VEH_Ship: stop_command = CMD_START_STOP_SHIP; break; |
1624 case VEH_SHIP: stop_command = CMD_START_STOP_SHIP; break; |
1627 case VEH_Aircraft: stop_command = CMD_START_STOP_AIRCRAFT; break; |
1625 case VEH_AIRCRAFT: stop_command = CMD_START_STOP_AIRCRAFT; break; |
1628 default: return CMD_ERROR; |
1626 default: return CMD_ERROR; |
1629 } |
1627 } |
1630 |
1628 |
1631 if (vehicle_list_window) { |
1629 if (vehicle_list_window) { |
1632 uint32 id = p1; |
1630 uint32 id = p1; |
1643 int32 ret; |
1641 int32 ret; |
1644 |
1642 |
1645 if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue; |
1643 if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue; |
1646 |
1644 |
1647 if (!vehicle_list_window) { |
1645 if (!vehicle_list_window) { |
1648 if (vehicle_type == VEH_Train) { |
1646 if (vehicle_type == VEH_TRAIN) { |
1649 if (CheckTrainInDepot(v, false) == -1) continue; |
1647 if (CheckTrainInDepot(v, false) == -1) continue; |
1650 } else { |
1648 } else { |
1651 if (!(v->vehstatus & VS_HIDDEN)) continue; |
1649 if (!(v->vehstatus & VS_HIDDEN)) continue; |
1652 } |
1650 } |
1653 } |
1651 } |
1683 int32 cost = 0; |
1681 int32 cost = 0; |
1684 uint i, sell_command, total_number_vehicles; |
1682 uint i, sell_command, total_number_vehicles; |
1685 byte vehicle_type = GB(p1, 0, 8); |
1683 byte vehicle_type = GB(p1, 0, 8); |
1686 |
1684 |
1687 switch (vehicle_type) { |
1685 switch (vehicle_type) { |
1688 case VEH_Train: sell_command = CMD_SELL_RAIL_WAGON; break; |
1686 case VEH_TRAIN: sell_command = CMD_SELL_RAIL_WAGON; break; |
1689 case VEH_Road: sell_command = CMD_SELL_ROAD_VEH; break; |
1687 case VEH_ROAD: sell_command = CMD_SELL_ROAD_VEH; break; |
1690 case VEH_Ship: sell_command = CMD_SELL_SHIP; break; |
1688 case VEH_SHIP: sell_command = CMD_SELL_SHIP; break; |
1691 case VEH_Aircraft: sell_command = CMD_SELL_AIRCRAFT; break; |
1689 case VEH_AIRCRAFT: sell_command = CMD_SELL_AIRCRAFT; break; |
1692 default: return CMD_ERROR; |
1690 default: return CMD_ERROR; |
1693 } |
1691 } |
1694 |
1692 |
1695 /* Get the list of vehicles in the depot */ |
1693 /* Get the list of vehicles in the depot */ |
1696 BuildDepotVehicleList(vehicle_type, tile, &engines, &engine_list_length, &engine_count, |
1694 BuildDepotVehicleList(vehicle_type, tile, &engines, &engine_list_length, &engine_count, |
1812 * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains |
1810 * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains |
1813 */ |
1811 */ |
1814 |
1812 |
1815 if (!CheckOwnership(v->owner)) return CMD_ERROR; |
1813 if (!CheckOwnership(v->owner)) return CMD_ERROR; |
1816 |
1814 |
1817 if (v->type == VEH_Train && (!IsFrontEngine(v) || v->u.rail.crash_anim_pos >= 4400)) return CMD_ERROR; |
1815 if (v->type == VEH_TRAIN && (!IsFrontEngine(v) || v->u.rail.crash_anim_pos >= 4400)) return CMD_ERROR; |
1818 |
1816 |
1819 // check that we can allocate enough vehicles |
1817 // check that we can allocate enough vehicles |
1820 if (!(flags & DC_EXEC)) { |
1818 if (!(flags & DC_EXEC)) { |
1821 int veh_counter = 0; |
1819 int veh_counter = 0; |
1822 do { |
1820 do { |
1855 * If we pay for it anyway, the cost and the estimated cost will not be the same and we will have an assert. |
1853 * If we pay for it anyway, the cost and the estimated cost will not be the same and we will have an assert. |
1856 * We need to check the whole chain if it is a train because some newgrf articulated engines can refit some units only (and not the front) */ |
1854 * We need to check the whole chain if it is a train because some newgrf articulated engines can refit some units only (and not the front) */ |
1857 DoCommand(0, w->index, v2->cargo_type | (v2->cargo_subtype << 8), flags, GetCmdRefitVeh(v)); |
1855 DoCommand(0, w->index, v2->cargo_type | (v2->cargo_subtype << 8), flags, GetCmdRefitVeh(v)); |
1858 break; // We learned that the engine in question needed a refit. No need to check anymore |
1856 break; // We learned that the engine in question needed a refit. No need to check anymore |
1859 } |
1857 } |
1860 } while (v->type == VEH_Train && (w2 = w2->next) != NULL && (v2 = v2->next) != NULL); |
1858 } while (v->type == VEH_TRAIN && (w2 = w2->next) != NULL && (v2 = v2->next) != NULL); |
1861 |
1859 |
1862 if (v->type == VEH_Train && HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) { |
1860 if (v->type == VEH_TRAIN && HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) { |
1863 SETBIT(w->u.rail.flags, VRF_REVERSE_DIRECTION); |
1861 SETBIT(w->u.rail.flags, VRF_REVERSE_DIRECTION); |
1864 } |
1862 } |
1865 |
1863 |
1866 if (v->type == VEH_Train && !IsFrontEngine(v)) { |
1864 if (v->type == VEH_TRAIN && !IsFrontEngine(v)) { |
1867 // this s a train car |
1865 // this s a train car |
1868 // add this unit to the end of the train |
1866 // add this unit to the end of the train |
1869 DoCommand(0, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE); |
1867 DoCommand(0, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE); |
1870 } else { |
1868 } else { |
1871 // this is a front engine or not a train. It need orders |
1869 // this is a front engine or not a train. It need orders |
1873 w->service_interval = v->service_interval; |
1871 w->service_interval = v->service_interval; |
1874 DoCommand(0, (v->index << 16) | w->index, p2 & 1 ? CO_SHARE : CO_COPY, flags, CMD_CLONE_ORDER); |
1872 DoCommand(0, (v->index << 16) | w->index, p2 & 1 ? CO_SHARE : CO_COPY, flags, CMD_CLONE_ORDER); |
1875 } |
1873 } |
1876 w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop |
1874 w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop |
1877 } |
1875 } |
1878 } while (v->type == VEH_Train && (v = GetNextVehicle(v)) != NULL); |
1876 } while (v->type == VEH_TRAIN && (v = GetNextVehicle(v)) != NULL); |
1879 |
1877 |
1880 if (flags & DC_EXEC && v_front->type == VEH_Train) { |
1878 if (flags & DC_EXEC && v_front->type == VEH_TRAIN) { |
1881 // for trains this needs to be the front engine due to the callback function |
1879 // for trains this needs to be the front engine due to the callback function |
1882 _new_vehicle_id = w_front->index; |
1880 _new_vehicle_id = w_front->index; |
1883 } |
1881 } |
1884 |
1882 |
1885 /* Set the expense type last as refitting will make the cost go towards |
1883 /* Set the expense type last as refitting will make the cost go towards |
1886 * running costs... */ |
1884 * running costs... */ |
1887 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1885 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1888 return total_cost; |
1886 return total_cost; |
1889 } |
1887 } |
1890 |
1888 |
1891 /* |
|
1892 * move the cargo from one engine to another if possible |
|
1893 */ |
|
1894 static void MoveVehicleCargo(Vehicle *dest, Vehicle *source) |
|
1895 { |
|
1896 Vehicle *v = dest; |
|
1897 int units_moved; |
|
1898 |
|
1899 do { |
|
1900 do { |
|
1901 if (source->cargo_type != dest->cargo_type) |
|
1902 continue; // cargo not compatible |
|
1903 |
|
1904 if (dest->cargo_count == dest->cargo_cap) |
|
1905 continue; // the destination vehicle is already full |
|
1906 |
|
1907 units_moved = min(source->cargo_count, dest->cargo_cap - dest->cargo_count); |
|
1908 source->cargo_count -= units_moved; |
|
1909 dest->cargo_count += units_moved; |
|
1910 dest->cargo_source = source->cargo_source; |
|
1911 |
|
1912 // copy the age of the cargo |
|
1913 dest->cargo_days = source->cargo_days; |
|
1914 dest->day_counter = source->day_counter; |
|
1915 dest->tick_counter = source->tick_counter; |
|
1916 |
|
1917 } while (source->cargo_count > 0 && (dest = dest->next) != NULL); |
|
1918 dest = v; |
|
1919 } while ((source = source->next) != NULL); |
|
1920 |
|
1921 /* |
|
1922 * The of the train will be incorrect at this moment. This is due |
|
1923 * to the fact that removing the old wagon updates the weight of |
|
1924 * the complete train, which is without the weight of cargo we just |
|
1925 * moved back into some (of the) new wagon(s). |
|
1926 */ |
|
1927 if (dest->type == VEH_Train) TrainConsistChanged(dest->first); |
|
1928 } |
|
1929 |
|
1930 static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, const EngineID engine_type) |
|
1931 { |
|
1932 const Order *o; |
|
1933 const Vehicle *u; |
|
1934 |
|
1935 if (v->type == VEH_Train) { |
|
1936 u = GetFirstVehicleInChain(v); |
|
1937 } else { |
|
1938 u = v; |
|
1939 } |
|
1940 |
|
1941 FOR_VEHICLE_ORDERS(u, o) { |
|
1942 if (!(o->refit_cargo < NUM_CARGO)) continue; |
|
1943 if (!CanRefitTo(v->engine_type, o->refit_cargo)) continue; |
|
1944 if (!CanRefitTo(engine_type, o->refit_cargo)) return false; |
|
1945 } |
|
1946 |
|
1947 return true; |
|
1948 } |
|
1949 |
|
1950 /** |
|
1951 * Function to find what type of cargo to refit to when autoreplacing |
|
1952 * @param *v Original vehicle, that is being replaced |
|
1953 * @param engine_type The EngineID of the vehicle that is being replaced to |
|
1954 * @return The cargo type to replace to |
|
1955 * CT_NO_REFIT is returned if no refit is needed |
|
1956 * CT_INVALID is returned when both old and new vehicle got cargo capacity and refitting the new one to the old one's cargo type isn't possible |
|
1957 */ |
|
1958 static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type) |
|
1959 { |
|
1960 bool new_cargo_capacity = true; |
|
1961 CargoID new_cargo_type = CT_INVALID; |
|
1962 |
|
1963 switch (v->type) { |
|
1964 case VEH_Train: |
|
1965 new_cargo_capacity = (RailVehInfo(engine_type)->capacity > 0); |
|
1966 new_cargo_type = RailVehInfo(engine_type)->cargo_type; |
|
1967 break; |
|
1968 |
|
1969 case VEH_Road: |
|
1970 new_cargo_capacity = (RoadVehInfo(engine_type)->capacity > 0); |
|
1971 new_cargo_type = RoadVehInfo(engine_type)->cargo_type; |
|
1972 break; |
|
1973 case VEH_Ship: |
|
1974 new_cargo_capacity = (ShipVehInfo(engine_type)->capacity > 0); |
|
1975 new_cargo_type = ShipVehInfo(engine_type)->cargo_type; |
|
1976 break; |
|
1977 |
|
1978 case VEH_Aircraft: |
|
1979 /* all aircraft starts as passenger planes with cargo capacity |
|
1980 * new_cargo_capacity is always true for aircraft, which is the init value. No need to set it here */ |
|
1981 new_cargo_type = CT_PASSENGERS; |
|
1982 break; |
|
1983 |
|
1984 default: NOT_REACHED(); break; |
|
1985 } |
|
1986 |
|
1987 if (!new_cargo_capacity) return CT_NO_REFIT; // Don't try to refit an engine with no cargo capacity |
|
1988 |
|
1989 if (v->cargo_type == new_cargo_type || CanRefitTo(engine_type, v->cargo_type)) { |
|
1990 if (VerifyAutoreplaceRefitForOrders(v, engine_type)) { |
|
1991 return v->cargo_type == new_cargo_type ? (CargoID)CT_NO_REFIT : v->cargo_type; |
|
1992 } else { |
|
1993 return CT_INVALID; |
|
1994 } |
|
1995 } |
|
1996 if (v->type != VEH_Train) return CT_INVALID; // We can't refit the vehicle to carry the cargo we want |
|
1997 |
|
1998 /* Below this line it's safe to assume that the vehicle in question is a train */ |
|
1999 |
|
2000 if (v->cargo_cap != 0) return CT_INVALID; // trying to replace a vehicle with cargo capacity into another one with incompatible cargo type |
|
2001 |
|
2002 /* the old engine didn't have cargo capacity, but the new one does |
|
2003 * now we will figure out what cargo the train is carrying and refit to fit this */ |
|
2004 v = GetFirstVehicleInChain(v); |
|
2005 do { |
|
2006 if (v->cargo_cap == 0) continue; |
|
2007 /* Now we found a cargo type being carried on the train and we will see if it is possible to carry to this one */ |
|
2008 if (v->cargo_type == new_cargo_type) return CT_NO_REFIT; |
|
2009 if (CanRefitTo(engine_type, v->cargo_type)) return v->cargo_type; |
|
2010 } while ((v=v->next) != NULL); |
|
2011 return CT_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one |
|
2012 } |
|
2013 |
|
2014 /* Replaces a vehicle (used to be called autorenew) |
|
2015 * This function is only called from MaybeReplaceVehicle() |
|
2016 * Must be called with _current_player set to the owner of the vehicle |
|
2017 * @param w Vehicle to replace |
|
2018 * @param flags is the flags to use when calling DoCommand(). Mainly DC_EXEC counts |
|
2019 * @return value is cost of the replacement or CMD_ERROR |
|
2020 */ |
|
2021 static int32 ReplaceVehicle(Vehicle **w, byte flags, int32 total_cost) |
|
2022 { |
|
2023 int32 cost; |
|
2024 int32 sell_value; |
|
2025 Vehicle *old_v = *w; |
|
2026 const Player *p = GetPlayer(old_v->owner); |
|
2027 EngineID new_engine_type; |
|
2028 const UnitID cached_unitnumber = old_v->unitnumber; |
|
2029 bool new_front = false; |
|
2030 Vehicle *new_v = NULL; |
|
2031 char vehicle_name[32]; |
|
2032 CargoID replacement_cargo_type; |
|
2033 |
|
2034 new_engine_type = EngineReplacementForPlayer(p, old_v->engine_type); |
|
2035 if (new_engine_type == INVALID_ENGINE) new_engine_type = old_v->engine_type; |
|
2036 |
|
2037 replacement_cargo_type = GetNewCargoTypeForReplace(old_v, new_engine_type); |
|
2038 |
|
2039 /* check if we can't refit to the needed type, so no replace takes place to prevent the vehicle from altering cargo type */ |
|
2040 if (replacement_cargo_type == CT_INVALID) return 0; |
|
2041 |
|
2042 sell_value = DoCommand(0, old_v->index, 0, DC_QUERY_COST, GetCmdSellVeh(old_v)); |
|
2043 |
|
2044 /* We give the player a loan of the same amount as the sell value. |
|
2045 * This is needed in case he needs the income from the sale to build the new vehicle. |
|
2046 * We take it back if building fails or when we really sell the old engine */ |
|
2047 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
2048 SubtractMoneyFromPlayer(sell_value); |
|
2049 |
|
2050 cost = DoCommand(old_v->tile, new_engine_type, 3, flags, GetCmdBuildVeh(old_v)); |
|
2051 if (CmdFailed(cost)) { |
|
2052 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
2053 SubtractMoneyFromPlayer(-sell_value); // Take back the money we just gave the player |
|
2054 return cost; |
|
2055 } |
|
2056 |
|
2057 if (replacement_cargo_type != CT_NO_REFIT) cost += GetRefitCost(new_engine_type); // add refit cost |
|
2058 |
|
2059 if (flags & DC_EXEC) { |
|
2060 new_v = GetVehicle(_new_vehicle_id); |
|
2061 *w = new_v; //we changed the vehicle, so MaybeReplaceVehicle needs to work on the new one. Now we tell it what the new one is |
|
2062 |
|
2063 /* refit if needed */ |
|
2064 if (replacement_cargo_type != CT_NO_REFIT) { |
|
2065 if (CmdFailed(DoCommand(0, new_v->index, replacement_cargo_type, DC_EXEC, GetCmdRefitVeh(new_v)))) { |
|
2066 /* Being here shows a failure, which most likely is in GetNewCargoTypeForReplace() or incorrect estimation costs */ |
|
2067 error("Autoreplace failed to refit. Replace engine %d to %d and refit to cargo %d", old_v->engine_type, new_v->engine_type, replacement_cargo_type); |
|
2068 } |
|
2069 } |
|
2070 |
|
2071 if (new_v->type == VEH_Train && HASBIT(old_v->u.rail.flags, VRF_REVERSE_DIRECTION) && !IsMultiheaded(new_v) && !(new_v->next != NULL && IsArticulatedPart(new_v->next))) { |
|
2072 // we are autorenewing to a single engine, so we will turn it as the old one was turned as well |
|
2073 SETBIT(new_v->u.rail.flags, VRF_REVERSE_DIRECTION); |
|
2074 } |
|
2075 |
|
2076 if (old_v->type == VEH_Train && !IsFrontEngine(old_v)) { |
|
2077 /* this is a railcar. We need to move the car into the train |
|
2078 * We add the new engine after the old one instead of replacing it. It will give the same result anyway when we |
|
2079 * sell the old engine in a moment |
|
2080 */ |
|
2081 DoCommand(0, (GetPrevVehicleInChain(old_v)->index << 16) | new_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
|
2082 /* Now we move the old one out of the train */ |
|
2083 DoCommand(0, (INVALID_VEHICLE << 16) | old_v->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
|
2084 } else { |
|
2085 // copy/clone the orders |
|
2086 DoCommand(0, (old_v->index << 16) | new_v->index, IsOrderListShared(old_v) ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER); |
|
2087 new_v->cur_order_index = old_v->cur_order_index; |
|
2088 ChangeVehicleViewWindow(old_v, new_v); |
|
2089 new_v->profit_this_year = old_v->profit_this_year; |
|
2090 new_v->profit_last_year = old_v->profit_last_year; |
|
2091 new_v->service_interval = old_v->service_interval; |
|
2092 new_front = true; |
|
2093 new_v->unitnumber = old_v->unitnumber; // use the same unit number |
|
2094 |
|
2095 new_v->current_order = old_v->current_order; |
|
2096 if (old_v->type == VEH_Train && GetNextVehicle(old_v) != NULL){ |
|
2097 Vehicle *temp_v = GetNextVehicle(old_v); |
|
2098 |
|
2099 // move the entire train to the new engine, excluding the old engine |
|
2100 if (IsMultiheaded(old_v) && temp_v == old_v->u.rail.other_multiheaded_part) { |
|
2101 // we got front and rear of a multiheaded engine right after each other. We should work with the next in line instead |
|
2102 temp_v = GetNextVehicle(temp_v); |
|
2103 } |
|
2104 |
|
2105 if (temp_v != NULL) { |
|
2106 DoCommand(0, (new_v->index << 16) | temp_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
|
2107 } |
|
2108 } |
|
2109 } |
|
2110 /* We are done setting up the new vehicle. Now we move the cargo from the old one to the new one */ |
|
2111 MoveVehicleCargo(new_v->type == VEH_Train ? GetFirstVehicleInChain(new_v) : new_v, old_v); |
|
2112 |
|
2113 // Get the name of the old vehicle if it has a custom name. |
|
2114 if (!IsCustomName(old_v->string_id)) { |
|
2115 vehicle_name[0] = '\0'; |
|
2116 } else { |
|
2117 GetName(vehicle_name, old_v->string_id & 0x7FF, lastof(vehicle_name)); |
|
2118 } |
|
2119 } else { // flags & DC_EXEC not set |
|
2120 /* Ensure that the player will not end up having negative money while autoreplacing |
|
2121 * This is needed because the only other check is done after the income from selling the old vehicle is substracted from the cost */ |
|
2122 if (p->money64 < (cost + total_cost)) { |
|
2123 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
2124 SubtractMoneyFromPlayer(-sell_value); // Pay back the loan |
|
2125 return CMD_ERROR; |
|
2126 } |
|
2127 } |
|
2128 |
|
2129 /* Take back the money we just gave the player just before building the vehicle |
|
2130 * The player will get the same amount now that the sale actually takes place */ |
|
2131 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
2132 SubtractMoneyFromPlayer(-sell_value); |
|
2133 |
|
2134 /* sell the engine/ find out how much you get for the old engine (income is returned as negative cost) */ |
|
2135 cost += DoCommand(0, old_v->index, 0, flags, GetCmdSellVeh(old_v)); |
|
2136 |
|
2137 if (new_front) { |
|
2138 /* now we assign the old unitnumber to the new vehicle */ |
|
2139 new_v->unitnumber = cached_unitnumber; |
|
2140 } |
|
2141 |
|
2142 /* Transfer the name of the old vehicle */ |
|
2143 if ((flags & DC_EXEC) && vehicle_name[0] != '\0') { |
|
2144 _cmd_text = vehicle_name; |
|
2145 DoCommand(0, new_v->index, 0, DC_EXEC, CMD_NAME_VEHICLE); |
|
2146 } |
|
2147 |
|
2148 return cost; |
|
2149 } |
|
2150 |
|
2151 /** replaces a vehicle if it's set for autoreplace or is too old |
|
2152 * (used to be called autorenew) |
|
2153 * @param v The vehicle to replace |
|
2154 * if the vehicle is a train, v needs to be the front engine |
|
2155 * @param check Checks if the replace is valid. No action is done at all |
|
2156 * @param display_costs If set, a cost animation is shown (only if check is false) |
|
2157 * @return CMD_ERROR if something went wrong. Otherwise the price of the replace |
|
2158 */ |
|
2159 static int32 MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs) |
|
2160 { |
|
2161 Vehicle *w; |
|
2162 const Player *p = GetPlayer(v->owner); |
|
2163 byte flags = 0; |
|
2164 int32 cost, temp_cost = 0; |
|
2165 bool stopped; |
|
2166 |
|
2167 /* Remember the length in case we need to trim train later on |
|
2168 * If it's not a train, the value is unused |
|
2169 * round up to the length of the tiles used for the train instead of the train length instead |
|
2170 * Useful when newGRF uses custom length */ |
|
2171 uint16 old_total_length = (v->type == VEH_Train ? |
|
2172 (v->u.rail.cached_total_length + TILE_SIZE - 1) / TILE_SIZE * TILE_SIZE : |
|
2173 -1 |
|
2174 ); |
|
2175 |
|
2176 |
|
2177 _current_player = v->owner; |
|
2178 |
|
2179 assert(IsPlayerBuildableVehicleType(v)); |
|
2180 |
|
2181 assert(v->vehstatus & VS_STOPPED); // the vehicle should have been stopped in VehicleEnteredDepotThisTick() if needed |
|
2182 |
|
2183 /* Remember the flag v->leave_depot_instantly because if we replace the vehicle, the vehicle holding this flag will be sold |
|
2184 * If it is set, then we only stopped the vehicle to replace it (if needed) and we will need to start it again. |
|
2185 * We also need to reset the flag since it should remain false except from when the vehicle enters a depot until autoreplace is handled in the same tick */ |
|
2186 stopped = v->leave_depot_instantly; |
|
2187 v->leave_depot_instantly = false; |
|
2188 |
|
2189 for (;;) { |
|
2190 cost = 0; |
|
2191 w = v; |
|
2192 do { |
|
2193 if (w->type == VEH_Train && IsMultiheaded(w) && !IsTrainEngine(w)) { |
|
2194 /* we build the rear ends of multiheaded trains with the front ones */ |
|
2195 continue; |
|
2196 } |
|
2197 |
|
2198 // check if the vehicle should be replaced |
|
2199 if (!p->engine_renew || |
|
2200 w->age - w->max_age < (p->engine_renew_months * 30) || // replace if engine is too old |
|
2201 w->max_age == 0) { // rail cars got a max age of 0 |
|
2202 if (!EngineHasReplacementForPlayer(p, w->engine_type)) // updates to a new model |
|
2203 continue; |
|
2204 } |
|
2205 |
|
2206 /* Now replace the vehicle */ |
|
2207 temp_cost = ReplaceVehicle(&w, flags, cost); |
|
2208 |
|
2209 if (flags & DC_EXEC && |
|
2210 (w->type != VEH_Train || w->u.rail.first_engine == INVALID_ENGINE)) { |
|
2211 /* now we bought a new engine and sold the old one. We need to fix the |
|
2212 * pointers in order to avoid pointing to the old one for trains: these |
|
2213 * pointers should point to the front engine and not the cars |
|
2214 */ |
|
2215 v = w; |
|
2216 } |
|
2217 |
|
2218 if (!CmdFailed(temp_cost)) { |
|
2219 cost += temp_cost; |
|
2220 } |
|
2221 } while (w->type == VEH_Train && (w = GetNextVehicle(w)) != NULL); |
|
2222 |
|
2223 if (!(flags & DC_EXEC) && (p->money64 < (int32)(cost + p->engine_renew_money) || cost == 0)) { |
|
2224 if (!check && p->money64 < (int32)(cost + p->engine_renew_money) && ( _local_player == v->owner ) && cost != 0) { |
|
2225 StringID message; |
|
2226 SetDParam(0, v->unitnumber); |
|
2227 switch (v->type) { |
|
2228 case VEH_Train: message = STR_TRAIN_AUTORENEW_FAILED; break; |
|
2229 case VEH_Road: message = STR_ROADVEHICLE_AUTORENEW_FAILED; break; |
|
2230 case VEH_Ship: message = STR_SHIP_AUTORENEW_FAILED; break; |
|
2231 case VEH_Aircraft: message = STR_AIRCRAFT_AUTORENEW_FAILED; break; |
|
2232 // This should never happen |
|
2233 default: NOT_REACHED(); message = 0; break; |
|
2234 } |
|
2235 |
|
2236 AddNewsItem(message, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0); |
|
2237 } |
|
2238 if (stopped) v->vehstatus &= ~VS_STOPPED; |
|
2239 if (display_costs) _current_player = OWNER_NONE; |
|
2240 return CMD_ERROR; |
|
2241 } |
|
2242 |
|
2243 if (flags & DC_EXEC) { |
|
2244 break; // we are done replacing since the loop ran once with DC_EXEC |
|
2245 } else if (check) { |
|
2246 /* It's a test only and we know that we can do this |
|
2247 * NOTE: payment for wagon removal is NOT included in this price */ |
|
2248 return cost; |
|
2249 } |
|
2250 // now we redo the loop, but this time we actually do stuff since we know that we can do it |
|
2251 flags |= DC_EXEC; |
|
2252 } |
|
2253 |
|
2254 /* If setting is on to try not to exceed the old length of the train with the replacement */ |
|
2255 if (v->type == VEH_Train && p->renew_keep_length) { |
|
2256 Vehicle *temp; |
|
2257 w = v; |
|
2258 |
|
2259 while (v->u.rail.cached_total_length > old_total_length) { |
|
2260 // the train is too long. We will remove cars one by one from the start of the train until it's short enough |
|
2261 while (w != NULL && RailVehInfo(w->engine_type)->railveh_type != RAILVEH_WAGON) { |
|
2262 w = GetNextVehicle(w); |
|
2263 } |
|
2264 if (w == NULL) { |
|
2265 // we failed to make the train short enough |
|
2266 SetDParam(0, v->unitnumber); |
|
2267 AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0); |
|
2268 break; |
|
2269 } |
|
2270 temp = w; |
|
2271 w = GetNextVehicle(w); |
|
2272 DoCommand(0, (INVALID_VEHICLE << 16) | temp->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
|
2273 MoveVehicleCargo(v, temp); |
|
2274 cost += DoCommand(0, temp->index, 0, DC_EXEC, CMD_SELL_RAIL_WAGON); |
|
2275 } |
|
2276 } |
|
2277 |
|
2278 if (stopped) v->vehstatus &= ~VS_STOPPED; |
|
2279 if (display_costs) { |
|
2280 if (IsLocalPlayer()) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost); |
|
2281 _current_player = OWNER_NONE; |
|
2282 } |
|
2283 return cost; |
|
2284 } |
|
2285 |
1889 |
2286 /* Extend the list size for BuildDepotVehicleList() */ |
1890 /* Extend the list size for BuildDepotVehicleList() */ |
2287 static inline void ExtendVehicleListSize(const Vehicle ***engine_list, uint16 *engine_list_length, uint16 step_size) |
1891 static inline void ExtendVehicleListSize(const Vehicle ***engine_list, uint16 *engine_list_length, uint16 step_size) |
2288 { |
1892 { |
2289 *engine_list_length = min(*engine_list_length + step_size, GetMaxVehicleIndex() + 1); |
1893 *engine_list_length = min(*engine_list_length + step_size, GetMaxVehicleIndex() + 1); |
2305 void BuildDepotVehicleList(byte type, TileIndex tile, Vehicle ***engine_list, uint16 *engine_list_length, uint16 *engine_count, Vehicle ***wagon_list, uint16 *wagon_list_length, uint16 *wagon_count) |
1909 void BuildDepotVehicleList(byte type, TileIndex tile, Vehicle ***engine_list, uint16 *engine_list_length, uint16 *engine_count, Vehicle ***wagon_list, uint16 *wagon_list_length, uint16 *wagon_count) |
2306 { |
1910 { |
2307 Vehicle *v; |
1911 Vehicle *v; |
2308 |
1912 |
2309 /* This function should never be called without an array to store results */ |
1913 /* This function should never be called without an array to store results */ |
2310 assert(!(engine_list == NULL && type != VEH_Train)); |
1914 assert(!(engine_list == NULL && type != VEH_TRAIN)); |
2311 assert(!(type == VEH_Train && engine_list == NULL && wagon_list == NULL)); |
1915 assert(!(type == VEH_TRAIN && engine_list == NULL && wagon_list == NULL)); |
2312 |
1916 |
2313 /* Both array and the length should either be NULL to disable the list or both should not be NULL */ |
1917 /* Both array and the length should either be NULL to disable the list or both should not be NULL */ |
2314 assert((engine_list == NULL && engine_list_length == NULL) || (engine_list != NULL && engine_list_length != NULL)); |
1918 assert((engine_list == NULL && engine_list_length == NULL) || (engine_list != NULL && engine_list_length != NULL)); |
2315 assert((wagon_list == NULL && wagon_list_length == NULL) || (wagon_list != NULL && wagon_list_length != NULL)); |
1919 assert((wagon_list == NULL && wagon_list_length == NULL) || (wagon_list != NULL && wagon_list_length != NULL)); |
2316 |
1920 |
2319 |
1923 |
2320 if (engine_count != NULL) *engine_count = 0; |
1924 if (engine_count != NULL) *engine_count = 0; |
2321 if (wagon_count != NULL) *wagon_count = 0; |
1925 if (wagon_count != NULL) *wagon_count = 0; |
2322 |
1926 |
2323 switch (type) { |
1927 switch (type) { |
2324 case VEH_Train: |
1928 case VEH_TRAIN: |
2325 FOR_ALL_VEHICLES(v) { |
1929 FOR_ALL_VEHICLES(v) { |
2326 if (v->tile == tile && v->type == VEH_Train && v->u.rail.track == TRACK_BIT_DEPOT) { |
1930 if (v->tile == tile && v->type == VEH_TRAIN && v->u.rail.track == TRACK_BIT_DEPOT) { |
2327 if (IsFrontEngine(v)) { |
1931 if (IsFrontEngine(v)) { |
2328 if (engine_list == NULL) continue; |
1932 if (engine_list == NULL) continue; |
2329 if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25); |
1933 if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25); |
2330 (*engine_list)[(*engine_count)++] = v; |
1934 (*engine_list)[(*engine_count)++] = v; |
2331 } else if (IsFreeWagon(v)) { |
1935 } else if (IsFreeWagon(v)) { |
2335 } |
1939 } |
2336 } |
1940 } |
2337 } |
1941 } |
2338 break; |
1942 break; |
2339 |
1943 |
2340 case VEH_Road: |
1944 case VEH_ROAD: |
2341 FOR_ALL_VEHICLES(v) { |
1945 FOR_ALL_VEHICLES(v) { |
2342 if (v->tile == tile && v->type == VEH_Road && IsRoadVehInDepot(v)) { |
1946 if (v->tile == tile && v->type == VEH_ROAD && IsRoadVehInDepot(v)) { |
2343 if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25); |
1947 if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25); |
2344 (*engine_list)[(*engine_count)++] = v; |
1948 (*engine_list)[(*engine_count)++] = v; |
2345 } |
1949 } |
2346 } |
1950 } |
2347 break; |
1951 break; |
2348 |
1952 |
2349 case VEH_Ship: |
1953 case VEH_SHIP: |
2350 FOR_ALL_VEHICLES(v) { |
1954 FOR_ALL_VEHICLES(v) { |
2351 if (v->tile == tile && v->type == VEH_Ship && IsShipInDepot(v)) { |
1955 if (v->tile == tile && v->type == VEH_SHIP && IsShipInDepot(v)) { |
2352 if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25); |
1956 if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25); |
2353 (*engine_list)[(*engine_count)++] = v; |
1957 (*engine_list)[(*engine_count)++] = v; |
2354 } |
1958 } |
2355 } |
1959 } |
2356 break; |
1960 break; |
2357 |
1961 |
2358 case VEH_Aircraft: |
1962 case VEH_AIRCRAFT: |
2359 FOR_ALL_VEHICLES(v) { |
1963 FOR_ALL_VEHICLES(v) { |
2360 if (v->tile == tile && |
1964 if (v->tile == tile && |
2361 v->type == VEH_Aircraft && IsNormalAircraft(v) && |
1965 v->type == VEH_AIRCRAFT && IsNormalAircraft(v) && |
2362 v->vehstatus & VS_HIDDEN) { |
1966 v->vehstatus & VS_HIDDEN) { |
2363 if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25); |
1967 if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25); |
2364 (*engine_list)[(*engine_count)++] = v; |
1968 (*engine_list)[(*engine_count)++] = v; |
2365 } |
1969 } |
2366 } |
1970 } |
2383 * @param window_type tells what kind of window the list is for. Use the VLW flags in vehicle_gui.h |
1987 * @param window_type tells what kind of window the list is for. Use the VLW flags in vehicle_gui.h |
2384 * @return the number of vehicles added to the list |
1988 * @return the number of vehicles added to the list |
2385 */ |
1989 */ |
2386 uint GenerateVehicleSortList(const Vehicle ***sort_list, uint16 *length_of_array, byte type, PlayerID owner, uint32 index, uint16 window_type) |
1990 uint GenerateVehicleSortList(const Vehicle ***sort_list, uint16 *length_of_array, byte type, PlayerID owner, uint32 index, uint16 window_type) |
2387 { |
1991 { |
2388 const byte subtype = (type != VEH_Aircraft) ? (byte)Train_Front : (byte)AIR_AIRCRAFT; |
1992 const byte subtype = (type != VEH_AIRCRAFT) ? (byte)Train_Front : (byte)AIR_AIRCRAFT; |
2389 uint n = 0; |
1993 uint n = 0; |
2390 const Vehicle *v; |
1994 const Vehicle *v; |
2391 |
1995 |
2392 switch (window_type) { |
1996 switch (window_type) { |
2393 case VLW_STATION_LIST: { |
1997 case VLW_STATION_LIST: { |
2394 FOR_ALL_VEHICLES(v) { |
1998 FOR_ALL_VEHICLES(v) { |
2395 if (v->type == type && ( |
1999 if (v->type == type && ( |
2396 (type == VEH_Train && IsFrontEngine(v)) || |
2000 (type == VEH_TRAIN && IsFrontEngine(v)) || |
2397 (type != VEH_Train && v->subtype <= subtype))) { |
2001 (type != VEH_TRAIN && v->subtype <= subtype))) { |
2398 const Order *order; |
2002 const Order *order; |
2399 |
2003 |
2400 FOR_VEHICLE_ORDERS(v, order) { |
2004 FOR_VEHICLE_ORDERS(v, order) { |
2401 if (order->type == OT_GOTO_STATION && order->dest == index) { |
2005 if (order->type == OT_GOTO_STATION && order->dest == index) { |
2402 if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50); |
2006 if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50); |
2426 } |
2030 } |
2427 |
2031 |
2428 case VLW_STANDARD: { |
2032 case VLW_STANDARD: { |
2429 FOR_ALL_VEHICLES(v) { |
2033 FOR_ALL_VEHICLES(v) { |
2430 if (v->type == type && v->owner == owner && ( |
2034 if (v->type == type && v->owner == owner && ( |
2431 (type == VEH_Train && IsFrontEngine(v)) || |
2035 (type == VEH_TRAIN && IsFrontEngine(v)) || |
2432 (type != VEH_Train && v->subtype <= subtype))) { |
2036 (type != VEH_TRAIN && v->subtype <= subtype))) { |
2433 /* TODO find a better estimate on the total number of vehicles for current player */ |
2037 /* TODO find a better estimate on the total number of vehicles for current player */ |
2434 if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles()/4); |
2038 if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles()/4); |
2435 (*sort_list)[n++] = v; |
2039 (*sort_list)[n++] = v; |
2436 } |
2040 } |
2437 } |
2041 } |
2439 } |
2043 } |
2440 |
2044 |
2441 case VLW_DEPOT_LIST: { |
2045 case VLW_DEPOT_LIST: { |
2442 FOR_ALL_VEHICLES(v) { |
2046 FOR_ALL_VEHICLES(v) { |
2443 if (v->type == type && ( |
2047 if (v->type == type && ( |
2444 (type == VEH_Train && IsFrontEngine(v)) || |
2048 (type == VEH_TRAIN && IsFrontEngine(v)) || |
2445 (type != VEH_Train && v->subtype <= subtype))) { |
2049 (type != VEH_TRAIN && v->subtype <= subtype))) { |
2446 const Order *order; |
2050 const Order *order; |
2447 |
2051 |
2448 FOR_VEHICLE_ORDERS(v, order) { |
2052 FOR_VEHICLE_ORDERS(v, order) { |
2449 if (order->type == OT_GOTO_DEPOT && order->dest == index) { |
2053 if (order->type == OT_GOTO_DEPOT && order->dest == index) { |
2450 if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25); |
2054 if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25); |
2508 } |
2112 } |
2509 |
2113 |
2510 bool IsVehicleInDepot(const Vehicle *v) |
2114 bool IsVehicleInDepot(const Vehicle *v) |
2511 { |
2115 { |
2512 switch (v->type) { |
2116 switch (v->type) { |
2513 case VEH_Train: return CheckTrainInDepot(v, false) != -1; |
2117 case VEH_TRAIN: return CheckTrainInDepot(v, false) != -1; |
2514 case VEH_Road: return IsRoadVehInDepot(v); |
2118 case VEH_ROAD: return IsRoadVehInDepot(v); |
2515 case VEH_Ship: return IsShipInDepot(v); |
2119 case VEH_SHIP: return IsShipInDepot(v); |
2516 case VEH_Aircraft: return IsAircraftInHangar(v); |
2120 case VEH_AIRCRAFT: return IsAircraftInHangar(v); |
2517 default: NOT_REACHED(); |
2121 default: NOT_REACHED(); |
2518 } |
2122 } |
2519 return false; |
2123 return false; |
2520 } |
2124 } |
2521 |
2125 |
2522 void VehicleEnterDepot(Vehicle *v) |
2126 void VehicleEnterDepot(Vehicle *v) |
2523 { |
2127 { |
2524 switch (v->type) { |
2128 switch (v->type) { |
2525 case VEH_Train: |
2129 case VEH_TRAIN: |
2526 InvalidateWindowClasses(WC_TRAINS_LIST); |
2130 InvalidateWindowClasses(WC_TRAINS_LIST); |
2527 if (!IsFrontEngine(v)) v = GetFirstVehicleInChain(v); |
2131 if (!IsFrontEngine(v)) v = GetFirstVehicleInChain(v); |
2528 UpdateSignalsOnSegment(v->tile, GetRailDepotDirection(v->tile)); |
2132 UpdateSignalsOnSegment(v->tile, GetRailDepotDirection(v->tile)); |
2529 v->load_unload_time_rem = 0; |
2133 v->load_unload_time_rem = 0; |
2530 break; |
2134 break; |
2531 |
2135 |
2532 case VEH_Road: |
2136 case VEH_ROAD: |
2533 InvalidateWindowClasses(WC_ROADVEH_LIST); |
2137 InvalidateWindowClasses(WC_ROADVEH_LIST); |
2534 v->u.road.state = RVSB_IN_DEPOT; |
2138 v->u.road.state = RVSB_IN_DEPOT; |
2535 break; |
2139 break; |
2536 |
2140 |
2537 case VEH_Ship: |
2141 case VEH_SHIP: |
2538 InvalidateWindowClasses(WC_SHIPS_LIST); |
2142 InvalidateWindowClasses(WC_SHIPS_LIST); |
2539 v->u.ship.state = TRACK_BIT_DEPOT; |
2143 v->u.ship.state = TRACK_BIT_DEPOT; |
2540 RecalcShipStuff(v); |
2144 RecalcShipStuff(v); |
2541 break; |
2145 break; |
2542 |
2146 |
2543 case VEH_Aircraft: |
2147 case VEH_AIRCRAFT: |
2544 InvalidateWindowClasses(WC_AIRCRAFT_LIST); |
2148 InvalidateWindowClasses(WC_AIRCRAFT_LIST); |
2545 HandleAircraftEnterHangar(v); |
2149 HandleAircraftEnterHangar(v); |
2546 break; |
2150 break; |
2547 default: NOT_REACHED(); |
2151 default: NOT_REACHED(); |
2548 } |
2152 } |
2549 |
2153 |
2550 if (v->type != VEH_Train) { |
2154 if (v->type != VEH_TRAIN) { |
2551 /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters. |
2155 /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters. |
2552 * We only increase the number of vehicles when the first one enters, so we will not need to search for more vehicles in the depot */ |
2156 * We only increase the number of vehicles when the first one enters, so we will not need to search for more vehicles in the depot */ |
2553 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
2157 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
2554 } |
2158 } |
2555 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
2159 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
2589 } |
2193 } |
2590 } |
2194 } |
2591 |
2195 |
2592 if (HASBIT(t.flags, OFB_PART_OF_ORDERS)) { |
2196 if (HASBIT(t.flags, OFB_PART_OF_ORDERS)) { |
2593 /* Part of orders */ |
2197 /* Part of orders */ |
2594 if (v->type == VEH_Train) v->u.rail.days_since_order_progr = 0; |
2198 if (v->type == VEH_TRAIN) v->u.rail.days_since_order_progr = 0; |
2595 v->cur_order_index++; |
2199 v->cur_order_index++; |
2596 } else if (HASBIT(t.flags, OFB_HALT_IN_DEPOT)) { |
2200 } else if (HASBIT(t.flags, OFB_HALT_IN_DEPOT)) { |
2597 /* Force depot visit */ |
2201 /* Force depot visit */ |
2598 v->vehstatus |= VS_STOPPED; |
2202 v->vehstatus |= VS_STOPPED; |
2599 if (v->owner == _local_player) { |
2203 if (v->owner == _local_player) { |
2600 StringID string; |
2204 StringID string; |
2601 |
2205 |
2602 switch (v->type) { |
2206 switch (v->type) { |
2603 case VEH_Train: string = STR_8814_TRAIN_IS_WAITING_IN_DEPOT; break; |
2207 case VEH_TRAIN: string = STR_8814_TRAIN_IS_WAITING_IN_DEPOT; break; |
2604 case VEH_Road: string = STR_9016_ROAD_VEHICLE_IS_WAITING; break; |
2208 case VEH_ROAD: string = STR_9016_ROAD_VEHICLE_IS_WAITING; break; |
2605 case VEH_Ship: string = STR_981C_SHIP_IS_WAITING_IN_DEPOT; break; |
2209 case VEH_SHIP: string = STR_981C_SHIP_IS_WAITING_IN_DEPOT; break; |
2606 case VEH_Aircraft: string = STR_A014_AIRCRAFT_IS_WAITING_IN; break; |
2210 case VEH_AIRCRAFT: string = STR_A014_AIRCRAFT_IS_WAITING_IN; break; |
2607 default: NOT_REACHED(); string = STR_EMPTY; // Set the string to something to avoid a compiler warning |
2211 default: NOT_REACHED(); string = STR_EMPTY; // Set the string to something to avoid a compiler warning |
2608 } |
2212 } |
2609 |
2213 |
2610 SetDParam(0, v->unitnumber); |
2214 SetDParam(0, v->unitnumber); |
2611 AddNewsItem(string, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0); |
2215 AddNewsItem(string, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0); |
2742 Trackdir GetVehicleTrackdir(const Vehicle* v) |
2346 Trackdir GetVehicleTrackdir(const Vehicle* v) |
2743 { |
2347 { |
2744 if (v->vehstatus & VS_CRASHED) return INVALID_TRACKDIR; |
2348 if (v->vehstatus & VS_CRASHED) return INVALID_TRACKDIR; |
2745 |
2349 |
2746 switch (v->type) { |
2350 switch (v->type) { |
2747 case VEH_Train: |
2351 case VEH_TRAIN: |
2748 if (v->u.rail.track == TRACK_BIT_DEPOT) /* We'll assume the train is facing outwards */ |
2352 if (v->u.rail.track == TRACK_BIT_DEPOT) /* We'll assume the train is facing outwards */ |
2749 return DiagdirToDiagTrackdir(GetRailDepotDirection(v->tile)); /* Train in depot */ |
2353 return DiagdirToDiagTrackdir(GetRailDepotDirection(v->tile)); /* Train in depot */ |
2750 |
2354 |
2751 if (v->u.rail.track == TRACK_BIT_WORMHOLE) /* train in tunnel, so just use his direction and assume a diagonal track */ |
2355 if (v->u.rail.track == TRACK_BIT_WORMHOLE) /* train in tunnel, so just use his direction and assume a diagonal track */ |
2752 return DiagdirToDiagTrackdir(DirToDiagDir(v->direction)); |
2356 return DiagdirToDiagTrackdir(DirToDiagDir(v->direction)); |
2753 |
2357 |
2754 return TrackDirectionToTrackdir(FindFirstTrack(v->u.rail.track), v->direction); |
2358 return TrackDirectionToTrackdir(FindFirstTrack(v->u.rail.track), v->direction); |
2755 |
2359 |
2756 case VEH_Ship: |
2360 case VEH_SHIP: |
2757 if (IsShipInDepot(v)) |
2361 if (IsShipInDepot(v)) |
2758 /* We'll assume the ship is facing outwards */ |
2362 /* We'll assume the ship is facing outwards */ |
2759 return DiagdirToDiagTrackdir(GetShipDepotDirection(v->tile)); |
2363 return DiagdirToDiagTrackdir(GetShipDepotDirection(v->tile)); |
2760 |
2364 |
2761 return TrackDirectionToTrackdir(FindFirstTrack(v->u.ship.state), v->direction); |
2365 return TrackDirectionToTrackdir(FindFirstTrack(v->u.ship.state), v->direction); |
2762 |
2366 |
2763 case VEH_Road: |
2367 case VEH_ROAD: |
2764 if (IsRoadVehInDepot(v)) /* We'll assume the road vehicle is facing outwards */ |
2368 if (IsRoadVehInDepot(v)) /* We'll assume the road vehicle is facing outwards */ |
2765 return DiagdirToDiagTrackdir(GetRoadDepotDirection(v->tile)); |
2369 return DiagdirToDiagTrackdir(GetRoadDepotDirection(v->tile)); |
2766 |
2370 |
2767 if (IsStandardRoadStopTile(v->tile)) /* We'll assume the road vehicle is facing outwards */ |
2371 if (IsStandardRoadStopTile(v->tile)) /* We'll assume the road vehicle is facing outwards */ |
2768 return DiagdirToDiagTrackdir(GetRoadStopDir(v->tile)); /* Road vehicle in a station */ |
2372 return DiagdirToDiagTrackdir(GetRoadStopDir(v->tile)); /* Road vehicle in a station */ |
2773 if (!IsReversingRoadTrackdir((Trackdir)v->u.road.state)) return (Trackdir)v->u.road.state; |
2377 if (!IsReversingRoadTrackdir((Trackdir)v->u.road.state)) return (Trackdir)v->u.road.state; |
2774 |
2378 |
2775 /* Vehicle is turning around, get the direction from vehicle's direction */ |
2379 /* Vehicle is turning around, get the direction from vehicle's direction */ |
2776 return DiagdirToDiagTrackdir(DirToDiagDir(v->direction)); |
2380 return DiagdirToDiagTrackdir(DirToDiagDir(v->direction)); |
2777 |
2381 |
2778 /* case VEH_Aircraft: case VEH_Special: case VEH_Disaster: */ |
2382 /* case VEH_AIRCRAFT: case VEH_SPECIAL: case VEH_DISASTER: */ |
2779 default: return INVALID_TRACKDIR; |
2383 default: return INVALID_TRACKDIR; |
2780 } |
2384 } |
2781 } |
2385 } |
2782 |
2386 |
2783 /** |
2387 /** |
2795 const Vehicle *u; |
2399 const Vehicle *u; |
2796 static bool *cache = NULL; |
2400 static bool *cache = NULL; |
2797 static UnitID gmax = 0; |
2401 static UnitID gmax = 0; |
2798 |
2402 |
2799 switch (type) { |
2403 switch (type) { |
2800 case VEH_Train: max = _patches.max_trains; break; |
2404 case VEH_TRAIN: max = _patches.max_trains; break; |
2801 case VEH_Road: max = _patches.max_roadveh; break; |
2405 case VEH_ROAD: max = _patches.max_roadveh; break; |
2802 case VEH_Ship: max = _patches.max_ships; break; |
2406 case VEH_SHIP: max = _patches.max_ships; break; |
2803 case VEH_Aircraft: max = _patches.max_aircraft; break; |
2407 case VEH_AIRCRAFT: max = _patches.max_aircraft; break; |
2804 default: NOT_REACHED(); |
2408 default: NOT_REACHED(); |
2805 } |
2409 } |
2806 |
2410 |
2807 if (max == 0) { |
2411 if (max == 0) { |
2808 /* we can't build any of this kind of vehicle, so we just return 1 instead of looking for a free number |
2412 /* we can't build any of this kind of vehicle, so we just return 1 instead of looking for a free number |
2858 /* The default livery is always available for use, but its in_use flag determines |
2462 /* The default livery is always available for use, but its in_use flag determines |
2859 * whether any _other_ liveries are in use. */ |
2463 * whether any _other_ liveries are in use. */ |
2860 if (p->livery[LS_DEFAULT].in_use && (_patches.liveries == 2 || (_patches.liveries == 1 && player == _local_player))) { |
2464 if (p->livery[LS_DEFAULT].in_use && (_patches.liveries == 2 || (_patches.liveries == 1 && player == _local_player))) { |
2861 /* Determine the livery scheme to use */ |
2465 /* Determine the livery scheme to use */ |
2862 switch (GetEngine(engine_type)->type) { |
2466 switch (GetEngine(engine_type)->type) { |
2863 case VEH_Train: { |
2467 case VEH_TRAIN: { |
2864 const RailVehicleInfo *rvi = RailVehInfo(engine_type); |
2468 const RailVehicleInfo *rvi = RailVehInfo(engine_type); |
2865 |
2469 |
2866 switch (rvi->railtype) { |
2470 switch (rvi->railtype) { |
2867 default: NOT_REACHED(); |
2471 default: NOT_REACHED(); |
2868 case RAILTYPE_RAIL: |
2472 case RAILTYPE_RAIL: |
2899 case RAILTYPE_MAGLEV: scheme = LS_MAGLEV; break; |
2503 case RAILTYPE_MAGLEV: scheme = LS_MAGLEV; break; |
2900 } |
2504 } |
2901 break; |
2505 break; |
2902 } |
2506 } |
2903 |
2507 |
2904 case VEH_Road: { |
2508 case VEH_ROAD: { |
2905 const RoadVehicleInfo *rvi = RoadVehInfo(engine_type); |
2509 const RoadVehicleInfo *rvi = RoadVehInfo(engine_type); |
2906 if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type; |
2510 if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type; |
2907 scheme = (cargo_type == CT_PASSENGERS) ? LS_BUS : LS_TRUCK; |
2511 scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK; |
2908 break; |
2512 break; |
2909 } |
2513 } |
2910 |
2514 |
2911 case VEH_Ship: { |
2515 case VEH_SHIP: { |
2912 const ShipVehicleInfo *svi = ShipVehInfo(engine_type); |
2516 const ShipVehicleInfo *svi = ShipVehInfo(engine_type); |
2913 if (cargo_type == CT_INVALID) cargo_type = svi->cargo_type; |
2517 if (cargo_type == CT_INVALID) cargo_type = svi->cargo_type; |
2914 scheme = (cargo_type == CT_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP; |
2518 scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP; |
2915 break; |
2519 break; |
2916 } |
2520 } |
2917 |
2521 |
2918 case VEH_Aircraft: { |
2522 case VEH_AIRCRAFT: { |
2919 const AircraftVehicleInfo *avi = AircraftVehInfo(engine_type); |
2523 const AircraftVehicleInfo *avi = AircraftVehInfo(engine_type); |
2920 if (cargo_type == CT_INVALID) cargo_type = CT_PASSENGERS; |
2524 if (cargo_type == CT_INVALID) cargo_type = CT_PASSENGERS; |
2921 switch (avi->subtype) { |
2525 switch (avi->subtype) { |
2922 case AIR_HELI: scheme = LS_HELICOPTER; break; |
2526 case AIR_HELI: scheme = LS_HELICOPTER; break; |
2923 case AIR_CTOL: scheme = LS_SMALL_PLANE; break; |
2527 case AIR_CTOL: scheme = LS_SMALL_PLANE; break; |
2946 return GetEngineColourMap(engine_type, player, INVALID_ENGINE, NULL); |
2550 return GetEngineColourMap(engine_type, player, INVALID_ENGINE, NULL); |
2947 } |
2551 } |
2948 |
2552 |
2949 SpriteID GetVehiclePalette(const Vehicle *v) |
2553 SpriteID GetVehiclePalette(const Vehicle *v) |
2950 { |
2554 { |
2951 if (v->type == VEH_Train) { |
2555 if (v->type == VEH_TRAIN) { |
2952 return GetEngineColourMap( |
2556 return GetEngineColourMap( |
2953 (v->u.rail.first_engine != INVALID_ENGINE && (IsArticulatedPart(v) || UsesWagonOverride(v))) ? |
2557 (v->u.rail.first_engine != INVALID_ENGINE && (IsArticulatedPart(v) || UsesWagonOverride(v))) ? |
2954 v->u.rail.first_engine : v->engine_type, |
2558 v->u.rail.first_engine : v->engine_type, |
2955 v->owner, v->u.rail.first_engine, v); |
2559 v->owner, v->u.rail.first_engine, v); |
2956 } |
2560 } |
3069 SLE_END() |
2673 SLE_END() |
3070 }; |
2674 }; |
3071 |
2675 |
3072 |
2676 |
3073 static const SaveLoad _train_desc[] = { |
2677 static const SaveLoad _train_desc[] = { |
3074 SLE_WRITEBYTE(Vehicle, type, VEH_Train, 0), // Train type. VEH_Train in mem, 0 in file. |
2678 SLE_WRITEBYTE(Vehicle, type, VEH_TRAIN, 0), // Train type. VEH_TRAIN in mem, 0 in file. |
3075 SLE_INCLUDEX(0, INC_VEHICLE_COMMON), |
2679 SLE_INCLUDEX(0, INC_VEHICLE_COMMON), |
3076 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, crash_anim_pos), SLE_UINT16), |
2680 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, crash_anim_pos), SLE_UINT16), |
3077 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, force_proceed), SLE_UINT8), |
2681 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, force_proceed), SLE_UINT8), |
3078 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, railtype), SLE_UINT8), |
2682 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, railtype), SLE_UINT8), |
3079 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, track), SLE_UINT8), |
2683 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRail, track), SLE_UINT8), |
3087 |
2691 |
3088 SLE_END() |
2692 SLE_END() |
3089 }; |
2693 }; |
3090 |
2694 |
3091 static const SaveLoad _roadveh_desc[] = { |
2695 static const SaveLoad _roadveh_desc[] = { |
3092 SLE_WRITEBYTE(Vehicle, type, VEH_Road, 1), // Road type. VEH_Road in mem, 1 in file. |
2696 SLE_WRITEBYTE(Vehicle, type, VEH_ROAD, 1), // Road type. VEH_ROAD in mem, 1 in file. |
3093 SLE_INCLUDEX(0, INC_VEHICLE_COMMON), |
2697 SLE_INCLUDEX(0, INC_VEHICLE_COMMON), |
3094 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, state), SLE_UINT8), |
2698 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, state), SLE_UINT8), |
3095 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, frame), SLE_UINT8), |
2699 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, frame), SLE_UINT8), |
3096 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, blocked_ctr), SLE_UINT16), |
2700 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, blocked_ctr), SLE_UINT16), |
3097 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, overtaking), SLE_UINT8), |
2701 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleRoad, overtaking), SLE_UINT8), |
3107 |
2711 |
3108 SLE_END() |
2712 SLE_END() |
3109 }; |
2713 }; |
3110 |
2714 |
3111 static const SaveLoad _ship_desc[] = { |
2715 static const SaveLoad _ship_desc[] = { |
3112 SLE_WRITEBYTE(Vehicle, type, VEH_Ship, 2), // Ship type. VEH_Ship in mem, 2 in file. |
2716 SLE_WRITEBYTE(Vehicle, type, VEH_SHIP, 2), // Ship type. VEH_SHIP in mem, 2 in file. |
3113 SLE_INCLUDEX(0, INC_VEHICLE_COMMON), |
2717 SLE_INCLUDEX(0, INC_VEHICLE_COMMON), |
3114 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleShip, state), SLE_UINT8), |
2718 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleShip, state), SLE_UINT8), |
3115 |
2719 |
3116 // reserve extra space in savegame here. (currently 16 bytes) |
2720 // reserve extra space in savegame here. (currently 16 bytes) |
3117 SLE_CONDNULL(16, 2, SL_MAX_VERSION), |
2721 SLE_CONDNULL(16, 2, SL_MAX_VERSION), |
3118 |
2722 |
3119 SLE_END() |
2723 SLE_END() |
3120 }; |
2724 }; |
3121 |
2725 |
3122 static const SaveLoad _aircraft_desc[] = { |
2726 static const SaveLoad _aircraft_desc[] = { |
3123 SLE_WRITEBYTE(Vehicle, type, VEH_Aircraft, 3), // Aircraft type. VEH_Aircraft in mem, 3 in file. |
2727 SLE_WRITEBYTE(Vehicle, type, VEH_AIRCRAFT, 3), // Aircraft type. VEH_AIRCRAFT in mem, 3 in file. |
3124 SLE_INCLUDEX(0, INC_VEHICLE_COMMON), |
2728 SLE_INCLUDEX(0, INC_VEHICLE_COMMON), |
3125 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleAir, crashed_counter), SLE_UINT16), |
2729 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleAir, crashed_counter), SLE_UINT16), |
3126 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleAir, pos), SLE_UINT8), |
2730 SLE_VARX(offsetof(Vehicle, u) + offsetof(VehicleAir, pos), SLE_UINT8), |
3127 |
2731 |
3128 SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleAir, targetairport), SLE_FILE_U8 | SLE_VAR_U16, 0, 4), |
2732 SLE_CONDVARX(offsetof(Vehicle, u) + offsetof(VehicleAir, targetairport), SLE_FILE_U8 | SLE_VAR_U16, 0, 4), |
3137 |
2741 |
3138 SLE_END() |
2742 SLE_END() |
3139 }; |
2743 }; |
3140 |
2744 |
3141 static const SaveLoad _special_desc[] = { |
2745 static const SaveLoad _special_desc[] = { |
3142 SLE_WRITEBYTE(Vehicle,type,VEH_Special, 4), |
2746 SLE_WRITEBYTE(Vehicle,type,VEH_SPECIAL, 4), |
3143 |
2747 |
3144 SLE_VAR(Vehicle, subtype, SLE_UINT8), |
2748 SLE_VAR(Vehicle, subtype, SLE_UINT8), |
3145 |
2749 |
3146 SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), |
2750 SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), |
3147 SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), |
2751 SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), |
3169 |
2773 |
3170 SLE_END() |
2774 SLE_END() |
3171 }; |
2775 }; |
3172 |
2776 |
3173 static const SaveLoad _disaster_desc[] = { |
2777 static const SaveLoad _disaster_desc[] = { |
3174 SLE_WRITEBYTE(Vehicle, type, VEH_Disaster, 5), |
2778 SLE_WRITEBYTE(Vehicle, type, VEH_DISASTER, 5), |
3175 |
2779 |
3176 SLE_REF(Vehicle, next, REF_VEHICLE_OLD), |
2780 SLE_REF(Vehicle, next, REF_VEHICLE_OLD), |
3177 |
2781 |
3178 SLE_VAR(Vehicle, subtype, SLE_UINT8), |
2782 SLE_VAR(Vehicle, subtype, SLE_UINT8), |
3179 SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), |
2783 SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), |
3221 _special_desc, |
2825 _special_desc, |
3222 _disaster_desc, |
2826 _disaster_desc, |
3223 }; |
2827 }; |
3224 |
2828 |
3225 // Will be called when the vehicles need to be saved. |
2829 // Will be called when the vehicles need to be saved. |
3226 static void Save_VEHS(void) |
2830 static void Save_VEHS() |
3227 { |
2831 { |
3228 Vehicle *v; |
2832 Vehicle *v; |
3229 // Write the vehicles |
2833 // Write the vehicles |
3230 FOR_ALL_VEHICLES(v) { |
2834 FOR_ALL_VEHICLES(v) { |
3231 SlSetArrayIndex(v->index); |
2835 SlSetArrayIndex(v->index); |
3232 SlObject(v, (SaveLoad*)_veh_descs[v->type]); |
2836 SlObject(v, (SaveLoad*)_veh_descs[v->type]); |
3233 } |
2837 } |
3234 } |
2838 } |
3235 |
2839 |
3236 // Will be called when vehicles need to be loaded. |
2840 // Will be called when vehicles need to be loaded. |
3237 static void Load_VEHS(void) |
2841 static void Load_VEHS() |
3238 { |
2842 { |
3239 int index; |
2843 int index; |
3240 Vehicle *v; |
2844 Vehicle *v; |
3241 |
2845 |
3242 while ((index = SlIterateArray()) != -1) { |
2846 while ((index = SlIterateArray()) != -1) { |
3282 { 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST}, |
2886 { 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST}, |
3283 }; |
2887 }; |
3284 |
2888 |
3285 void Vehicle::BeginLoading() |
2889 void Vehicle::BeginLoading() |
3286 { |
2890 { |
3287 assert(IsTileType(tile, MP_STATION) || type == VEH_Ship); |
2891 assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP); |
3288 current_order.type = OT_LOADING; |
2892 current_order.type = OT_LOADING; |
3289 } |
2893 } |
3290 |
2894 |
3291 void Vehicle::LeaveStation() |
2895 void Vehicle::LeaveStation() |
3292 { |
2896 { |
3293 assert(IsTileType(tile, MP_STATION) || type == VEH_Ship); |
2897 assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP); |
3294 assert(current_order.type == OT_LOADING); |
2898 assert(current_order.type == OT_LOADING); |
3295 current_order.type = OT_LEAVESTATION; |
2899 current_order.type = OT_LEAVESTATION; |
3296 current_order.flags = 0; |
2900 current_order.flags = 0; |
3297 } |
2901 } |