58 * Recalculates the cached total power of a train. Should be called when the consist is changed |
58 * Recalculates the cached total power of a train. Should be called when the consist is changed |
59 * @param v First vehicle of the consist. |
59 * @param v First vehicle of the consist. |
60 */ |
60 */ |
61 void TrainPowerChanged(Vehicle* v) |
61 void TrainPowerChanged(Vehicle* v) |
62 { |
62 { |
63 Vehicle* u; |
|
64 uint32 power = 0; |
63 uint32 power = 0; |
65 uint32 max_te = 0; |
64 uint32 max_te = 0; |
66 |
65 |
67 for (u = v; u != NULL; u = u->next) { |
66 for (const Vehicle *u = v; u != NULL; u = u->next) { |
68 /* Power is not added for articulated parts */ |
67 /* Power is not added for articulated parts */ |
69 if (IsArticulatedPart(u)) continue; |
68 if (IsArticulatedPart(u)) continue; |
70 |
69 |
71 RailType railtype = (IsLevelCrossingTile(u->tile) ? GetRailTypeCrossing(u->tile) : GetRailType(u->tile)); |
70 RailType railtype = (IsLevelCrossingTile(u->tile) ? GetRailTypeCrossing(u->tile) : GetRailType(u->tile)); |
72 bool engine_has_power = HasPowerOnRail(u->u.rail.railtype, railtype); |
71 bool engine_has_power = HasPowerOnRail(u->u.rail.railtype, railtype); |
99 * the consist changes. |
98 * the consist changes. |
100 * @param v First vehicle of the consist. |
99 * @param v First vehicle of the consist. |
101 */ |
100 */ |
102 static void TrainCargoChanged(Vehicle* v) |
101 static void TrainCargoChanged(Vehicle* v) |
103 { |
102 { |
104 Vehicle *u; |
|
105 uint32 weight = 0; |
103 uint32 weight = 0; |
106 |
104 |
107 for (u = v; u != NULL; u = u->next) { |
105 for (Vehicle *u = v; u != NULL; u = u->next) { |
108 const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); |
106 uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo_count * FreightWagonMult(u->cargo_type) / 16; |
109 uint32 vweight = (GetCargo(u->cargo_type)->weight * u->cargo_count * FreightWagonMult(u->cargo_type)) / 16; |
|
110 |
107 |
111 // Vehicle weight is not added for articulated parts. |
108 // Vehicle weight is not added for articulated parts. |
112 if (!IsArticulatedPart(u)) { |
109 if (!IsArticulatedPart(u)) { |
113 // vehicle weight is the sum of the weight of the vehicle and the weight of its cargo |
110 // vehicle weight is the sum of the weight of the vehicle and the weight of its cargo |
114 vweight += rvi->weight; |
111 vweight += RailVehInfo(u->engine_type)->weight; |
115 |
112 |
116 // powered wagons have extra weight added |
113 // powered wagons have extra weight added |
117 if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON)) |
114 if (HASBIT(u->u.rail.flags, VRF_POWEREDWAGON)) |
118 vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight; |
115 vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight; |
119 } |
116 } |
139 * Note: this needs to be called too for 'wagon chains' (in the depot, without an engine) |
136 * Note: this needs to be called too for 'wagon chains' (in the depot, without an engine) |
140 * @param v First vehicle of the chain. |
137 * @param v First vehicle of the chain. |
141 */ |
138 */ |
142 void TrainConsistChanged(Vehicle* v) |
139 void TrainConsistChanged(Vehicle* v) |
143 { |
140 { |
144 const RailVehicleInfo *rvi_v; |
|
145 Vehicle *u; |
|
146 uint16 max_speed = 0xFFFF; |
141 uint16 max_speed = 0xFFFF; |
147 EngineID first_engine; |
|
148 |
142 |
149 assert(v->type == VEH_Train); |
143 assert(v->type == VEH_Train); |
150 |
|
151 assert(IsFrontEngine(v) || IsFreeWagon(v)); |
144 assert(IsFrontEngine(v) || IsFreeWagon(v)); |
152 |
145 |
153 rvi_v = RailVehInfo(v->engine_type); |
146 const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type); |
154 first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE; |
147 EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE; |
155 v->u.rail.cached_total_length = 0; |
148 v->u.rail.cached_total_length = 0; |
156 v->u.rail.compatible_railtypes = 0; |
149 v->u.rail.compatible_railtypes = 0; |
157 |
150 |
158 for (u = v; u != NULL; u = u->next) { |
151 for (Vehicle *u = v; u != NULL; u = u->next) { |
159 const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); |
152 const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); |
160 uint16 veh_len; |
|
161 |
153 |
162 // Update the v->first cache. This is faster than having to brute force it later. |
154 // Update the v->first cache. This is faster than having to brute force it later. |
163 if (u->first == NULL) u->first = v; |
155 if (u->first == NULL) u->first = v; |
164 |
156 |
165 // update the 'first engine' |
157 // update the 'first engine' |
166 u->u.rail.first_engine = (v == u) ? (EngineID)INVALID_ENGINE : first_engine; |
158 u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine; |
167 u->u.rail.railtype = rvi_u->railtype; |
159 u->u.rail.railtype = rvi_u->railtype; |
168 |
160 |
169 if (IsTrainEngine(u)) first_engine = u->engine_type; |
161 if (IsTrainEngine(u)) first_engine = u->engine_type; |
170 |
162 |
171 if (rvi_u->visual_effect != 0) { |
163 if (rvi_u->visual_effect != 0) { |
182 u->u.rail.cached_vis_effect = 8; |
174 u->u.rail.cached_vis_effect = 8; |
183 } |
175 } |
184 } |
176 } |
185 |
177 |
186 if (!IsArticulatedPart(u)) { |
178 if (!IsArticulatedPart(u)) { |
187 // check if its a powered wagon |
|
188 CLRBIT(u->u.rail.flags, VRF_POWEREDWAGON); |
|
189 |
|
190 /* Check powered wagon / visual effect callback */ |
179 /* Check powered wagon / visual effect callback */ |
191 if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_WAGON_POWER)) { |
180 if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_WAGON_POWER)) { |
192 uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u); |
181 uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u); |
193 |
182 |
194 if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = callback; |
183 if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = callback; |
196 |
185 |
197 if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON && |
186 if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON && |
198 UsesWagonOverride(u) && (u->u.rail.cached_vis_effect < 0x40)) { |
187 UsesWagonOverride(u) && (u->u.rail.cached_vis_effect < 0x40)) { |
199 /* wagon is powered */ |
188 /* wagon is powered */ |
200 SETBIT(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status |
189 SETBIT(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status |
|
190 } else { |
|
191 CLRBIT(u->u.rail.flags, VRF_POWEREDWAGON); |
201 } |
192 } |
202 |
193 |
203 /* Do not count powered wagons for the compatible railtypes, as wagons always |
194 /* Do not count powered wagons for the compatible railtypes, as wagons always |
204 have railtype normal */ |
195 have railtype normal */ |
205 if (rvi_u->power > 0) { |
196 if (rvi_u->power > 0) { |
218 rvi_u->max_speed != 0 && !UsesWagonOverride(u)) |
209 rvi_u->max_speed != 0 && !UsesWagonOverride(u)) |
219 max_speed = min(rvi_u->max_speed, max_speed); |
210 max_speed = min(rvi_u->max_speed, max_speed); |
220 } |
211 } |
221 |
212 |
222 // check the vehicle length (callback) |
213 // check the vehicle length (callback) |
223 veh_len = CALLBACK_FAILED; |
214 uint16 veh_len = CALLBACK_FAILED; |
224 if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) { |
215 if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) { |
225 veh_len = GetVehicleCallback(CBID_TRAIN_VEHICLE_LENGTH, 0, 0, u->engine_type, u); |
216 veh_len = GetVehicleCallback(CBID_TRAIN_VEHICLE_LENGTH, 0, 0, u->engine_type, u); |
226 } |
217 } |
227 if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor; |
218 if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor; |
228 veh_len = clamp(veh_len, 0, u->next == NULL ? 7 : 5); // the clamp on vehicles not the last in chain is stricter, as too short wagons can break the 'follow next vehicle' code |
219 veh_len = clamp(veh_len, 0, u->next == NULL ? 7 : 5); // the clamp on vehicles not the last in chain is stricter, as too short wagons can break the 'follow next vehicle' code |
229 u->u.rail.cached_veh_length = 8 - veh_len; |
220 u->u.rail.cached_veh_length = 8 - veh_len; |
230 v->u.rail.cached_total_length += u->u.rail.cached_veh_length; |
221 v->u.rail.cached_total_length += u->u.rail.cached_veh_length; |
231 |
222 } |
232 }; |
|
233 |
223 |
234 // store consist weight/max speed in cache |
224 // store consist weight/max speed in cache |
235 v->u.rail.cached_max_speed = max_speed; |
225 v->u.rail.cached_max_speed = max_speed; |
236 |
226 |
237 // 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) |
227 // recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) |
289 } |
279 } |
290 |
280 |
291 //new acceleration |
281 //new acceleration |
292 static int GetTrainAcceleration(Vehicle *v, bool mode) |
282 static int GetTrainAcceleration(Vehicle *v, bool mode) |
293 { |
283 { |
294 const Vehicle *u; |
|
295 int num = 0; //number of vehicles, change this into the number of axles later |
|
296 int power = 0; |
|
297 int mass = 0; |
|
298 int max_speed = 2000; |
284 int max_speed = 2000; |
299 int area = 120; |
285 int speed = v->cur_speed * 10 / 16; //[mph] |
300 int friction = 35; //[1e-3] |
286 int curvecount[2] = {0, 0}; |
301 int drag_coeff = 20; //[1e-4] |
287 |
302 int incl = 0; |
288 //first find the curve speed limit |
303 int resistance; |
289 int numcurve = 0; |
304 int speed = v->cur_speed; //[mph] |
290 int sum = 0; |
305 int force = 0x3FFFFFFF; |
|
306 int pos = 0; |
291 int pos = 0; |
307 int lastpos = -1; |
292 int lastpos = -1; |
308 int curvecount[2] = {0, 0}; |
293 for (const Vehicle *u = v; u->next != NULL; u = u->next, pos++) { |
309 int sum = 0; |
|
310 int numcurve = 0; |
|
311 int max_te = v->u.rail.cached_max_te; // [N] |
|
312 |
|
313 speed *= 10; |
|
314 speed /= 16; |
|
315 |
|
316 //first find the curve speed limit |
|
317 for (u = v; u->next != NULL; u = u->next, pos++) { |
|
318 Direction dir = u->direction; |
294 Direction dir = u->direction; |
319 Direction ndir = u->next->direction; |
295 Direction ndir = u->next->direction; |
320 int i; |
296 int i; |
321 |
297 |
322 for (i = 0; i < 2; i++) { |
298 for (i = 0; i < 2; i++) { |
367 |
343 |
368 max_speed = max(max_speed, 25 * station_length); |
344 max_speed = max(max_speed, 25 * station_length); |
369 } |
345 } |
370 } |
346 } |
371 |
347 |
372 mass = v->u.rail.cached_weight; |
348 int mass = v->u.rail.cached_weight; |
373 power = v->u.rail.cached_power * 746; |
349 int power = v->u.rail.cached_power * 746; |
374 max_speed = min(max_speed, v->u.rail.cached_max_speed); |
350 max_speed = min(max_speed, v->u.rail.cached_max_speed); |
375 |
351 |
376 for (u = v; u != NULL; u = u->next) { |
352 int num = 0; //number of vehicles, change this into the number of axles later |
|
353 int incl = 0; |
|
354 int drag_coeff = 20; //[1e-4] |
|
355 for (const Vehicle *u = v; u != NULL; u = u->next) { |
377 num++; |
356 num++; |
378 drag_coeff += 3; |
357 drag_coeff += 3; |
379 |
358 |
380 if (u->u.rail.track == TRACK_BIT_DEPOT) max_speed = min(max_speed, 61); |
359 if (u->u.rail.track == TRACK_BIT_DEPOT) max_speed = min(max_speed, 61); |
381 |
360 |
435 } |
418 } |
436 } |
419 } |
437 |
420 |
438 static void UpdateTrainAcceleration(Vehicle* v) |
421 static void UpdateTrainAcceleration(Vehicle* v) |
439 { |
422 { |
440 uint power = 0; |
|
441 uint weight = 0; |
|
442 |
|
443 assert(IsFrontEngine(v)); |
423 assert(IsFrontEngine(v)); |
444 |
424 |
445 weight = v->u.rail.cached_weight; |
|
446 power = v->u.rail.cached_power; |
|
447 v->max_speed = v->u.rail.cached_max_speed; |
425 v->max_speed = v->u.rail.cached_max_speed; |
448 |
426 |
|
427 uint power = v->u.rail.cached_power; |
|
428 uint weight = v->u.rail.cached_weight; |
449 assert(weight != 0); |
429 assert(weight != 0); |
450 |
|
451 v->acceleration = clamp(power / weight * 4, 1, 255); |
430 v->acceleration = clamp(power / weight * 4, 1, 255); |
452 } |
431 } |
453 |
432 |
454 int GetTrainImage(const Vehicle* v, Direction direction) |
433 int GetTrainImage(const Vehicle* v, Direction direction) |
455 { |
434 { |
506 DrawSprite(image, pal, x, y); |
485 DrawSprite(image, pal, x, y); |
507 } |
486 } |
508 |
487 |
509 uint CountArticulatedParts(EngineID engine_type) |
488 uint CountArticulatedParts(EngineID engine_type) |
510 { |
489 { |
511 uint16 callback; |
490 if (!HASBIT(EngInfo(engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return 0; |
|
491 |
512 uint i; |
492 uint i; |
513 |
|
514 if (!HASBIT(EngInfo(engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return 0; |
|
515 |
|
516 for (i = 1; i < 10; i++) { |
493 for (i = 1; i < 10; i++) { |
517 callback = GetVehicleCallback(CBID_TRAIN_ARTIC_ENGINE, i, 0, engine_type, NULL); |
494 uint16 callback = GetVehicleCallback(CBID_TRAIN_ARTIC_ENGINE, i, 0, engine_type, NULL); |
518 if (callback == CALLBACK_FAILED || callback == 0xFF) break; |
495 if (callback == CALLBACK_FAILED || callback == 0xFF) break; |
519 } |
496 } |
520 |
497 |
521 return i - 1; |
498 return i - 1; |
522 } |
499 } |
523 |
500 |
524 static void AddArticulatedParts(Vehicle **vl) |
501 static void AddArticulatedParts(Vehicle **vl) |
525 { |
502 { |
526 const RailVehicleInfo *rvi_artic; |
503 const Vehicle *v = vl[0]; |
527 EngineID engine_type; |
504 Vehicle *u = vl[0]; |
528 Vehicle *v = vl[0]; |
|
529 Vehicle *u = v; |
|
530 uint16 callback; |
|
531 bool flip_image; |
|
532 uint i; |
|
533 |
505 |
534 if (!HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return; |
506 if (!HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return; |
535 |
507 |
536 for (i = 1; i < 10; i++) { |
508 for (uint i = 1; i < 10; i++) { |
537 callback = GetVehicleCallback(CBID_TRAIN_ARTIC_ENGINE, i, 0, v->engine_type, v); |
509 uint16 callback = GetVehicleCallback(CBID_TRAIN_ARTIC_ENGINE, i, 0, v->engine_type, v); |
538 if (callback == CALLBACK_FAILED || callback == 0xFF) return; |
510 if (callback == CALLBACK_FAILED || callback == 0xFF) return; |
539 |
511 |
540 /* Attempt to use pre-allocated vehicles until they run out. This can happen |
512 /* Attempt to use pre-allocated vehicles until they run out. This can happen |
541 * if the callback returns different values depending on the cargo type. */ |
513 * if the callback returns different values depending on the cargo type. */ |
542 u->next = vl[i]; |
514 u->next = vl[i]; |
543 if (u->next == NULL) u->next = AllocateVehicle(); |
515 if (u->next == NULL) u->next = AllocateVehicle(); |
544 if (u->next == NULL) return; |
516 if (u->next == NULL) return; |
545 |
517 |
546 u = u->next; |
518 u = u->next; |
547 |
519 |
548 engine_type = GB(callback, 0, 7); |
520 EngineID engine_type = GB(callback, 0, 7); |
549 flip_image = HASBIT(callback, 7); |
521 bool flip_image = HASBIT(callback, 7); |
550 rvi_artic = RailVehInfo(engine_type); |
522 const RailVehicleInfo *rvi_artic = RailVehInfo(engine_type); |
551 |
523 |
552 // get common values from first engine |
524 // get common values from first engine |
553 u->direction = v->direction; |
525 u->direction = v->direction; |
554 u->owner = v->owner; |
526 u->owner = v->owner; |
555 u->tile = v->tile; |
527 u->tile = v->tile; |
583 } |
555 } |
584 } |
556 } |
585 |
557 |
586 static int32 CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags) |
558 static int32 CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags) |
587 { |
559 { |
588 int32 value; |
|
589 const RailVehicleInfo *rvi; |
|
590 uint num_vehicles; |
|
591 |
|
592 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
560 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
593 |
561 |
594 rvi = RailVehInfo(engine); |
562 const RailVehicleInfo *rvi = RailVehInfo(engine); |
595 value = (rvi->base_cost * _price.build_railwagon) >> 8; |
563 int32 value = (rvi->base_cost * _price.build_railwagon) >> 8; |
596 |
564 |
597 num_vehicles = 1 + CountArticulatedParts(engine); |
565 uint num_vehicles = 1 + CountArticulatedParts(engine); |
598 |
566 |
599 if (!(flags & DC_QUERY_COST)) { |
567 if (!(flags & DC_QUERY_COST)) { |
600 Vehicle *vl[11]; // Allow for wagon and upto 10 artic parts. |
568 Vehicle *vl[11]; // Allow for wagon and upto 10 artic parts. |
601 Vehicle* v; |
|
602 int x; |
|
603 int y; |
|
604 |
569 |
605 memset(&vl, 0, sizeof(vl)); |
570 memset(&vl, 0, sizeof(vl)); |
606 |
571 |
607 if (!AllocateVehicles(vl, num_vehicles)) |
572 if (!AllocateVehicles(vl, num_vehicles)) |
608 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
573 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
609 |
574 |
610 if (flags & DC_EXEC) { |
575 if (flags & DC_EXEC) { |
611 Vehicle *u, *w; |
576 Vehicle *v = vl[0]; |
612 DiagDirection dir; |
|
613 |
|
614 v = vl[0]; |
|
615 v->spritenum = rvi->image_index; |
577 v->spritenum = rvi->image_index; |
616 |
578 |
617 u = NULL; |
579 Vehicle *u = NULL; |
618 |
580 |
|
581 Vehicle *w; |
619 FOR_ALL_VEHICLES(w) { |
582 FOR_ALL_VEHICLES(w) { |
620 if (w->type == VEH_Train && w->tile == tile && |
583 if (w->type == VEH_Train && w->tile == tile && |
621 IsFreeWagon(w) && w->engine_type == engine) { |
584 IsFreeWagon(w) && w->engine_type == engine) { |
622 u = GetLastVehicleInChain(w); |
585 u = GetLastVehicleInChain(w); |
623 break; |
586 break; |
624 } |
587 } |
625 } |
588 } |
626 |
589 |
627 v->engine_type = engine; |
590 v->engine_type = engine; |
628 |
591 |
629 dir = GetRailDepotDirection(tile); |
592 DiagDirection dir = GetRailDepotDirection(tile); |
630 |
593 |
631 v->direction = DiagDirToDir(dir); |
594 v->direction = DiagDirToDir(dir); |
632 v->tile = tile; |
595 v->tile = tile; |
633 |
596 |
634 x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir]; |
597 int x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir]; |
635 y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir]; |
598 int y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir]; |
636 |
599 |
637 v->x_pos = x; |
600 v->x_pos = x; |
638 v->y_pos = y; |
601 v->y_pos = y; |
639 v->z_pos = GetSlopeZ(x,y); |
602 v->z_pos = GetSlopeZ(x, y); |
640 v->owner = _current_player; |
603 v->owner = _current_player; |
641 v->z_height = 6; |
604 v->z_height = 6; |
642 v->u.rail.track = TRACK_BIT_DEPOT; |
605 v->u.rail.track = TRACK_BIT_DEPOT; |
643 v->vehstatus = VS_HIDDEN | VS_DEFPAL; |
606 v->vehstatus = VS_HIDDEN | VS_DEFPAL; |
644 |
607 |
738 * @param p2 bit 0 when set, the train will get number 0, otherwise it will get a free number |
701 * @param p2 bit 0 when set, the train will get number 0, otherwise it will get a free number |
739 * bit 1 prevents any free cars from being added to the train |
702 * bit 1 prevents any free cars from being added to the train |
740 */ |
703 */ |
741 int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
704 int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
742 { |
705 { |
743 const RailVehicleInfo *rvi; |
|
744 int value; |
|
745 Vehicle *v; |
|
746 UnitID unit_num; |
|
747 uint num_vehicles; |
|
748 |
|
749 /* Check if the engine-type is valid (for the player) */ |
706 /* Check if the engine-type is valid (for the player) */ |
750 if (!IsEngineBuildable(p1, VEH_Train, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE); |
707 if (!IsEngineBuildable(p1, VEH_Train, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE); |
751 |
708 |
752 /* Check if the train is actually being built in a depot belonging |
709 /* Check if the train is actually being built in a depot belonging |
753 * to the player. Doesn't matter if only the cost is queried */ |
710 * to the player. Doesn't matter if only the cost is queried */ |
756 if (!IsTileOwner(tile, _current_player)) return CMD_ERROR; |
713 if (!IsTileOwner(tile, _current_player)) return CMD_ERROR; |
757 } |
714 } |
758 |
715 |
759 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
716 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
760 |
717 |
761 rvi = RailVehInfo(p1); |
718 const RailVehicleInfo *rvi = RailVehInfo(p1); |
762 |
719 |
763 /* Check if depot and new engine uses the same kind of tracks */ |
720 /* Check if depot and new engine uses the same kind of tracks */ |
764 /* We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */ |
721 /* We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */ |
765 if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; |
722 if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; |
766 |
723 |
767 if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags); |
724 if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags); |
768 |
725 |
769 value = EstimateTrainCost(rvi); |
726 int32 value = EstimateTrainCost(rvi); |
770 |
727 |
771 num_vehicles = (rvi->railveh_type == RAILVEH_MULTIHEAD) ? 2 : 1; |
728 uint num_vehicles = |
772 num_vehicles += CountArticulatedParts(p1); |
729 (rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + |
|
730 CountArticulatedParts(p1); |
773 |
731 |
774 if (!(flags & DC_QUERY_COST)) { |
732 if (!(flags & DC_QUERY_COST)) { |
775 Vehicle *vl[12]; // Allow for upto 10 artic parts and dual-heads |
733 Vehicle *vl[12]; // Allow for upto 10 artic parts and dual-heads |
776 |
734 |
777 memset(&vl, 0, sizeof(vl)); |
735 memset(&vl, 0, sizeof(vl)); |
778 |
736 |
779 if (!AllocateVehicles(vl, num_vehicles)) |
737 if (!AllocateVehicles(vl, num_vehicles)) |
780 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
738 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
781 |
739 |
782 v = vl[0]; |
740 Vehicle *v = vl[0]; |
783 |
741 |
784 unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Train); |
742 UnitID unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Train); |
785 if (unit_num > _patches.max_trains) |
743 if (unit_num > _patches.max_trains) |
786 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
744 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
787 |
745 |
788 if (flags & DC_EXEC) { |
746 if (flags & DC_EXEC) { |
789 DiagDirection dir = GetRailDepotDirection(tile); |
747 DiagDirection dir = GetRailDepotDirection(tile); |
869 |
827 |
870 /* Check if all the wagons of the given train are in a depot, returns the |
828 /* Check if all the wagons of the given train are in a depot, returns the |
871 * number of cars (including loco) then. If not it returns -1 */ |
829 * number of cars (including loco) then. If not it returns -1 */ |
872 int CheckTrainInDepot(const Vehicle *v, bool needs_to_be_stopped) |
830 int CheckTrainInDepot(const Vehicle *v, bool needs_to_be_stopped) |
873 { |
831 { |
874 int count; |
|
875 TileIndex tile = v->tile; |
832 TileIndex tile = v->tile; |
876 |
833 |
877 /* check if stopped in a depot */ |
834 /* check if stopped in a depot */ |
878 if (!IsTileDepotType(tile, TRANSPORT_RAIL) || v->cur_speed != 0) return -1; |
835 if (!IsTileDepotType(tile, TRANSPORT_RAIL) || v->cur_speed != 0) return -1; |
879 |
836 |
880 count = 0; |
837 int count = 0; |
881 for (; v != NULL; v = v->next) { |
838 for (; v != NULL; v = v->next) { |
882 /* This count is used by the depot code to determine the number of engines |
839 /* This count is used by the depot code to determine the number of engines |
883 * in the consist. Exclude articulated parts so that autoreplacing to |
840 * in the consist. Exclude articulated parts so that autoreplacing to |
884 * engines with more articulated parts than before works correctly. |
841 * engines with more articulated parts than before works correctly. |
885 * |
842 * |
901 } |
858 } |
902 |
859 |
903 /* Used to check if the train is inside the depot, but not checking the VS_STOPPED flag */ |
860 /* Used to check if the train is inside the depot, but not checking the VS_STOPPED flag */ |
904 inline bool CheckTrainIsInsideDepot(const Vehicle *v) |
861 inline bool CheckTrainIsInsideDepot(const Vehicle *v) |
905 { |
862 { |
906 return (CheckTrainInDepot(v, false) > 0); |
863 return CheckTrainInDepot(v, false) > 0; |
907 } |
864 } |
908 |
865 |
909 /** |
866 /** |
910 * Unlink a rail wagon from the consist. |
867 * Unlink a rail wagon from the consist. |
911 * @param v Vehicle to remove. |
868 * @param v Vehicle to remove. |
912 * @param first The first vehicle of the consist. |
869 * @param first The first vehicle of the consist. |
913 * @return The first vehicle of the consist. |
870 * @return The first vehicle of the consist. |
914 */ |
871 */ |
915 static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first) |
872 static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first) |
916 { |
873 { |
917 Vehicle *u; |
|
918 |
|
919 // unlinking the first vehicle of the chain? |
874 // unlinking the first vehicle of the chain? |
920 if (v == first) { |
875 if (v == first) { |
921 v = GetNextVehicle(v); |
876 v = GetNextVehicle(v); |
922 if (v == NULL) return NULL; |
877 if (v == NULL) return NULL; |
923 |
878 |
924 if (IsTrainWagon(v)) SetFreeWagon(v); |
879 if (IsTrainWagon(v)) SetFreeWagon(v); |
925 |
880 |
926 return v; |
881 return v; |
927 } |
882 } |
928 |
883 |
|
884 Vehicle *u; |
929 for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {} |
885 for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {} |
930 GetLastEnginePart(u)->next = GetNextVehicle(v); |
886 GetLastEnginePart(u)->next = GetNextVehicle(v); |
931 return first; |
887 return first; |
932 } |
888 } |
933 |
889 |
971 * move around on the train so rear engines are placed correctly according to the other engines |
927 * move around on the train so rear engines are placed correctly according to the other engines |
972 * always call with the front engine |
928 * always call with the front engine |
973 */ |
929 */ |
974 static void NormaliseTrainConsist(Vehicle *v) |
930 static void NormaliseTrainConsist(Vehicle *v) |
975 { |
931 { |
976 Vehicle *u; |
|
977 |
|
978 if (IsFreeWagon(v)) return; |
932 if (IsFreeWagon(v)) return; |
979 |
933 |
980 assert(IsFrontEngine(v)); |
934 assert(IsFrontEngine(v)); |
981 |
935 |
982 for (; v != NULL; v = GetNextVehicle(v)) { |
936 for (; v != NULL; v = GetNextVehicle(v)) { |
983 if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue; |
937 if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue; |
984 |
938 |
985 /* make sure that there are no free cars before next engine */ |
939 /* make sure that there are no free cars before next engine */ |
986 for (u = v; u->next != NULL && !IsTrainEngine(u->next); u = u->next); |
940 Vehicle *u; |
|
941 for (u = v; u->next != NULL && !IsTrainEngine(u->next); u = u->next) {} |
987 |
942 |
988 if (u == v->u.rail.other_multiheaded_part) continue; |
943 if (u == v->u.rail.other_multiheaded_part) continue; |
989 AddWagonToConsist(v->u.rail.other_multiheaded_part, u); |
944 AddWagonToConsist(v->u.rail.other_multiheaded_part, u); |
990 } |
945 } |
991 } |
946 } |
999 */ |
954 */ |
1000 int32 CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
955 int32 CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1001 { |
956 { |
1002 VehicleID s = GB(p1, 0, 16); |
957 VehicleID s = GB(p1, 0, 16); |
1003 VehicleID d = GB(p1, 16, 16); |
958 VehicleID d = GB(p1, 16, 16); |
1004 Vehicle *src, *dst, *src_head, *dst_head; |
|
1005 |
959 |
1006 if (!IsValidVehicleID(s)) return CMD_ERROR; |
960 if (!IsValidVehicleID(s)) return CMD_ERROR; |
1007 |
961 |
1008 src = GetVehicle(s); |
962 Vehicle *src = GetVehicle(s); |
1009 |
963 |
1010 if (src->type != VEH_Train || !CheckOwnership(src->owner)) return CMD_ERROR; |
964 if (src->type != VEH_Train || !CheckOwnership(src->owner)) return CMD_ERROR; |
1011 |
965 |
1012 // if nothing is selected as destination, try and find a matching vehicle to drag to. |
966 // if nothing is selected as destination, try and find a matching vehicle to drag to. |
|
967 Vehicle *dst; |
1013 if (d == INVALID_VEHICLE) { |
968 if (d == INVALID_VEHICLE) { |
1014 dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src); |
969 dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src); |
1015 } else { |
970 } else { |
1016 if (!IsValidVehicleID(d)) return CMD_ERROR; |
971 if (!IsValidVehicleID(d)) return CMD_ERROR; |
1017 dst = GetVehicle(d); |
972 dst = GetVehicle(d); |
1026 |
981 |
1027 // don't move the same vehicle.. |
982 // don't move the same vehicle.. |
1028 if (src == dst) return 0; |
983 if (src == dst) return 0; |
1029 |
984 |
1030 /* locate the head of the two chains */ |
985 /* locate the head of the two chains */ |
1031 src_head = GetFirstVehicleInChain(src); |
986 Vehicle *src_head = GetFirstVehicleInChain(src); |
|
987 Vehicle *dst_head; |
1032 if (dst != NULL) { |
988 if (dst != NULL) { |
1033 dst_head = GetFirstVehicleInChain(dst); |
989 dst_head = GetFirstVehicleInChain(dst); |
1034 if (dst_head->tile != src_head->tile) return CMD_ERROR; |
990 if (dst_head->tile != src_head->tile) return CMD_ERROR; |
1035 // Now deal with articulated part of destination wagon |
991 // Now deal with articulated part of destination wagon |
1036 dst = GetLastEnginePart(dst); |
992 dst = GetLastEnginePart(dst); |
1075 |
1031 |
1076 // when moving all wagons, we can't have the same src_head and dst_head |
1032 // when moving all wagons, we can't have the same src_head and dst_head |
1077 if (HASBIT(p2, 0) && src_head == dst_head) return 0; |
1033 if (HASBIT(p2, 0) && src_head == dst_head) return 0; |
1078 |
1034 |
1079 { |
1035 { |
1080 int src_len = 0; |
|
1081 int max_len = _patches.mammoth_trains ? 100 : 9; |
1036 int max_len = _patches.mammoth_trains ? 100 : 9; |
1082 |
1037 |
1083 // check if all vehicles in the source train are stopped inside a depot. |
1038 // check if all vehicles in the source train are stopped inside a depot. |
1084 src_len = CheckTrainStoppedInDepot(src_head); |
1039 int src_len = CheckTrainStoppedInDepot(src_head); |
1085 if (src_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1040 if (src_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1086 |
1041 |
1087 // check the destination row if the source and destination aren't the same. |
1042 // check the destination row if the source and destination aren't the same. |
1088 if (src_head != dst_head) { |
1043 if (src_head != dst_head) { |
1089 int dst_len = 0; |
1044 int dst_len = 0; |
1253 InvalidateWindow(WC_VEHICLE_REFIT, src_head->index); |
1204 InvalidateWindow(WC_VEHICLE_REFIT, src_head->index); |
1254 InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, 12); |
1205 InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, 12); |
1255 } |
1206 } |
1256 /* Update the depot window */ |
1207 /* Update the depot window */ |
1257 InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile); |
1208 InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile); |
1258 }; |
1209 } |
1259 |
1210 |
1260 if (dst_head != NULL) { |
1211 if (dst_head != NULL) { |
1261 NormaliseTrainConsist(dst_head); |
1212 NormaliseTrainConsist(dst_head); |
1262 TrainConsistChanged(dst_head); |
1213 TrainConsistChanged(dst_head); |
1263 if (IsFrontEngine(dst_head)) { |
1214 if (IsFrontEngine(dst_head)) { |
1282 * @param p1 train to start/stop |
1233 * @param p1 train to start/stop |
1283 * @param p2 unused |
1234 * @param p2 unused |
1284 */ |
1235 */ |
1285 int32 CmdStartStopTrain(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1236 int32 CmdStartStopTrain(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1286 { |
1237 { |
1287 Vehicle *v; |
|
1288 uint16 callback; |
|
1289 |
|
1290 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1238 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1291 |
1239 |
1292 v = GetVehicle(p1); |
1240 Vehicle *v = GetVehicle(p1); |
1293 |
1241 |
1294 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1242 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1295 |
1243 |
1296 /* Check if this train can be started/stopped. The callback will fail or |
1244 /* Check if this train can be started/stopped. The callback will fail or |
1297 * return 0xFF if it can. */ |
1245 * return 0xFF if it can. */ |
1298 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); |
1246 uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); |
1299 if (callback != CALLBACK_FAILED && callback != 0xFF) { |
1247 if (callback != CALLBACK_FAILED && callback != 0xFF) { |
1300 StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback); |
1248 StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback); |
1301 return_cmd_error(error); |
1249 return_cmd_error(error); |
1302 } |
1250 } |
1303 |
1251 |
1326 * - p2 = 2: when selling attached locos, rearrange all vehicles after it to separate lines; |
1274 * - p2 = 2: when selling attached locos, rearrange all vehicles after it to separate lines; |
1327 * all wagons of the same type will go on the same line. Used by the AI currently |
1275 * all wagons of the same type will go on the same line. Used by the AI currently |
1328 */ |
1276 */ |
1329 int32 CmdSellRailWagon(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1277 int32 CmdSellRailWagon(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1330 { |
1278 { |
1331 Vehicle *v, *tmp, *first; |
|
1332 Vehicle *new_f = NULL; |
|
1333 int32 cost = 0; |
|
1334 |
|
1335 if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR; |
1279 if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR; |
1336 |
1280 |
1337 v = GetVehicle(p1); |
1281 Vehicle *v = GetVehicle(p1); |
1338 |
1282 |
1339 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1283 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1340 |
1284 |
1341 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1285 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1342 |
1286 |
1343 while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v); |
1287 while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v); |
1344 first = GetFirstVehicleInChain(v); |
1288 Vehicle *first = GetFirstVehicleInChain(v); |
1345 |
1289 |
1346 // make sure the vehicle is stopped in the depot |
1290 // make sure the vehicle is stopped in the depot |
1347 if (CheckTrainStoppedInDepot(first) < 0) { |
1291 if (CheckTrainStoppedInDepot(first) < 0) { |
1348 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1292 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1349 } |
1293 } |
1378 } |
1323 } |
1379 |
1324 |
1380 /* 2. We are selling the first engine, some special action might be required |
1325 /* 2. We are selling the first engine, some special action might be required |
1381 * here, so take attention */ |
1326 * here, so take attention */ |
1382 if ((flags & DC_EXEC) && v == first) { |
1327 if ((flags & DC_EXEC) && v == first) { |
1383 new_f = GetNextVehicle(first); |
1328 Vehicle *new_f = GetNextVehicle(first); |
1384 |
1329 |
1385 /* 2.1 If the first wagon is sold, update the first-> pointers to NULL */ |
1330 /* 2.1 If the first wagon is sold, update the first-> pointers to NULL */ |
1386 for (tmp = first; tmp != NULL; tmp = tmp->next) tmp->first = NULL; |
1331 for (Vehicle *tmp = first; tmp != NULL; tmp = tmp->next) tmp->first = NULL; |
1387 |
1332 |
1388 /* 2.2 If there are wagons present after the deleted front engine, check |
1333 /* 2.2 If there are wagons present after the deleted front engine, check |
1389 * if the second wagon (which will be first) is an engine. If it is one, |
1334 * if the second wagon (which will be first) is an engine. If it is one, |
1390 * promote it as a new train, retaining the unitnumber, orders */ |
1335 * promote it as a new train, retaining the unitnumber, orders */ |
1391 if (new_f != NULL) { |
1336 if (new_f != NULL) { |
1439 /* (6.) Borked AI. If it sells an engine it expects all wagons lined |
1384 /* (6.) Borked AI. If it sells an engine it expects all wagons lined |
1440 * up on a new line to be added to the newly built loco. Replace it is. |
1385 * up on a new line to be added to the newly built loco. Replace it is. |
1441 * Totally braindead cause building a new engine adds all loco-less |
1386 * Totally braindead cause building a new engine adds all loco-less |
1442 * engines to its train anyways */ |
1387 * engines to its train anyways */ |
1443 if (p2 == 2 && HASBIT(ori_subtype, Train_Front)) { |
1388 if (p2 == 2 && HASBIT(ori_subtype, Train_Front)) { |
|
1389 Vehicle *tmp; |
1444 for (v = first; v != NULL; v = tmp) { |
1390 for (v = first; v != NULL; v = tmp) { |
1445 tmp = GetNextVehicle(v); |
1391 tmp = GetNextVehicle(v); |
1446 DoCommand(v->tile, v->index | INVALID_VEHICLE << 16, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
1392 DoCommand(v->tile, v->index | INVALID_VEHICLE << 16, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); |
1447 } |
1393 } |
1448 } |
1394 } |
1450 } break; |
1396 } break; |
1451 case 1: { /* Delete wagon and all wagons after it given certain criteria */ |
1397 case 1: { /* Delete wagon and all wagons after it given certain criteria */ |
1452 /* Start deleting every vehicle after the selected one |
1398 /* Start deleting every vehicle after the selected one |
1453 * If we encounter a matching rear-engine to a front-engine |
1399 * If we encounter a matching rear-engine to a front-engine |
1454 * earlier in the chain (before deletion), leave it alone */ |
1400 * earlier in the chain (before deletion), leave it alone */ |
|
1401 Vehicle *tmp; |
1455 for (; v != NULL; v = tmp) { |
1402 for (; v != NULL; v = tmp) { |
1456 tmp = GetNextVehicle(v); |
1403 tmp = GetNextVehicle(v); |
1457 |
1404 |
1458 if (IsMultiheaded(v)) { |
1405 if (IsMultiheaded(v)) { |
1459 if (IsTrainEngine(v)) { |
1406 if (IsTrainEngine(v)) { |
1634 * @param v First vehicle in chain |
1579 * @param v First vehicle in chain |
1635 * @param before Set to true for the call before reversing, false otherwise |
1580 * @param before Set to true for the call before reversing, false otherwise |
1636 */ |
1581 */ |
1637 static void AdvanceWagons(Vehicle *v, bool before) |
1582 static void AdvanceWagons(Vehicle *v, bool before) |
1638 { |
1583 { |
1639 Vehicle* base; |
1584 Vehicle *base = v; |
1640 Vehicle* first; |
1585 Vehicle *first = base->next; |
1641 int length; |
1586 uint length = CountVehiclesInChain(v); |
1642 |
|
1643 base = v; |
|
1644 first = base->next; |
|
1645 length = CountVehiclesInChain(v); |
|
1646 |
1587 |
1647 while (length > 2) { |
1588 while (length > 2) { |
1648 Vehicle* last; |
|
1649 int differential; |
|
1650 int i; |
|
1651 |
|
1652 // find pairwise matching wagon |
1589 // find pairwise matching wagon |
1653 // start<>end, start+1<>end-1, ... |
1590 // start<>end, start+1<>end-1, ... |
1654 last = first; |
1591 Vehicle *last = first; |
1655 for (i = length - 3; i > 0; i--) last = last->next; |
1592 for (uint i = length - 3; i > 0; i--) last = last->next; |
1656 |
1593 |
1657 differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length; |
1594 int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length; |
1658 if (before) differential *= -1; |
1595 if (before) differential *= -1; |
1659 |
1596 |
1660 if (differential > 0) { |
1597 if (differential > 0) { |
1661 Vehicle* tempnext; |
|
1662 |
|
1663 // disconnect last car to make sure only this subset moves |
1598 // disconnect last car to make sure only this subset moves |
1664 tempnext = last->next; |
1599 Vehicle *tempnext = last->next; |
1665 last->next = NULL; |
1600 last->next = NULL; |
1666 |
1601 |
1667 for (i = 0; i < differential; i++) TrainController(first, false); |
1602 for (int i = 0; i < differential; i++) TrainController(first, false); |
1668 |
1603 |
1669 last->next = tempnext; |
1604 last->next = tempnext; |
1670 } |
1605 } |
1671 |
1606 |
1672 base = first; |
1607 base = first; |
1700 /* Check if the train left a rail/road-crossing */ |
1632 /* Check if the train left a rail/road-crossing */ |
1701 DisableTrainCrossing(tile); |
1633 DisableTrainCrossing(tile); |
1702 } |
1634 } |
1703 |
1635 |
1704 // count number of vehicles |
1636 // count number of vehicles |
1705 u = v; |
1637 int r = -1; |
|
1638 const Vehicle *u = v; |
1706 do r++; while ( (u = u->next) != NULL ); |
1639 do r++; while ( (u = u->next) != NULL ); |
1707 |
1640 |
1708 AdvanceWagons(v, true); |
1641 AdvanceWagons(v, true); |
1709 |
1642 |
1710 /* swap start<>end, start+1<>end-1, ... */ |
1643 /* swap start<>end, start+1<>end-1, ... */ |
|
1644 int l = 0; |
1711 do { |
1645 do { |
1712 ReverseTrainSwapVeh(v, l++, r--); |
1646 ReverseTrainSwapVeh(v, l++, r--); |
1713 } while (l <= r); |
1647 } while (l <= r); |
1714 |
1648 |
1715 AdvanceWagons(v, false); |
1649 AdvanceWagons(v, false); |
1726 * @param p1 train to reverse |
1660 * @param p1 train to reverse |
1727 * @param p2 if true, reverse a unit in a train (needs to be in a depot) |
1661 * @param p2 if true, reverse a unit in a train (needs to be in a depot) |
1728 */ |
1662 */ |
1729 int32 CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1663 int32 CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1730 { |
1664 { |
1731 Vehicle *v; |
|
1732 |
|
1733 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1665 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1734 |
1666 |
1735 v = GetVehicle(p1); |
1667 Vehicle *v = GetVehicle(p1); |
1736 |
1668 |
1737 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1669 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1738 |
1670 |
1739 if (p2) { |
1671 if (p2) { |
1740 // turn a single unit around |
1672 // turn a single unit around |
1741 Vehicle *front; |
|
1742 |
1673 |
1743 if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) { |
1674 if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) { |
1744 return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT); |
1675 return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT); |
1745 } |
1676 } |
1746 |
1677 |
1747 front = GetFirstVehicleInChain(v); |
1678 Vehicle *front = GetFirstVehicleInChain(v); |
1748 // make sure the vehicle is stopped in the depot |
1679 // make sure the vehicle is stopped in the depot |
1749 if (CheckTrainStoppedInDepot(front) < 0) { |
1680 if (CheckTrainStoppedInDepot(front) < 0) { |
1750 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1681 return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); |
1751 } |
1682 } |
1752 |
1683 |
1801 */ |
1730 */ |
1802 int32 CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1731 int32 CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1803 { |
1732 { |
1804 CargoID new_cid = GB(p2, 0, 8); |
1733 CargoID new_cid = GB(p2, 0, 8); |
1805 byte new_subtype = GB(p2, 8, 8); |
1734 byte new_subtype = GB(p2, 8, 8); |
1806 Vehicle *v; |
|
1807 int32 cost; |
|
1808 uint num; |
|
1809 |
1735 |
1810 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1736 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1811 |
1737 |
1812 v = GetVehicle(p1); |
1738 Vehicle *v = GetVehicle(p1); |
1813 |
1739 |
1814 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1740 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1815 if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED); |
1741 if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED); |
1816 |
1742 |
1817 /* Check cargo */ |
1743 /* Check cargo */ |
1818 if (new_cid > NUM_CARGO) return CMD_ERROR; |
1744 if (new_cid > NUM_CARGO) return CMD_ERROR; |
1819 |
1745 |
1820 SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN); |
1746 SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN); |
1821 |
1747 |
1822 cost = 0; |
1748 int32 cost = 0; |
1823 num = 0; |
1749 uint num = 0; |
1824 |
1750 |
1825 do { |
1751 do { |
1826 /* XXX: We also refit all the attached wagons en-masse if they |
1752 /* XXX: We also refit all the attached wagons en-masse if they |
1827 * can be refitted. This is how TTDPatch does it. TODO: Have |
1753 * can be refitted. This is how TTDPatch does it. TODO: Have |
1828 * some nice [Refit] button near each wagon. --pasky */ |
1754 * some nice [Refit] button near each wagon. --pasky */ |
1829 if (!CanRefitTo(v->engine_type, new_cid)) continue; |
1755 if (!CanRefitTo(v->engine_type, new_cid)) continue; |
1830 |
1756 |
1831 if (v->cargo_cap != 0) { |
1757 if (v->cargo_cap != 0) { |
1832 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); |
|
1833 uint16 amount = CALLBACK_FAILED; |
1758 uint16 amount = CALLBACK_FAILED; |
1834 |
1759 |
1835 if (HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_REFIT_CAPACITY)) { |
1760 if (HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_REFIT_CAPACITY)) { |
1836 /* Back up the vehicle's cargo type */ |
1761 /* Back up the vehicle's cargo type */ |
1837 CargoID temp_cid = v->cargo_type; |
1762 CargoID temp_cid = v->cargo_type; |
1844 v->cargo_type = temp_cid; |
1769 v->cargo_type = temp_cid; |
1845 v->cargo_subtype = temp_subtype; |
1770 v->cargo_subtype = temp_subtype; |
1846 } |
1771 } |
1847 |
1772 |
1848 if (amount == CALLBACK_FAILED) { // callback failed or not used, use default |
1773 if (amount == CALLBACK_FAILED) { // callback failed or not used, use default |
|
1774 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); |
1849 CargoID old_cid = rvi->cargo_type; |
1775 CargoID old_cid = rvi->cargo_type; |
1850 /* normally, the capacity depends on the cargo type, a rail vehicle can |
1776 /* normally, the capacity depends on the cargo type, a rail vehicle can |
1851 * carry twice as much mail/goods as normal cargo, and four times as |
1777 * carry twice as much mail/goods as normal cargo, and four times as |
1852 * many passengers |
1778 * many passengers |
1853 */ |
1779 */ |
1920 |
1846 |
1921 // returns the tile of a depot to goto to. The given vehicle must not be |
1847 // returns the tile of a depot to goto to. The given vehicle must not be |
1922 // crashed! |
1848 // crashed! |
1923 static TrainFindDepotData FindClosestTrainDepot(Vehicle *v, int max_distance) |
1849 static TrainFindDepotData FindClosestTrainDepot(Vehicle *v, int max_distance) |
1924 { |
1850 { |
|
1851 assert(!(v->vehstatus & VS_CRASHED)); |
|
1852 |
1925 TrainFindDepotData tfdd; |
1853 TrainFindDepotData tfdd; |
1926 TileIndex tile = v->tile; |
|
1927 |
|
1928 assert(!(v->vehstatus & VS_CRASHED)); |
|
1929 |
|
1930 tfdd.owner = v->owner; |
1854 tfdd.owner = v->owner; |
1931 tfdd.best_length = (uint)-1; |
1855 tfdd.best_length = (uint)-1; |
1932 tfdd.reverse = false; |
1856 tfdd.reverse = false; |
1933 |
1857 |
1934 if (IsTileDepotType(tile, TRANSPORT_RAIL)){ |
1858 TileIndex tile = v->tile; |
|
1859 if (IsTileDepotType(tile, TRANSPORT_RAIL)) { |
1935 tfdd.tile = tile; |
1860 tfdd.tile = tile; |
1936 tfdd.best_length = 0; |
1861 tfdd.best_length = 0; |
1937 return tfdd; |
1862 return tfdd; |
1938 } |
1863 } |
1939 |
1864 |
1940 if (_patches.yapf.rail_use_yapf) { |
1865 if (_patches.yapf.rail_use_yapf) { |
1941 bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse); |
1866 bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse); |
1942 tfdd.best_length = found ? max_distance / 2 : -1; // some fake distance or NOT_FOUND |
1867 tfdd.best_length = found ? max_distance / 2 : -1; // some fake distance or NOT_FOUND |
1943 } else if (_patches.new_pathfinding_all) { |
1868 } else if (_patches.new_pathfinding_all) { |
1944 NPFFoundTargetData ftd; |
|
1945 Vehicle* last = GetLastVehicleInChain(v); |
1869 Vehicle* last = GetLastVehicleInChain(v); |
1946 Trackdir trackdir = GetVehicleTrackdir(v); |
1870 Trackdir trackdir = GetVehicleTrackdir(v); |
1947 Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last)); |
1871 Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last)); |
1948 |
1872 |
1949 assert (trackdir != INVALID_TRACKDIR); |
1873 assert(trackdir != INVALID_TRACKDIR); |
1950 ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, last->tile, trackdir_rev, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY); |
1874 NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, last->tile, trackdir_rev, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY); |
1951 if (ftd.best_bird_dist == 0) { |
1875 if (ftd.best_bird_dist == 0) { |
1952 /* Found target */ |
1876 /* Found target */ |
1953 tfdd.tile = ftd.node.tile; |
1877 tfdd.tile = ftd.node.tile; |
1954 /* Our caller expects a number of tiles, so we just approximate that |
1878 /* Our caller expects a number of tiles, so we just approximate that |
1955 * number by this. It might not be completely what we want, but it will |
1879 * number by this. It might not be completely what we want, but it will |
1958 tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH; |
1882 tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH; |
1959 if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true; |
1883 if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true; |
1960 } |
1884 } |
1961 } else { |
1885 } else { |
1962 // search in the forward direction first. |
1886 // search in the forward direction first. |
1963 DiagDirection i; |
1887 DiagDirection i = DirToDiagDir(v->direction); |
1964 |
|
1965 i = DirToDiagDir(v->direction); |
|
1966 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { |
1888 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { |
1967 i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT); |
1889 i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT); |
1968 } |
1890 } |
1969 NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); |
1891 NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); |
1970 if (tfdd.best_length == (uint)-1){ |
1892 if (tfdd.best_length == (uint)-1){ |
1988 * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h) |
1910 * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h) |
1989 * - p2 bit 8-10 - VLW flag (for mass goto depot) |
1911 * - p2 bit 8-10 - VLW flag (for mass goto depot) |
1990 */ |
1912 */ |
1991 int32 CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1913 int32 CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1992 { |
1914 { |
1993 Vehicle *v; |
|
1994 TrainFindDepotData tfdd; |
|
1995 |
|
1996 if (p2 & DEPOT_MASS_SEND) { |
1915 if (p2 & DEPOT_MASS_SEND) { |
1997 /* Mass goto depot requested */ |
1916 /* Mass goto depot requested */ |
1998 if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR; |
1917 if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR; |
1999 return SendAllVehiclesToDepot(VEH_Train, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1); |
1918 return SendAllVehiclesToDepot(VEH_Train, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1); |
2000 } |
1919 } |
2001 |
1920 |
2002 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1921 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
2003 |
1922 |
2004 v = GetVehicle(p1); |
1923 Vehicle *v = GetVehicle(p1); |
2005 |
1924 |
2006 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1925 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
2007 |
1926 |
2008 if (v->vehstatus & VS_CRASHED) return CMD_ERROR; |
1927 if (v->vehstatus & VS_CRASHED) return CMD_ERROR; |
2009 |
1928 |
2035 |
1954 |
2036 /* check if at a standstill (not stopped only) in a depot |
1955 /* check if at a standstill (not stopped only) in a depot |
2037 * the check is down here to make it possible to alter stop/service for trains entering the depot */ |
1956 * the check is down here to make it possible to alter stop/service for trains entering the depot */ |
2038 if (IsTileDepotType(v->tile, TRANSPORT_RAIL) && v->cur_speed == 0) return CMD_ERROR; |
1957 if (IsTileDepotType(v->tile, TRANSPORT_RAIL) && v->cur_speed == 0) return CMD_ERROR; |
2039 |
1958 |
2040 tfdd = FindClosestTrainDepot(v, 0); |
1959 TrainFindDepotData tfdd = FindClosestTrainDepot(v, 0); |
2041 if (tfdd.best_length == (uint)-1) return_cmd_error(STR_883A_UNABLE_TO_FIND_ROUTE_TO); |
1960 if (tfdd.best_length == (uint)-1) return_cmd_error(STR_883A_UNABLE_TO_FIND_ROUTE_TO); |
2042 |
1961 |
2043 if (flags & DC_EXEC) { |
1962 if (flags & DC_EXEC) { |
2044 v->dest_tile = tfdd.tile; |
1963 v->dest_tile = tfdd.tile; |
2045 v->current_order.type = OT_GOTO_DEPOT; |
1964 v->current_order.type = OT_GOTO_DEPOT; |
2066 1, 1, 1, 0, -1, -1, -1, 0 |
1985 1, 1, 1, 0, -1, -1, -1, 0 |
2067 }; |
1986 }; |
2068 |
1987 |
2069 static void HandleLocomotiveSmokeCloud(const Vehicle* v) |
1988 static void HandleLocomotiveSmokeCloud(const Vehicle* v) |
2070 { |
1989 { |
2071 const Vehicle* u; |
|
2072 bool sound = false; |
1990 bool sound = false; |
2073 |
1991 |
2074 if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2) |
1992 if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2) |
2075 return; |
1993 return; |
2076 |
1994 |
2077 u = v; |
1995 const Vehicle* u = v; |
2078 |
1996 |
2079 do { |
1997 do { |
2080 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); |
1998 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); |
2081 int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8; |
1999 int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8; |
2082 byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2); |
2000 byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2); |
2083 bool disable_effect = HASBIT(v->u.rail.cached_vis_effect, 6); |
2001 bool disable_effect = HASBIT(v->u.rail.cached_vis_effect, 6); |
2084 int x, y; |
|
2085 |
2002 |
2086 // no smoke? |
2003 // no smoke? |
2087 if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) || |
2004 if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) || |
2088 disable_effect || |
2005 disable_effect || |
2089 rvi->railtype > RAILTYPE_ELECTRIC || |
2006 rvi->railtype > RAILTYPE_ELECTRIC || |
2293 static const byte _pick_track_table[6] = {1, 3, 2, 2, 0, 0}; |
2205 static const byte _pick_track_table[6] = {1, 3, 2, 2, 0, 0}; |
2294 |
2206 |
2295 /* choose a track */ |
2207 /* choose a track */ |
2296 static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks) |
2208 static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks) |
2297 { |
2209 { |
2298 TrainTrackFollowerData fd; |
|
2299 Track best_track; |
2210 Track best_track; |
2300 // pathfinders are able to tell that route was only 'guessed' |
2211 // pathfinders are able to tell that route was only 'guessed' |
2301 bool path_not_found = false; |
2212 bool path_not_found = false; |
2302 |
2213 |
2303 #ifdef PF_BENCHMARK |
2214 #ifdef PF_BENCHMARK |
2316 } else { |
2227 } else { |
2317 best_track = FindFirstTrack(tracks); |
2228 best_track = FindFirstTrack(tracks); |
2318 } |
2229 } |
2319 } else if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */ |
2230 } else if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */ |
2320 void* perf = NpfBeginInterval(); |
2231 void* perf = NpfBeginInterval(); |
2321 int time = 0; |
|
2322 |
2232 |
2323 NPFFindStationOrTileData fstd; |
2233 NPFFindStationOrTileData fstd; |
2324 NPFFoundTargetData ftd; |
|
2325 Trackdir trackdir; |
|
2326 |
|
2327 NPFFillWithOrderData(&fstd, v); |
2234 NPFFillWithOrderData(&fstd, v); |
2328 /* The enterdir for the new tile, is the exitdir for the old tile */ |
2235 /* The enterdir for the new tile, is the exitdir for the old tile */ |
2329 trackdir = GetVehicleTrackdir(v); |
2236 Trackdir trackdir = GetVehicleTrackdir(v); |
2330 assert(trackdir != 0xff); |
2237 assert(trackdir != 0xff); |
2331 |
2238 |
2332 ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes); |
2239 NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.compatible_railtypes); |
2333 |
2240 |
2334 if (ftd.best_trackdir == 0xff) { |
2241 if (ftd.best_trackdir == 0xff) { |
2335 /* We are already at our target. Just do something */ |
2242 /* We are already at our target. Just do something */ |
2336 //TODO: maybe display error? |
2243 //TODO: maybe display error? |
2337 //TODO: go straight ahead if possible? |
2244 //TODO: go straight ahead if possible? |
2344 if (ftd.best_bird_dist != 0) path_not_found = true; |
2251 if (ftd.best_bird_dist != 0) path_not_found = true; |
2345 /* Discard enterdir information, making it a normal track */ |
2252 /* Discard enterdir information, making it a normal track */ |
2346 best_track = TrackdirToTrack(ftd.best_trackdir); |
2253 best_track = TrackdirToTrack(ftd.best_trackdir); |
2347 } |
2254 } |
2348 |
2255 |
2349 time = NpfEndInterval(perf); |
2256 int time = NpfEndInterval(perf); |
2350 DEBUG(yapf, 4, "[NPFT] %d us - %d rounds - %d open - %d closed -- ", time, 0, _aystar_stats_open_size, _aystar_stats_closed_size); |
2257 DEBUG(yapf, 4, "[NPFT] %d us - %d rounds - %d open - %d closed -- ", time, 0, _aystar_stats_open_size, _aystar_stats_closed_size); |
2351 } else { |
2258 } else { |
2352 void* perf = NpfBeginInterval(); |
2259 void* perf = NpfBeginInterval(); |
2353 int time = 0; |
2260 |
2354 |
2261 TrainTrackFollowerData fd; |
2355 FillWithStationData(&fd, v); |
2262 FillWithStationData(&fd, v); |
2356 |
2263 |
2357 /* New train pathfinding */ |
2264 /* New train pathfinding */ |
2358 fd.best_bird_dist = (uint)-1; |
2265 fd.best_bird_dist = (uint)-1; |
2359 fd.best_track_dist = (uint)-1; |
2266 fd.best_track_dist = (uint)-1; |
2370 best_track = FindFirstTrack(tracks); |
2277 best_track = FindFirstTrack(tracks); |
2371 } else { |
2278 } else { |
2372 best_track = TrackdirToTrack(fd.best_track); |
2279 best_track = TrackdirToTrack(fd.best_track); |
2373 } |
2280 } |
2374 |
2281 |
2375 time = NpfEndInterval(perf); |
2282 int time = NpfEndInterval(perf); |
2376 DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0); |
2283 DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0); |
2377 } |
2284 } |
2378 // handle "path not found" state |
2285 // handle "path not found" state |
2379 if (path_not_found) { |
2286 if (path_not_found) { |
2380 // PF didn't find the route |
2287 // PF didn't find the route |
2408 } |
2315 } |
2409 |
2316 |
2410 |
2317 |
2411 static bool CheckReverseTrain(Vehicle *v) |
2318 static bool CheckReverseTrain(Vehicle *v) |
2412 { |
2319 { |
2413 TrainTrackFollowerData fd; |
|
2414 int i, r; |
|
2415 int best_track; |
|
2416 uint best_bird_dist = 0; |
|
2417 uint best_track_dist = 0; |
|
2418 uint reverse, reverse_best; |
|
2419 |
|
2420 if (_opt.diff.line_reverse_mode != 0 || |
2320 if (_opt.diff.line_reverse_mode != 0 || |
2421 v->u.rail.track == TRACK_BIT_DEPOT || v->u.rail.track == TRACK_BIT_WORMHOLE || |
2321 v->u.rail.track == TRACK_BIT_DEPOT || v->u.rail.track == TRACK_BIT_WORMHOLE || |
2422 !(v->direction & 1)) |
2322 !(v->direction & 1)) |
2423 return false; |
2323 return false; |
2424 |
2324 |
|
2325 TrainTrackFollowerData fd; |
2425 FillWithStationData(&fd, v); |
2326 FillWithStationData(&fd, v); |
2426 |
2327 |
2427 best_track = -1; |
2328 uint reverse_best = 0; |
2428 reverse_best = reverse = 0; |
|
2429 |
2329 |
2430 assert(v->u.rail.track); |
2330 assert(v->u.rail.track); |
2431 |
2331 |
2432 i = _search_directions[FIND_FIRST_BIT(v->u.rail.track)][DirToDiagDir(v->direction)]; |
2332 int i = _search_directions[FIND_FIRST_BIT(v->u.rail.track)][DirToDiagDir(v->direction)]; |
2433 |
2333 |
2434 if (_patches.yapf.rail_use_yapf) { |
2334 if (_patches.yapf.rail_use_yapf) { |
2435 reverse_best = YapfCheckReverseTrain(v); |
2335 reverse_best = YapfCheckReverseTrain(v); |
2436 } else if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */ |
2336 } else if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */ |
2437 NPFFindStationOrTileData fstd; |
2337 NPFFindStationOrTileData fstd; |
2682 return (spd >> 8); |
2584 return (spd >> 8); |
2683 } |
2585 } |
2684 |
2586 |
2685 static void TrainEnterStation(Vehicle *v, StationID station) |
2587 static void TrainEnterStation(Vehicle *v, StationID station) |
2686 { |
2588 { |
2687 Station *st; |
|
2688 uint32 flags; |
|
2689 |
|
2690 v->last_station_visited = station; |
2589 v->last_station_visited = station; |
2691 |
2590 |
2692 /* check if a train ever visited this station before */ |
2591 /* check if a train ever visited this station before */ |
2693 st = GetStation(station); |
2592 Station *st = GetStation(station); |
2694 if (!(st->had_vehicle_of_type & HVOT_TRAIN)) { |
2593 if (!(st->had_vehicle_of_type & HVOT_TRAIN)) { |
2695 st->had_vehicle_of_type |= HVOT_TRAIN; |
2594 st->had_vehicle_of_type |= HVOT_TRAIN; |
2696 SetDParam(0, st->index); |
2595 SetDParam(0, st->index); |
2697 flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0); |
2596 uint32 flags = v->owner == _local_player ? |
|
2597 NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : |
|
2598 NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ARRIVAL_OTHER, 0); |
2698 AddNewsItem( |
2599 AddNewsItem( |
2699 STR_8801_CITIZENS_CELEBRATE_FIRST, |
2600 STR_8801_CITIZENS_CELEBRATE_FIRST, |
2700 flags, |
2601 flags, |
2701 v->index, |
2602 v->index, |
2702 0 |
2603 0 |
2728 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2629 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2729 } |
2630 } |
2730 |
2631 |
2731 static byte AfterSetTrainPos(Vehicle *v, bool new_tile) |
2632 static byte AfterSetTrainPos(Vehicle *v, bool new_tile) |
2732 { |
2633 { |
2733 byte new_z, old_z; |
|
2734 |
|
2735 // need this hint so it returns the right z coordinate on bridges. |
2634 // need this hint so it returns the right z coordinate on bridges. |
2736 new_z = GetSlopeZ(v->x_pos, v->y_pos); |
2635 byte new_z = GetSlopeZ(v->x_pos, v->y_pos); |
2737 |
2636 |
2738 old_z = v->z_pos; |
2637 byte old_z = v->z_pos; |
2739 v->z_pos = new_z; |
2638 v->z_pos = new_z; |
2740 |
2639 |
2741 if (new_tile) { |
2640 if (new_tile) { |
2742 CLRBIT(v->u.rail.flags, VRF_GOINGUP); |
2641 CLRBIT(v->u.rail.flags, VRF_GOINGUP); |
2743 CLRBIT(v->u.rail.flags, VRF_GOINGDOWN); |
2642 CLRBIT(v->u.rail.flags, VRF_GOINGDOWN); |
2828 }; |
2727 }; |
2829 |
2728 |
2830 /* Modify the speed of the vehicle due to a turn */ |
2729 /* Modify the speed of the vehicle due to a turn */ |
2831 static void AffectSpeedByDirChange(Vehicle* v, Direction new_dir) |
2730 static void AffectSpeedByDirChange(Vehicle* v, Direction new_dir) |
2832 { |
2731 { |
2833 DirDiff diff; |
|
2834 const RailtypeSlowdownParams *rsp; |
|
2835 |
|
2836 if (_patches.realistic_acceleration) return; |
2732 if (_patches.realistic_acceleration) return; |
2837 |
2733 |
2838 diff = DirDifference(v->direction, new_dir); |
2734 DirDiff diff = DirDifference(v->direction, new_dir); |
2839 if (diff == DIRDIFF_SAME) return; |
2735 if (diff == DIRDIFF_SAME) return; |
2840 |
2736 |
2841 rsp = &_railtype_slowdown[v->u.rail.railtype]; |
2737 const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype]; |
2842 v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8; |
2738 v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8; |
2843 } |
2739 } |
2844 |
2740 |
2845 /* Modify the speed of the vehicle due to a change in altitude */ |
2741 /* Modify the speed of the vehicle due to a change in altitude */ |
2846 static void AffectSpeedByZChange(Vehicle *v, byte old_z) |
2742 static void AffectSpeedByZChange(Vehicle *v, byte old_z) |
2847 { |
2743 { |
2848 const RailtypeSlowdownParams *rsp; |
|
2849 if (old_z == v->z_pos || _patches.realistic_acceleration) return; |
2744 if (old_z == v->z_pos || _patches.realistic_acceleration) return; |
2850 |
2745 |
2851 rsp = &_railtype_slowdown[v->u.rail.railtype]; |
2746 const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype]; |
2852 |
2747 |
2853 if (old_z < v->z_pos) { |
2748 if (old_z < v->z_pos) { |
2854 v->cur_speed -= (v->cur_speed * rsp->z_up >> 8); |
2749 v->cur_speed -= (v->cur_speed * rsp->z_up >> 8); |
2855 } else { |
2750 } else { |
2856 uint16 spd = v->cur_speed + rsp->z_down; |
2751 uint16 spd = v->cur_speed + rsp->z_down; |
2926 * Reports the incident in a flashy news item, modifies station ratings and |
2819 * Reports the incident in a flashy news item, modifies station ratings and |
2927 * plays a sound. |
2820 * plays a sound. |
2928 */ |
2821 */ |
2929 static void CheckTrainCollision(Vehicle *v) |
2822 static void CheckTrainCollision(Vehicle *v) |
2930 { |
2823 { |
2931 TrainCollideChecker tcc; |
|
2932 Vehicle *coll; |
|
2933 Vehicle *realcoll; |
|
2934 uint num; |
|
2935 |
|
2936 /* can't collide in depot */ |
2824 /* can't collide in depot */ |
2937 if (v->u.rail.track == TRACK_BIT_DEPOT) return; |
2825 if (v->u.rail.track == TRACK_BIT_DEPOT) return; |
2938 |
2826 |
2939 assert(v->u.rail.track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile); |
2827 assert(v->u.rail.track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile); |
2940 |
2828 |
|
2829 TrainCollideChecker tcc; |
2941 tcc.v = v; |
2830 tcc.v = v; |
2942 tcc.v_skip = v->next; |
2831 tcc.v_skip = v->next; |
2943 |
2832 |
2944 /* find colliding vehicle */ |
2833 /* find colliding vehicle */ |
2945 realcoll = (Vehicle*)VehicleFromPos(TileVirtXY(v->x_pos, v->y_pos), &tcc, FindTrainCollideEnum); |
2834 Vehicle *realcoll = (Vehicle*)VehicleFromPos(TileVirtXY(v->x_pos, v->y_pos), &tcc, FindTrainCollideEnum); |
2946 if (realcoll == NULL) return; |
2835 if (realcoll == NULL) return; |
2947 |
2836 |
2948 coll = GetFirstVehicleInChain(realcoll); |
2837 Vehicle *coll = GetFirstVehicleInChain(realcoll); |
2949 |
2838 |
2950 /* it can't collide with its own wagons */ |
2839 /* it can't collide with its own wagons */ |
2951 if (v == coll || |
2840 if (v == coll || |
2952 (v->u.rail.track == TRACK_BIT_WORMHOLE && (v->direction & 2) != (realcoll->direction & 2))) |
2841 (v->u.rail.track == TRACK_BIT_WORMHOLE && (v->direction & 2) != (realcoll->direction & 2))) |
2953 return; |
2842 return; |
2954 |
2843 |
2955 //two drivers + passangers killed in train v |
2844 //two drivers + passangers killed in train v |
2956 num = 2 + CountPassengersInTrain(v); |
2845 uint num = 2 + CountPassengersInTrain(v); |
2957 if (!(coll->vehstatus & VS_CRASHED)) |
2846 if (!(coll->vehstatus & VS_CRASHED)) |
2958 //two drivers + passangers killed in train coll (if it was not crashed already) |
2847 //two drivers + passangers killed in train coll (if it was not crashed already) |
2959 num += 2 + CountPassengersInTrain(coll); |
2848 num += 2 + CountPassengersInTrain(coll); |
2960 |
2849 |
2961 SetVehicleCrashed(v); |
2850 SetVehicleCrashed(v); |
2991 |
2880 |
2992 static void TrainController(Vehicle *v, bool update_image) |
2881 static void TrainController(Vehicle *v, bool update_image) |
2993 { |
2882 { |
2994 Vehicle *prev; |
2883 Vehicle *prev; |
2995 GetNewVehiclePosResult gp; |
2884 GetNewVehiclePosResult gp; |
2996 uint32 r, tracks, ts; |
2885 uint32 ts; |
2997 Trackdir i; |
|
2998 DiagDirection enterdir; |
2886 DiagDirection enterdir; |
2999 Direction dir; |
2887 Direction dir; |
3000 Direction newdir; |
|
3001 Direction chosen_dir; |
|
3002 TrackBits chosen_track; |
|
3003 byte old_z; |
|
3004 |
2888 |
3005 /* For every vehicle after and including the given vehicle */ |
2889 /* For every vehicle after and including the given vehicle */ |
3006 for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) { |
2890 for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) { |
3007 BeginVehicleMove(v); |
2891 BeginVehicleMove(v); |
3008 |
2892 |
3017 } else { |
2901 } else { |
3018 /* Not inside depot */ |
2902 /* Not inside depot */ |
3019 |
2903 |
3020 if (IsFrontEngine(v) && !TrainCheckIfLineEnds(v)) return; |
2904 if (IsFrontEngine(v) && !TrainCheckIfLineEnds(v)) return; |
3021 |
2905 |
3022 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
2906 uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
3023 if (HASBIT(r, VETS_CANNOT_ENTER)) { |
2907 if (HASBIT(r, VETS_CANNOT_ENTER)) { |
3024 goto invalid_rail; |
2908 goto invalid_rail; |
3025 } |
2909 } |
3026 if (HASBIT(r, VETS_ENTERED_STATION)) { |
2910 if (HASBIT(r, VETS_ENTERED_STATION)) { |
3027 TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET); |
2911 TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET); |
3048 ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL) & _reachable_tracks[enterdir]; |
2932 ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL) & _reachable_tracks[enterdir]; |
3049 |
2933 |
3050 /* Combine the from & to directions. |
2934 /* Combine the from & to directions. |
3051 * Now, the lower byte contains the track status, and the byte at bit 16 contains |
2935 * Now, the lower byte contains the track status, and the byte at bit 16 contains |
3052 * the signal status. */ |
2936 * the signal status. */ |
3053 tracks = ts | (ts >> 8); |
2937 uint32 tracks = ts | (ts >> 8); |
3054 bits = (TrackBits)(tracks & TRACK_BIT_MASK); |
2938 bits = (TrackBits)(tracks & TRACK_BIT_MASK); |
3055 if ((_patches.new_pathfinding_all || _patches.yapf.rail_use_yapf) && _patches.forbid_90_deg && prev == NULL) { |
2939 if ((_patches.new_pathfinding_all || _patches.yapf.rail_use_yapf) && _patches.forbid_90_deg && prev == NULL) { |
3056 /* We allow wagons to make 90 deg turns, because forbid_90_deg |
2940 /* We allow wagons to make 90 deg turns, because forbid_90_deg |
3057 * can be switched on halfway a turn */ |
2941 * can be switched on halfway a turn */ |
3058 bits &= ~TrackCrossesTracks(FindFirstTrack(v->u.rail.track)); |
2942 bits &= ~TrackCrossesTracks(FindFirstTrack(v->u.rail.track)); |
3062 |
2946 |
3063 /* Check if the new tile contrains tracks that are compatible |
2947 /* Check if the new tile contrains tracks that are compatible |
3064 * with the current train, if not, bail out. */ |
2948 * with the current train, if not, bail out. */ |
3065 if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail; |
2949 if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail; |
3066 |
2950 |
|
2951 TrackBits chosen_track; |
3067 if (prev == NULL) { |
2952 if (prev == NULL) { |
3068 /* Currently the locomotive is active. Determine which one of the |
2953 /* Currently the locomotive is active. Determine which one of the |
3069 * available tracks to choose */ |
2954 * available tracks to choose */ |
3070 chosen_track = 1 << ChooseTrainTrack(v, gp.new_tile, enterdir, bits); |
2955 chosen_track = 1 << ChooseTrainTrack(v, gp.new_tile, enterdir, bits); |
3071 assert(chosen_track & tracks); |
2956 assert(chosen_track & tracks); |
3089 chosen_track == TRACK_BIT_X || chosen_track == TRACK_BIT_Y || |
2974 chosen_track == TRACK_BIT_X || chosen_track == TRACK_BIT_Y || |
3090 chosen_track == TRACK_BIT_UPPER || chosen_track == TRACK_BIT_LOWER || |
2975 chosen_track == TRACK_BIT_UPPER || chosen_track == TRACK_BIT_LOWER || |
3091 chosen_track == TRACK_BIT_LEFT || chosen_track == TRACK_BIT_RIGHT); |
2976 chosen_track == TRACK_BIT_LEFT || chosen_track == TRACK_BIT_RIGHT); |
3092 |
2977 |
3093 /* Update XY to reflect the entrance to the new tile, and select the direction to use */ |
2978 /* Update XY to reflect the entrance to the new tile, and select the direction to use */ |
3094 { |
2979 const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir]; |
3095 const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir]; |
2980 gp.x = (gp.x & ~0xF) | b[0]; |
3096 gp.x = (gp.x & ~0xF) | b[0]; |
2981 gp.y = (gp.y & ~0xF) | b[1]; |
3097 gp.y = (gp.y & ~0xF) | b[1]; |
2982 Direction chosen_dir = (Direction)b[2]; |
3098 chosen_dir = (Direction)b[2]; |
|
3099 } |
|
3100 |
2983 |
3101 /* Call the landscape function and tell it that the vehicle entered the tile */ |
2984 /* Call the landscape function and tell it that the vehicle entered the tile */ |
3102 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
2985 uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
3103 if (HASBIT(r, VETS_CANNOT_ENTER)) { |
2986 if (HASBIT(r, VETS_CANNOT_ENTER)) { |
3104 goto invalid_rail; |
2987 goto invalid_rail; |
3105 } |
2988 } |
3106 |
2989 |
3107 if (IsLevelCrossingTile(v->tile) && v->next == NULL) { |
2990 if (IsLevelCrossingTile(v->tile) && v->next == NULL) { |
3149 continue; |
3032 continue; |
3150 } |
3033 } |
3151 } |
3034 } |
3152 |
3035 |
3153 /* update image of train, as well as delta XY */ |
3036 /* update image of train, as well as delta XY */ |
3154 newdir = GetNewVehicleDirection(v, gp.x, gp.y); |
3037 Direction newdir = GetNewVehicleDirection(v, gp.x, gp.y); |
3155 UpdateTrainDeltaXY(v, newdir); |
3038 UpdateTrainDeltaXY(v, newdir); |
3156 if (update_image) v->cur_image = GetTrainImage(v, newdir); |
3039 if (update_image) v->cur_image = GetTrainImage(v, newdir); |
3157 |
3040 |
3158 v->x_pos = gp.x; |
3041 v->x_pos = gp.x; |
3159 v->y_pos = gp.y; |
3042 v->y_pos = gp.y; |
3160 |
3043 |
3161 /* update the Z position of the vehicle */ |
3044 /* update the Z position of the vehicle */ |
3162 old_z = AfterSetTrainPos(v, (gp.new_tile != gp.old_tile)); |
3045 byte old_z = AfterSetTrainPos(v, (gp.new_tile != gp.old_tile)); |
3163 |
3046 |
3164 if (prev == NULL) { |
3047 if (prev == NULL) { |
3165 /* This is the first vehicle in the train */ |
3048 /* This is the first vehicle in the train */ |
3166 AffectSpeedByZChange(v, old_z); |
3049 AffectSpeedByZChange(v, old_z); |
3167 } |
3050 } |
3216 * or inside a tunnel, recalculate the signals as they might need updating |
3099 * or inside a tunnel, recalculate the signals as they might need updating |
3217 * @param v the @Vehicle of which last wagon is to be removed |
3100 * @param v the @Vehicle of which last wagon is to be removed |
3218 */ |
3101 */ |
3219 static void DeleteLastWagon(Vehicle *v) |
3102 static void DeleteLastWagon(Vehicle *v) |
3220 { |
3103 { |
3221 Vehicle *u = v; |
|
3222 |
|
3223 /* Go to the last wagon and delete the link pointing there |
3104 /* Go to the last wagon and delete the link pointing there |
3224 * *u is then the one-before-last wagon, and *v the last |
3105 * *u is then the one-before-last wagon, and *v the last |
3225 * one which will physicially be removed */ |
3106 * one which will physicially be removed */ |
|
3107 Vehicle *u = v; |
3226 for (; v->next != NULL; v = v->next) u = v; |
3108 for (; v->next != NULL; v = v->next) u = v; |
3227 u->next = NULL; |
3109 u->next = NULL; |
3228 |
3110 |
3229 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
3111 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
3230 DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
3112 DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
3288 } |
3170 } |
3289 |
3171 |
3290 static void HandleCrashedTrain(Vehicle *v) |
3172 static void HandleCrashedTrain(Vehicle *v) |
3291 { |
3173 { |
3292 int state = ++v->u.rail.crash_anim_pos; |
3174 int state = ++v->u.rail.crash_anim_pos; |
3293 uint32 r; |
|
3294 Vehicle *u; |
|
3295 |
3175 |
3296 if (state == 4 && !(v->vehstatus & VS_HIDDEN)) { |
3176 if (state == 4 && !(v->vehstatus & VS_HIDDEN)) { |
3297 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE); |
3177 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE); |
3298 } |
3178 } |
3299 |
3179 |
|
3180 uint32 r; |
3300 if (state <= 200 && CHANCE16R(1, 7, r)) { |
3181 if (state <= 200 && CHANCE16R(1, 7, r)) { |
3301 int index = (r * 10 >> 16); |
3182 int index = (r * 10 >> 16); |
3302 |
3183 |
3303 u = v; |
3184 Vehicle *u = v; |
3304 do { |
3185 do { |
3305 if (--index < 0) { |
3186 if (--index < 0) { |
3306 r = Random(); |
3187 r = Random(); |
3307 |
3188 |
3308 CreateEffectVehicleRel(u, |
3189 CreateEffectVehicleRel(u, |
3357 225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15 |
3238 225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15 |
3358 }; |
3239 }; |
3359 |
3240 |
3360 static bool TrainCheckIfLineEnds(Vehicle *v) |
3241 static bool TrainCheckIfLineEnds(Vehicle *v) |
3361 { |
3242 { |
3362 TileIndex tile; |
3243 int t = v->breakdown_ctr; |
3363 uint x,y; |
|
3364 uint16 break_speed; |
|
3365 DiagDirection dir; |
|
3366 int t; |
|
3367 uint32 ts; |
|
3368 |
|
3369 t = v->breakdown_ctr; |
|
3370 if (t > 1) { |
3244 if (t > 1) { |
3371 v->vehstatus |= VS_TRAIN_SLOWING; |
3245 v->vehstatus |= VS_TRAIN_SLOWING; |
3372 |
3246 |
3373 break_speed = _breakdown_speeds[GB(~t, 4, 4)]; |
3247 uint16 break_speed = _breakdown_speeds[GB(~t, 4, 4)]; |
3374 if (break_speed < v->cur_speed) v->cur_speed = break_speed; |
3248 if (break_speed < v->cur_speed) v->cur_speed = break_speed; |
3375 } else { |
3249 } else { |
3376 v->vehstatus &= ~VS_TRAIN_SLOWING; |
3250 v->vehstatus &= ~VS_TRAIN_SLOWING; |
3377 } |
3251 } |
3378 |
3252 |
3379 if (v->u.rail.track == TRACK_BIT_WORMHOLE) return true; // exit if inside a tunnel |
3253 if (v->u.rail.track == TRACK_BIT_WORMHOLE) return true; // exit if inside a tunnel |
3380 if (v->u.rail.track == TRACK_BIT_DEPOT) return true; // exit if inside a depot |
3254 if (v->u.rail.track == TRACK_BIT_DEPOT) return true; // exit if inside a depot |
3381 |
3255 |
3382 tile = v->tile; |
3256 TileIndex tile = v->tile; |
3383 |
3257 |
3384 if (IsTileType(tile, MP_TUNNELBRIDGE)) { |
3258 if (IsTileType(tile, MP_TUNNELBRIDGE)) { |
3385 DiagDirection dir; |
3259 DiagDirection dir = IsTunnel(tile) ? GetTunnelDirection(tile) : GetBridgeRampDirection(tile); |
3386 |
|
3387 dir = IsTunnel(tile) ? GetTunnelDirection(tile) : GetBridgeRampDirection(tile); |
|
3388 if (DiagDirToDir(dir) == v->direction) return true; |
3260 if (DiagDirToDir(dir) == v->direction) return true; |
3389 } |
3261 } |
3390 |
3262 |
3391 // depot? |
3263 // depot? |
3392 /* XXX -- When enabled, this makes it possible to crash trains of others |
3264 /* XXX -- When enabled, this makes it possible to crash trains of others |
3393 (by building a depot right against a station) */ |
3265 (by building a depot right against a station) */ |
3394 /* if (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == RAIL_TILE_DEPOT_WAYPOINT) |
3266 /* if (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == RAIL_TILE_DEPOT_WAYPOINT) |
3395 return true;*/ |
3267 return true;*/ |
3396 |
3268 |
3397 /* Determine the non-diagonal direction in which we will exit this tile */ |
3269 /* Determine the non-diagonal direction in which we will exit this tile */ |
3398 dir = DirToDiagDir(v->direction); |
3270 DiagDirection dir = DirToDiagDir(v->direction); |
3399 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[dir]) { |
3271 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[dir]) { |
3400 dir = ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT); |
3272 dir = ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT); |
3401 } |
3273 } |
3402 /* Calculate next tile */ |
3274 /* Calculate next tile */ |
3403 tile += TileOffsByDiagDir(dir); |
3275 tile += TileOffsByDiagDir(dir); |
3404 // determine the track status on the next tile. |
3276 // determine the track status on the next tile. |
3405 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _reachable_tracks[dir]; |
3277 uint32 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _reachable_tracks[dir]; |
3406 |
3278 |
3407 /* Calc position within the current tile ?? */ |
3279 /* Calc position within the current tile ?? */ |
3408 x = v->x_pos & 0xF; |
3280 uint x = v->x_pos & 0xF; |
3409 y = v->y_pos & 0xF; |
3281 uint y = v->y_pos & 0xF; |
3410 |
3282 |
3411 switch (v->direction) { |
3283 switch (v->direction) { |
3412 case DIR_N : x = ~x + ~y + 24; break; |
3284 case DIR_N : x = ~x + ~y + 24; break; |
3413 case DIR_NW: x = y; /* FALLTHROUGH */ |
3285 case DIR_NW: x = y; /* FALLTHROUGH */ |
3414 case DIR_NE: x = ~x + 16; break; |
3286 case DIR_NE: x = ~x + 16; break; |
3559 if (CheckTrainIsInsideDepot(v)) { |
3426 if (CheckTrainIsInsideDepot(v)) { |
3560 VehicleServiceInDepot(v); |
3427 VehicleServiceInDepot(v); |
3561 return; |
3428 return; |
3562 } |
3429 } |
3563 |
3430 |
3564 tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST); |
3431 TrainFindDepotData tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST); |
3565 /* Only go to the depot if it is not too far out of our way. */ |
3432 /* Only go to the depot if it is not too far out of our way. */ |
3566 if (tfdd.best_length == (uint)-1 || tfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) { |
3433 if (tfdd.best_length == (uint)-1 || tfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) { |
3567 if (v->current_order.type == OT_GOTO_DEPOT) { |
3434 if (v->current_order.type == OT_GOTO_DEPOT) { |
3568 /* If we were already heading for a depot but it has |
3435 /* If we were already heading for a depot but it has |
3569 * suddenly moved farther away, we continue our normal |
3436 * suddenly moved farther away, we continue our normal |
3695 /* we got a rear car without a front car. We will convert it to a front one */ |
3559 /* we got a rear car without a front car. We will convert it to a front one */ |
3696 SetTrainEngine(u); |
3560 SetTrainEngine(u); |
3697 u->spritenum--; |
3561 u->spritenum--; |
3698 } |
3562 } |
3699 |
3563 |
3700 { |
3564 Vehicle *w; |
3701 Vehicle *w; |
3565 for (w = u->next; w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w)); |
3702 |
3566 if (w != NULL) { |
3703 for (w = u->next; w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w)); |
3567 /* we found a car to partner with this engine. Now we will make sure it face the right way */ |
3704 if (w != NULL) { |
3568 if (IsTrainEngine(w)) { |
3705 /* we found a car to partner with this engine. Now we will make sure it face the right way */ |
3569 ClearTrainEngine(w); |
3706 if (IsTrainEngine(w)) { |
3570 w->spritenum++; |
3707 ClearTrainEngine(w); |
|
3708 w->spritenum++; |
|
3709 } |
|
3710 } |
3571 } |
3711 |
3572 w->u.rail.other_multiheaded_part = u; |
3712 if (w != NULL) { |
3573 u->u.rail.other_multiheaded_part = w; |
3713 w->u.rail.other_multiheaded_part = u; |
3574 } else { |
3714 u->u.rail.other_multiheaded_part = w; |
3575 /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */ |
3715 } else { |
3576 ClearMultiheaded(u); |
3716 /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */ |
|
3717 ClearMultiheaded(u); |
|
3718 } |
|
3719 } |
3577 } |
3720 } |
3578 } |
3721 } END_ENUM_WAGONS(u) |
3579 } END_ENUM_WAGONS(u) |
3722 } |
3580 } |
3723 } |
3581 } |