branch | NewGRF_ports |
changeset 6872 | 1c4a4a609f85 |
parent 6871 | 5a9dc001e1ad |
child 6877 | 889301acc299 |
6871:5a9dc001e1ad | 6872:1c4a4a609f85 |
---|---|
4 |
4 |
5 #include "stdafx.h" |
5 #include "stdafx.h" |
6 #include "openttd.h" |
6 #include "openttd.h" |
7 #include "bridge_map.h" |
7 #include "bridge_map.h" |
8 #include "debug.h" |
8 #include "debug.h" |
9 #include "functions.h" |
9 #include "tile_cmd.h" |
10 #include "landscape.h" |
10 #include "landscape.h" |
11 #include "gui.h" |
11 #include "gui.h" |
12 #include "station_map.h" |
12 #include "station_map.h" |
13 #include "table/strings.h" |
|
14 #include "strings.h" |
|
15 #include "map.h" |
|
16 #include "tile.h" |
|
17 #include "tunnel_map.h" |
13 #include "tunnel_map.h" |
18 #include "vehicle.h" |
|
19 #include "timetable.h" |
14 #include "timetable.h" |
20 #include "articulated_vehicles.h" |
15 #include "articulated_vehicles.h" |
21 #include "command.h" |
16 #include "command_func.h" |
22 #include "pathfind.h" |
17 #include "pathfind.h" |
23 #include "npf.h" |
18 #include "npf.h" |
24 #include "station.h" |
19 #include "station.h" |
25 #include "table/train_cmd.h" |
|
26 #include "news.h" |
20 #include "news.h" |
27 #include "engine.h" |
21 #include "engine.h" |
28 #include "player.h" |
22 #include "player_func.h" |
29 #include "sound.h" |
23 #include "player_base.h" |
30 #include "depot.h" |
24 #include "depot.h" |
31 #include "waypoint.h" |
25 #include "waypoint.h" |
32 #include "vehicle_gui.h" |
26 #include "vehicle_gui.h" |
33 #include "train.h" |
27 #include "train.h" |
34 #include "bridge.h" |
28 #include "bridge.h" |
35 #include "newgrf_callbacks.h" |
29 #include "newgrf_callbacks.h" |
36 #include "newgrf_engine.h" |
30 #include "newgrf_engine.h" |
37 #include "newgrf_sound.h" |
31 #include "newgrf_sound.h" |
38 #include "newgrf_text.h" |
32 #include "newgrf_text.h" |
39 #include "direction.h" |
33 #include "direction_func.h" |
40 #include "yapf/yapf.h" |
34 #include "yapf/yapf.h" |
41 #include "date.h" |
|
42 #include "cargotype.h" |
35 #include "cargotype.h" |
43 #include "group.h" |
36 #include "group.h" |
44 #include "table/sprites.h" |
37 #include "table/sprites.h" |
38 #include "tunnelbridge_map.h" |
|
39 #include "strings_func.h" |
|
40 #include "functions.h" |
|
41 #include "window_func.h" |
|
42 #include "date_func.h" |
|
43 #include "vehicle_func.h" |
|
44 #include "sound_func.h" |
|
45 #include "signal_func.h" |
|
46 #include "variables.h" |
|
47 #include "autoreplace_gui.h" |
|
48 #include "gfx_func.h" |
|
49 #include "settings_type.h" |
|
50 |
|
51 #include "table/strings.h" |
|
52 #include "table/train_cmd.h" |
|
45 |
53 |
46 static bool TrainCheckIfLineEnds(Vehicle *v); |
54 static bool TrainCheckIfLineEnds(Vehicle *v); |
47 static void TrainController(Vehicle *v, bool update_image); |
55 static void TrainController(Vehicle *v, bool update_image); |
56 static TileIndex TrainApproachingCrossingTile(const Vehicle *v); |
|
48 |
57 |
49 static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8}; |
58 static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8}; |
50 static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10}; |
59 static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10}; |
51 static const TrackBits _state_dir_table[4] = { TRACK_BIT_RIGHT, TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER }; |
60 |
61 |
|
62 /** |
|
63 * Determine the side in which the train will leave the tile |
|
64 * |
|
65 * @param direction vehicle direction |
|
66 * @param track vehicle track bits |
|
67 * @return side of tile the train will leave |
|
68 */ |
|
69 static inline DiagDirection TrainExitDir(Direction direction, TrackBits track) |
|
70 { |
|
71 static const TrackBits state_dir_table[DIAGDIR_END] = { TRACK_BIT_RIGHT, TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER }; |
|
72 |
|
73 DiagDirection diagdir = DirToDiagDir(direction); |
|
74 |
|
75 /* Determine the diagonal direction in which we will exit this tile */ |
|
76 if (!HasBit(direction, 0) && track != state_dir_table[diagdir]) { |
|
77 diagdir = ChangeDiagDir(diagdir, DIAGDIRDIFF_90LEFT); |
|
78 } |
|
79 |
|
80 return diagdir; |
|
81 } |
|
52 |
82 |
53 |
83 |
54 /** Return the cargo weight multiplier to use for a rail vehicle |
84 /** Return the cargo weight multiplier to use for a rail vehicle |
55 * @param cargo Cargo type to get multiplier for |
85 * @param cargo Cargo type to get multiplier for |
56 * @return Cargo weight multiplier |
86 * @return Cargo weight multiplier |
100 if (total_power == 0) v->vehstatus |= VS_STOPPED; |
130 if (total_power == 0) v->vehstatus |= VS_STOPPED; |
101 |
131 |
102 v->u.rail.cached_power = total_power; |
132 v->u.rail.cached_power = total_power; |
103 v->u.rail.cached_max_te = max_te; |
133 v->u.rail.cached_max_te = max_te; |
104 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
134 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
105 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
135 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
106 } |
136 } |
107 } |
137 } |
108 |
138 |
109 |
139 |
110 /** |
140 /** |
158 assert(IsFrontEngine(v) || IsFreeWagon(v)); |
188 assert(IsFrontEngine(v) || IsFreeWagon(v)); |
159 |
189 |
160 const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type); |
190 const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type); |
161 EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE; |
191 EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE; |
162 v->u.rail.cached_total_length = 0; |
192 v->u.rail.cached_total_length = 0; |
163 v->u.rail.compatible_railtypes = 0; |
193 v->u.rail.compatible_railtypes = RAILTYPES_NONE; |
194 |
|
195 bool train_can_tilt = true; |
|
164 |
196 |
165 for (Vehicle *u = v; u != NULL; u = u->Next()) { |
197 for (Vehicle *u = v; u != NULL; u = u->Next()) { |
166 const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); |
198 const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); |
167 |
199 |
168 /* Check the v->first cache. */ |
200 /* Check the v->first cache. */ |
169 assert(u->First() == v); |
201 assert(u->First() == v); |
202 |
|
203 if (!HasBit(EngInfo(u->engine_type)->misc_flags, EF_RAIL_TILTS)) train_can_tilt = false; |
|
170 |
204 |
171 /* update the 'first engine' */ |
205 /* update the 'first engine' */ |
172 u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine; |
206 u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine; |
173 u->u.rail.railtype = rvi_u->railtype; |
207 u->u.rail.railtype = rvi_u->railtype; |
174 |
208 |
219 |
253 |
220 /* Some electric engines can be allowed to run on normal rail. It happens to all |
254 /* Some electric engines can be allowed to run on normal rail. It happens to all |
221 * existing electric engines when elrails are disabled and then re-enabled */ |
255 * existing electric engines when elrails are disabled and then re-enabled */ |
222 if (HasBit(u->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) { |
256 if (HasBit(u->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) { |
223 u->u.rail.railtype = RAILTYPE_RAIL; |
257 u->u.rail.railtype = RAILTYPE_RAIL; |
224 u->u.rail.compatible_railtypes |= (1 << RAILTYPE_RAIL); |
258 u->u.rail.compatible_railtypes |= RAILTYPES_RAIL; |
225 } |
259 } |
226 |
260 |
227 /* max speed is the minimum of the speed limits of all vehicles in the consist */ |
261 /* max speed is the minimum of the speed limits of all vehicles in the consist */ |
228 if ((rvi_u->railveh_type != RAILVEH_WAGON || _patches.wagon_speed_limits) && !UsesWagonOverride(u)) { |
262 if ((rvi_u->railveh_type != RAILVEH_WAGON || _patches.wagon_speed_limits) && !UsesWagonOverride(u)) { |
229 uint16 speed = GetVehicleProperty(u, 0x09, rvi_u->max_speed); |
263 uint16 speed = GetVehicleProperty(u, 0x09, rvi_u->max_speed); |
249 v->u.rail.cached_total_length += u->u.rail.cached_veh_length; |
283 v->u.rail.cached_total_length += u->u.rail.cached_veh_length; |
250 } |
284 } |
251 |
285 |
252 /* store consist weight/max speed in cache */ |
286 /* store consist weight/max speed in cache */ |
253 v->u.rail.cached_max_speed = max_speed; |
287 v->u.rail.cached_max_speed = max_speed; |
288 v->u.rail.cached_tilt = train_can_tilt; |
|
254 |
289 |
255 /* 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) */ |
290 /* recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) */ |
256 TrainCargoChanged(v); |
291 TrainCargoChanged(v); |
257 } |
292 } |
258 |
|
259 /* These two arrays are used for realistic acceleration. XXX: How should they |
|
260 * be interpreted? */ |
|
261 static const byte _curve_neighbours45[8][2] = { |
|
262 {7, 1}, |
|
263 {0, 2}, |
|
264 {1, 3}, |
|
265 {2, 4}, |
|
266 {3, 5}, |
|
267 {4, 6}, |
|
268 {5, 7}, |
|
269 {6, 0}, |
|
270 }; |
|
271 |
|
272 static const byte _curve_neighbours90[8][2] = { |
|
273 {6, 2}, |
|
274 {7, 3}, |
|
275 {0, 4}, |
|
276 {1, 5}, |
|
277 {2, 6}, |
|
278 {3, 7}, |
|
279 {4, 0}, |
|
280 {5, 1}, |
|
281 }; |
|
282 |
293 |
283 enum AccelType { |
294 enum AccelType { |
284 AM_ACCEL, |
295 AM_ACCEL, |
285 AM_BRAKE |
296 AM_BRAKE |
286 }; |
297 }; |
291 StationID sid = GetStationIndex(tile); |
302 StationID sid = GetStationIndex(tile); |
292 |
303 |
293 assert(v->type == VEH_TRAIN); |
304 assert(v->type == VEH_TRAIN); |
294 /* When does a train drive through a station |
305 /* When does a train drive through a station |
295 * first we deal with the "new nonstop handling" */ |
306 * first we deal with the "new nonstop handling" */ |
296 if (_patches.new_nonstop && o->flags & OF_NON_STOP && sid == o->dest) { |
307 if (_patches.new_nonstop && o->flags & OFB_NON_STOP && sid == o->dest) { |
297 return false; |
308 return false; |
298 } |
309 } |
299 |
310 |
300 if (v->last_station_visited == sid) return false; |
311 if (v->last_station_visited == sid) return false; |
301 |
312 |
302 if (sid != o->dest && (o->flags & OF_NON_STOP || _patches.new_nonstop)) { |
313 if (sid != o->dest && (o->flags & OFB_NON_STOP || _patches.new_nonstop)) { |
303 return false; |
314 return false; |
304 } |
315 } |
305 |
316 |
306 return true; |
317 return true; |
307 } |
318 } |
308 |
319 |
309 /** new acceleration*/ |
320 /** new acceleration*/ |
310 static int GetTrainAcceleration(Vehicle *v, bool mode) |
321 static int GetTrainAcceleration(Vehicle *v, bool mode) |
311 { |
322 { |
312 int max_speed = 2000; |
323 static const int absolute_max_speed = 2000; |
324 int max_speed = absolute_max_speed; |
|
313 int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h |
325 int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h |
314 int curvecount[2] = {0, 0}; |
326 int curvecount[2] = {0, 0}; |
315 |
327 |
316 /*first find the curve speed limit */ |
328 /*first find the curve speed limit */ |
317 int numcurve = 0; |
329 int numcurve = 0; |
318 int sum = 0; |
330 int sum = 0; |
319 int pos = 0; |
331 int pos = 0; |
320 int lastpos = -1; |
332 int lastpos = -1; |
321 for (const Vehicle *u = v; u->Next() != NULL; u = u->Next(), pos++) { |
333 for (const Vehicle *u = v; u->Next() != NULL; u = u->Next(), pos++) { |
322 Direction dir = u->direction; |
334 Direction this_dir = u->direction; |
323 Direction ndir = u->Next()->direction; |
335 Direction next_dir = u->Next()->direction; |
324 int i; |
336 |
325 |
337 DirDiff dirdiff = DirDifference(this_dir, next_dir); |
326 for (i = 0; i < 2; i++) { |
338 if (dirdiff == DIRDIFF_SAME) continue; |
327 if ( _curve_neighbours45[dir][i] == ndir) { |
339 |
328 curvecount[i]++; |
340 if (dirdiff == DIRDIFF_45LEFT) curvecount[0]++; |
329 if (lastpos != -1) { |
341 if (dirdiff == DIRDIFF_45RIGHT) curvecount[1]++; |
330 numcurve++; |
342 if (dirdiff == DIRDIFF_45LEFT || dirdiff == DIRDIFF_45RIGHT) { |
331 sum += pos - lastpos; |
343 if (lastpos != -1) { |
332 if (pos - lastpos == 1) { |
344 numcurve++; |
333 max_speed = 88; |
345 sum += pos - lastpos; |
334 } |
346 if (pos - lastpos == 1) { |
347 max_speed = 88; |
|
335 } |
348 } |
336 lastpos = pos; |
349 } |
337 } |
350 lastpos = pos; |
338 } |
351 } |
339 |
352 |
340 /*if we have a 90 degree turn, fix the speed limit to 60 */ |
353 /*if we have a 90 degree turn, fix the speed limit to 60 */ |
341 if (_curve_neighbours90[dir][0] == ndir || |
354 if (dirdiff == DIRDIFF_90LEFT || dirdiff == DIRDIFF_90RIGHT) { |
342 _curve_neighbours90[dir][1] == ndir) { |
|
343 max_speed = 61; |
355 max_speed = 61; |
344 } |
356 } |
345 } |
357 } |
346 |
|
347 if (numcurve > 0) sum /= numcurve; |
|
348 |
358 |
349 if ((curvecount[0] != 0 || curvecount[1] != 0) && max_speed > 88) { |
359 if ((curvecount[0] != 0 || curvecount[1] != 0) && max_speed > 88) { |
350 int total = curvecount[0] + curvecount[1]; |
360 int total = curvecount[0] + curvecount[1]; |
351 |
361 |
352 if (curvecount[0] == 1 && curvecount[1] == 1) { |
362 if (curvecount[0] == 1 && curvecount[1] == 1) { |
353 max_speed = 0xFFFF; |
363 max_speed = absolute_max_speed; |
354 } else if (total > 1) { |
364 } else if (total > 1) { |
365 if (numcurve > 0) sum /= numcurve; |
|
355 max_speed = 232 - (13 - Clamp(sum, 1, 12)) * (13 - Clamp(sum, 1, 12)); |
366 max_speed = 232 - (13 - Clamp(sum, 1, 12)) * (13 - Clamp(sum, 1, 12)); |
356 } |
367 } |
357 } |
368 } |
358 |
369 |
359 max_speed += (max_speed / 2) * v->u.rail.railtype; |
370 if (max_speed != absolute_max_speed) { |
371 /* Apply the engine's rail type curve speed advantage, if it slowed by curves */ |
|
372 const RailtypeInfo *rti = GetRailTypeInfo(v->u.rail.railtype); |
|
373 max_speed += (max_speed / 2) * rti->curve_speed; |
|
374 |
|
375 if (v->u.rail.cached_tilt) { |
|
376 /* Apply max_speed bonus of 20% for a tilting train */ |
|
377 max_speed += max_speed / 5; |
|
378 } |
|
379 } |
|
360 |
380 |
361 if (IsTileType(v->tile, MP_STATION) && IsFrontEngine(v)) { |
381 if (IsTileType(v->tile, MP_STATION) && IsFrontEngine(v)) { |
362 if (TrainShouldStop(v, v->tile)) { |
382 if (TrainShouldStop(v, v->tile)) { |
363 int station_length = GetStationByTile(v->tile)->GetPlatformLength(v->tile, DirToDiagDir(v->direction)); |
383 int station_length = GetStationByTile(v->tile)->GetPlatformLength(v->tile, DirToDiagDir(v->direction)); |
364 int delta_v; |
384 |
365 |
385 int st_max_speed = 120; |
366 max_speed = 120; |
386 |
367 |
387 int delta_v = v->cur_speed / (station_length + 1); |
368 delta_v = v->cur_speed / (station_length + 1); |
388 if (v->max_speed > (v->cur_speed - delta_v)) { |
369 if (v->max_speed > (v->cur_speed - delta_v)) |
389 st_max_speed = v->cur_speed - (delta_v / 10); |
370 max_speed = v->cur_speed - (delta_v / 10); |
390 } |
371 |
391 |
372 max_speed = max(max_speed, 25 * station_length); |
392 st_max_speed = max(st_max_speed, 25 * station_length); |
393 max_speed = min(max_speed, st_max_speed); |
|
373 } |
394 } |
374 } |
395 } |
375 |
396 |
376 int mass = v->u.rail.cached_weight; |
397 int mass = v->u.rail.cached_weight; |
377 int power = v->u.rail.cached_power * 746; |
398 int power = v->u.rail.cached_power * 746; |
466 if (HasBit(this->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction); |
487 if (HasBit(this->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction); |
467 |
488 |
468 if (is_custom_sprite(img)) { |
489 if (is_custom_sprite(img)) { |
469 base = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img))); |
490 base = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img))); |
470 if (base != 0) return base; |
491 if (base != 0) return base; |
471 img = orig_rail_vehicle_info[this->engine_type].image_index; |
492 img = _orig_rail_vehicle_info[this->engine_type].image_index; |
472 } |
493 } |
473 |
494 |
474 base = _engine_sprite_base[img] + ((direction + _engine_sprite_add[img]) & _engine_sprite_and[img]); |
495 base = _engine_sprite_base[img] + ((direction + _engine_sprite_add[img]) & _engine_sprite_and[img]); |
475 |
496 |
476 if (this->cargo.Count() >= this->cargo_cap / 2U) base += _wagon_full_adder[img]; |
497 if (this->cargo.Count() >= this->cargo_cap / 2U) base += _wagon_full_adder[img]; |
485 SpriteID image = 0; |
506 SpriteID image = 0; |
486 |
507 |
487 if (is_custom_sprite(img)) { |
508 if (is_custom_sprite(img)) { |
488 image = GetCustomVehicleIcon(engine, DIR_W); |
509 image = GetCustomVehicleIcon(engine, DIR_W); |
489 if (image == 0) { |
510 if (image == 0) { |
490 img = orig_rail_vehicle_info[engine].image_index; |
511 img = _orig_rail_vehicle_info[engine].image_index; |
491 } else { |
512 } else { |
492 y += _traininfo_vehicle_pitch; |
513 y += _traininfo_vehicle_pitch; |
493 } |
514 } |
494 } |
515 } |
495 if (image == 0) { |
516 if (image == 0) { |
500 DrawSprite(image, pal, x - 14, y); |
521 DrawSprite(image, pal, x - 14, y); |
501 x += 15; |
522 x += 15; |
502 image = 0; |
523 image = 0; |
503 if (is_custom_sprite(img)) { |
524 if (is_custom_sprite(img)) { |
504 image = GetCustomVehicleIcon(engine, DIR_E); |
525 image = GetCustomVehicleIcon(engine, DIR_E); |
505 if (image == 0) img = orig_rail_vehicle_info[engine].image_index; |
526 if (image == 0) img = _orig_rail_vehicle_info[engine].image_index; |
506 } |
527 } |
507 if (image == 0) { |
528 if (image == 0) { |
508 image = |
529 image = |
509 ((6 + _engine_sprite_add[img + 1]) & _engine_sprite_and[img + 1]) + |
530 ((6 + _engine_sprite_add[img + 1]) & _engine_sprite_and[img + 1]) + |
510 _engine_sprite_base[img + 1]; |
531 _engine_sprite_base[img + 1]; |
513 DrawSprite(image, pal, x, y); |
534 DrawSprite(image, pal, x, y); |
514 } |
535 } |
515 |
536 |
516 static CommandCost CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags) |
537 static CommandCost CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags) |
517 { |
538 { |
518 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
519 |
|
520 const RailVehicleInfo *rvi = RailVehInfo(engine); |
539 const RailVehicleInfo *rvi = RailVehInfo(engine); |
521 CommandCost value((GetEngineProperty(engine, 0x17, rvi->base_cost) * _price.build_railwagon) >> 8); |
540 CommandCost value(EXPENSES_NEW_VEHICLES, (GetEngineProperty(engine, 0x17, rvi->base_cost) * _price.build_railwagon) >> 8); |
522 |
541 |
523 uint num_vehicles = 1 + CountArticulatedParts(engine, false); |
542 uint num_vehicles = 1 + CountArticulatedParts(engine, false); |
524 |
543 |
525 if (!(flags & DC_QUERY_COST)) { |
544 if (!(flags & DC_QUERY_COST)) { |
526 /* Allow for the wagon and the articulated parts, plus one to "terminate" the list. */ |
545 /* Allow for the wagon and the articulated parts, plus one to "terminate" the list. */ |
602 } |
621 } |
603 GetPlayer(_current_player)->num_engines[engine]++; |
622 GetPlayer(_current_player)->num_engines[engine]++; |
604 } |
623 } |
605 } |
624 } |
606 |
625 |
607 return CommandCost(value); |
626 return value; |
608 } |
627 } |
609 |
628 |
610 /** Move all free vehicles in the depot to the train */ |
629 /** Move all free vehicles in the depot to the train */ |
611 static void NormalizeTrainVehInDepot(const Vehicle* u) |
630 static void NormalizeTrainVehInDepot(const Vehicle* u) |
612 { |
631 { |
623 } |
642 } |
624 } |
643 } |
625 |
644 |
626 static CommandCost EstimateTrainCost(EngineID engine, const RailVehicleInfo* rvi) |
645 static CommandCost EstimateTrainCost(EngineID engine, const RailVehicleInfo* rvi) |
627 { |
646 { |
628 return CommandCost(GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5); |
647 return CommandCost(EXPENSES_NEW_VEHICLES, GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5); |
629 } |
648 } |
630 |
649 |
631 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building) |
650 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building) |
632 { |
651 { |
633 u = new (u) Train(); |
652 u = new (u) Train(); |
673 if (!(flags & DC_QUERY_COST)) { |
692 if (!(flags & DC_QUERY_COST)) { |
674 if (!IsTileDepotType(tile, TRANSPORT_RAIL)) return CMD_ERROR; |
693 if (!IsTileDepotType(tile, TRANSPORT_RAIL)) return CMD_ERROR; |
675 if (!IsTileOwner(tile, _current_player)) return CMD_ERROR; |
694 if (!IsTileOwner(tile, _current_player)) return CMD_ERROR; |
676 } |
695 } |
677 |
696 |
678 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
679 |
|
680 const RailVehicleInfo *rvi = RailVehInfo(p1); |
697 const RailVehicleInfo *rvi = RailVehInfo(p1); |
681 |
698 |
682 /* Check if depot and new engine uses the same kind of tracks */ |
699 /* Check if depot and new engine uses the same kind of tracks */ |
683 /* We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */ |
700 /* We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */ |
684 if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; |
701 if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; |
734 const Engine *e = GetEngine(p1); |
751 const Engine *e = GetEngine(p1); |
735 v->reliability = e->reliability; |
752 v->reliability = e->reliability; |
736 v->reliability_spd_dec = e->reliability_spd_dec; |
753 v->reliability_spd_dec = e->reliability_spd_dec; |
737 v->max_age = e->lifelength * 366; |
754 v->max_age = e->lifelength * 366; |
738 |
755 |
739 v->string_id = STR_SV_TRAIN_NAME; |
756 v->name = NULL; |
740 v->u.rail.railtype = rvi->railtype; |
757 v->u.rail.railtype = rvi->railtype; |
741 _new_vehicle_id = v->index; |
758 _new_vehicle_id = v->index; |
742 |
759 |
743 v->service_interval = _patches.servint_trains; |
760 v->service_interval = _patches.servint_trains; |
744 v->date_of_last_service = _date; |
761 v->date_of_last_service = _date; |
883 { |
900 { |
884 UnlinkWagon(v, v->First()); |
901 UnlinkWagon(v, v->First()); |
885 if (dest == NULL) return; |
902 if (dest == NULL) return; |
886 |
903 |
887 Vehicle *next = dest->Next(); |
904 Vehicle *next = dest->Next(); |
905 v->SetNext(NULL); |
|
888 dest->SetNext(v); |
906 dest->SetNext(v); |
889 v->SetNext(next); |
907 v->SetNext(next); |
890 ClearFreeWagon(v); |
908 ClearFreeWagon(v); |
891 ClearFrontEngine(v); |
909 ClearFrontEngine(v); |
892 } |
910 } |
1022 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
1040 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
1023 |
1041 |
1024 if (flags & DC_EXEC) src->unitnumber = unit_num; |
1042 if (flags & DC_EXEC) src->unitnumber = unit_num; |
1025 } |
1043 } |
1026 |
1044 |
1027 if (dst_head != NULL) { |
1045 /* |
1028 /* Check NewGRF Callback 0x1D */ |
1046 * Check whether the vehicles in the source chain are in the destination |
1029 uint16 callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, dst_head->engine_type, src, dst_head); |
1047 * chain. This can easily be done by checking whether the first vehicle |
1030 if (callback != CALLBACK_FAILED) { |
1048 * of the source chain is in the destination chain as the Next/Previous |
1031 if (callback == 0xFD) return_cmd_error(STR_INCOMPATIBLE_RAIL_TYPES); |
1049 * pointers always make a doubly linked list of it where the assumption |
1032 if (callback < 0xFD) { |
1050 * v->Next()->Previous() == v holds (assuming v->Next() != NULL). |
1033 StringID error = GetGRFStringID(GetEngineGRFID(dst_head->engine_type), 0xD000 + callback); |
1051 */ |
1034 return_cmd_error(error); |
1052 bool src_in_dst = false; |
1035 } |
1053 for (Vehicle *v = dst_head; !src_in_dst && v != NULL; v = v->Next()) src_in_dst = v == src; |
1036 } |
1054 |
1055 /* |
|
1056 * If the source chain is in the destination chain then the user is |
|
1057 * only reordering the vehicles, thus not attaching a new vehicle. |
|
1058 * Therefor the 'allow wagon attach' callback does not need to be |
|
1059 * called. If it would be called strange things would happen because |
|
1060 * one 'attaches' an already 'attached' vehicle causing more trouble |
|
1061 * than it actually solves (infinite loops and such). |
|
1062 */ |
|
1063 if (dst_head != NULL && !src_in_dst) { |
|
1064 /* |
|
1065 * When performing the 'allow wagon attach' callback, we have to check |
|
1066 * that for each and every wagon, not only the first one. This means |
|
1067 * that we have to test one wagon, attach it to the train and then test |
|
1068 * the next wagon till we have reached the end. We have to restore it |
|
1069 * to the state it was before we 'tried' attaching the train when the |
|
1070 * attaching fails or succeeds because we are not 'only' doing this |
|
1071 * in the DC_EXEC state. |
|
1072 */ |
|
1073 Vehicle *dst_tail = dst_head; |
|
1074 while (dst_tail->Next() != NULL) dst_tail = dst_tail->Next(); |
|
1075 |
|
1076 Vehicle *orig_tail = dst_tail; |
|
1077 Vehicle *next_to_attach = src; |
|
1078 Vehicle *src_previous = src->Previous(); |
|
1079 |
|
1080 while (next_to_attach != NULL) { |
|
1081 /* Back up and clear the first_engine data to avoid using wagon override group */ |
|
1082 EngineID first_engine = next_to_attach->u.rail.first_engine; |
|
1083 next_to_attach->u.rail.first_engine = INVALID_ENGINE; |
|
1084 |
|
1085 uint16 callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, dst_head->engine_type, next_to_attach, dst_head); |
|
1086 |
|
1087 /* Restore original first_engine data */ |
|
1088 next_to_attach->u.rail.first_engine = first_engine; |
|
1089 |
|
1090 if (callback != CALLBACK_FAILED) { |
|
1091 StringID error = STR_NULL; |
|
1092 |
|
1093 if (callback == 0xFD) error = STR_INCOMPATIBLE_RAIL_TYPES; |
|
1094 if (callback < 0xFD) error = GetGRFStringID(GetEngineGRFID(dst_head->engine_type), 0xD000 + callback); |
|
1095 |
|
1096 if (error != STR_NULL) { |
|
1097 /* |
|
1098 * The attaching is not allowed. In this case 'next_to_attach' |
|
1099 * can contain some vehicles of the 'source' and the destination |
|
1100 * train can have some too. We 'just' add the to-be added wagons |
|
1101 * to the chain and then split it where it was previously |
|
1102 * separated, i.e. the tail of the original destination train. |
|
1103 * Furthermore the 'previous' link of the original source vehicle needs |
|
1104 * to be restored, otherwise the train goes missing in the depot. |
|
1105 */ |
|
1106 dst_tail->SetNext(next_to_attach); |
|
1107 orig_tail->SetNext(NULL); |
|
1108 if (src_previous != NULL) src_previous->SetNext(src); |
|
1109 |
|
1110 return_cmd_error(error); |
|
1111 } |
|
1112 } |
|
1113 |
|
1114 /* Only check further wagons if told to move the chain */ |
|
1115 if (!HasBit(p2, 0)) break; |
|
1116 |
|
1117 /* |
|
1118 * Adding a next wagon to the chain so we can test the other wagons. |
|
1119 * First 'take' the first wagon from 'next_to_attach' and move it |
|
1120 * to the next wagon. Then add that to the tail of the destination |
|
1121 * train and update the tail with the new vehicle. |
|
1122 */ |
|
1123 Vehicle *to_add = next_to_attach; |
|
1124 next_to_attach = next_to_attach->Next(); |
|
1125 |
|
1126 to_add->SetNext(NULL); |
|
1127 dst_tail->SetNext(to_add); |
|
1128 dst_tail = dst_tail->Next(); |
|
1129 } |
|
1130 |
|
1131 /* |
|
1132 * When we reach this the attaching is allowed. It also means that the |
|
1133 * chain of vehicles to attach is empty, so we do not need to merge that. |
|
1134 * This means only the splitting needs to be done. |
|
1135 * Furthermore the 'previous' link of the original source vehicle needs |
|
1136 * to be restored, otherwise the train goes missing in the depot. |
|
1137 */ |
|
1138 orig_tail->SetNext(NULL); |
|
1139 if (src_previous != NULL) src_previous->SetNext(src); |
|
1037 } |
1140 } |
1038 |
1141 |
1039 /* do it? */ |
1142 /* do it? */ |
1040 if (flags & DC_EXEC) { |
1143 if (flags & DC_EXEC) { |
1041 /* If we move the front Engine and if the second vehicle is not an engine |
1144 /* If we move the front Engine and if the second vehicle is not an engine |
1142 if (IsFrontEngine(src_head)) { |
1245 if (IsFrontEngine(src_head)) { |
1143 UpdateTrainAcceleration(src_head); |
1246 UpdateTrainAcceleration(src_head); |
1144 InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index); |
1247 InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index); |
1145 /* Update the refit button and window */ |
1248 /* Update the refit button and window */ |
1146 InvalidateWindow(WC_VEHICLE_REFIT, src_head->index); |
1249 InvalidateWindow(WC_VEHICLE_REFIT, src_head->index); |
1147 InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, 12); |
1250 InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, VVW_WIDGET_REFIT_VEH); |
1148 } |
1251 } |
1149 /* Update the depot window */ |
1252 /* Update the depot window */ |
1150 InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile); |
1253 InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile); |
1151 } |
1254 } |
1152 |
1255 |
1156 UpdateTrainGroupID(dst_head); |
1259 UpdateTrainGroupID(dst_head); |
1157 if (IsFrontEngine(dst_head)) { |
1260 if (IsFrontEngine(dst_head)) { |
1158 UpdateTrainAcceleration(dst_head); |
1261 UpdateTrainAcceleration(dst_head); |
1159 InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index); |
1262 InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index); |
1160 /* Update the refit button and window */ |
1263 /* Update the refit button and window */ |
1161 InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, 12); |
1264 InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, VVW_WIDGET_REFIT_VEH); |
1162 InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index); |
1265 InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index); |
1163 } |
1266 } |
1164 /* Update the depot window */ |
1267 /* Update the depot window */ |
1165 InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile); |
1268 InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile); |
1166 } |
1269 } |
1199 if (v->vehstatus & VS_STOPPED && v->u.rail.track == TRACK_BIT_DEPOT) { |
1302 if (v->vehstatus & VS_STOPPED && v->u.rail.track == TRACK_BIT_DEPOT) { |
1200 DeleteVehicleNews(p1, STR_8814_TRAIN_IS_WAITING_IN_DEPOT); |
1303 DeleteVehicleNews(p1, STR_8814_TRAIN_IS_WAITING_IN_DEPOT); |
1201 } |
1304 } |
1202 |
1305 |
1203 v->vehstatus ^= VS_STOPPED; |
1306 v->vehstatus ^= VS_STOPPED; |
1204 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
1307 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
1205 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
1308 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
1206 } |
1309 } |
1207 return CommandCost(); |
1310 return CommandCost(); |
1208 } |
1311 } |
1209 |
1312 |
1229 |
1332 |
1230 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1333 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1231 |
1334 |
1232 if (HASBITS(v->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE); |
1335 if (HASBITS(v->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE); |
1233 |
1336 |
1234 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
1235 |
|
1236 while (IsArticulatedPart(v)) v = v->Previous(); |
1337 while (IsArticulatedPart(v)) v = v->Previous(); |
1237 Vehicle *first = v->First(); |
1338 Vehicle *first = v->First(); |
1238 |
1339 |
1239 /* make sure the vehicle is stopped in the depot */ |
1340 /* make sure the vehicle is stopped in the depot */ |
1240 if (CheckTrainStoppedInDepot(first) < 0) { |
1341 if (CheckTrainStoppedInDepot(first) < 0) { |
1250 } |
1351 } |
1251 InvalidateWindow(WC_VEHICLE_DEPOT, first->tile); |
1352 InvalidateWindow(WC_VEHICLE_DEPOT, first->tile); |
1252 RebuildVehicleLists(); |
1353 RebuildVehicleLists(); |
1253 } |
1354 } |
1254 |
1355 |
1255 CommandCost cost; |
1356 CommandCost cost(EXPENSES_NEW_VEHICLES); |
1256 switch (p2) { |
1357 switch (p2) { |
1257 case 0: case 2: { /* Delete given wagon */ |
1358 case 0: case 2: { /* Delete given wagon */ |
1258 bool switch_engine = false; // update second wagon to engine? |
1359 bool switch_engine = false; // update second wagon to engine? |
1259 byte ori_subtype = v->subtype; // backup subtype of deleted wagon in case DeleteVehicle() changes |
1360 byte ori_subtype = v->subtype; // backup subtype of deleted wagon in case DeleteVehicle() changes |
1260 |
1361 |
1446 { |
1547 { |
1447 int old = v->u.rail.last_speed; |
1548 int old = v->u.rail.last_speed; |
1448 if (spd != old) { |
1549 if (spd != old) { |
1449 v->u.rail.last_speed = spd; |
1550 v->u.rail.last_speed = spd; |
1450 if (_patches.vehicle_speed || (old == 0) != (spd == 0)) |
1551 if (_patches.vehicle_speed || (old == 0) != (spd == 0)) |
1451 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
1552 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
1452 } |
1553 } |
1453 } |
1554 } |
1454 |
1555 |
1455 static void SwapTrainFlags(byte *swap_flag1, byte *swap_flag2) |
1556 static void SwapTrainFlags(byte *swap_flag1, byte *swap_flag2) |
1456 { |
1557 { |
1522 |
1623 |
1523 /* Update train's power incase tiles were different rail type */ |
1624 /* Update train's power incase tiles were different rail type */ |
1524 TrainPowerChanged(v); |
1625 TrainPowerChanged(v); |
1525 } |
1626 } |
1526 |
1627 |
1527 /* Check if the vehicle is a train and is on the tile we are testing */ |
1628 |
1528 static void *TestTrainOnCrossing(Vehicle *v, void *data) |
1629 /** |
1529 { |
1630 * Check if the vehicle is a train |
1530 if (v->tile != *(const TileIndex*)data || v->type != VEH_TRAIN) return NULL; |
1631 * @param v vehicle on tile |
1632 * @return v if it is a train, NULL otherwise |
|
1633 */ |
|
1634 static void *TrainOnTileEnum(Vehicle *v, void *) |
|
1635 { |
|
1636 return (v->type == VEH_TRAIN) ? v : NULL; |
|
1637 } |
|
1638 |
|
1639 |
|
1640 /** |
|
1641 * Checks if a train is approaching a rail-road crossing |
|
1642 * @param v vehicle on tile |
|
1643 * @param data tile with crossing we are testing |
|
1644 * @return v if it is approaching a crossing, NULL otherwise |
|
1645 */ |
|
1646 static void *TrainApproachingCrossingEnum(Vehicle *v, void *data) |
|
1647 { |
|
1648 /* not a train || not front engine || crashed */ |
|
1649 if (v->type != VEH_TRAIN || !IsFrontEngine(v) || v->vehstatus & VS_CRASHED) return NULL; |
|
1650 |
|
1651 TileIndex tile = *(TileIndex*)data; |
|
1652 |
|
1653 if (TrainApproachingCrossingTile(v) != tile) return NULL; |
|
1654 |
|
1531 return v; |
1655 return v; |
1532 } |
1656 } |
1533 |
1657 |
1534 static void DisableTrainCrossing(TileIndex tile) |
1658 |
1535 { |
1659 /** |
1536 if (IsLevelCrossingTile(tile) && |
1660 * Finds a vehicle approaching rail-road crossing |
1537 VehicleFromPos(tile, &tile, TestTrainOnCrossing) == NULL && // empty? |
1661 * @param tile tile to test |
1538 IsCrossingBarred(tile)) { |
1662 * @return pointer to vehicle approaching the crossing |
1539 UnbarCrossing(tile); |
1663 * @pre tile is a rail-road crossing |
1664 */ |
|
1665 static Vehicle *TrainApproachingCrossing(TileIndex tile) |
|
1666 { |
|
1667 assert(IsLevelCrossingTile(tile)); |
|
1668 |
|
1669 DiagDirection dir = AxisToDiagDir(OtherAxis(GetCrossingRoadAxis(tile))); |
|
1670 TileIndex tile_from = tile + TileOffsByDiagDir(dir); |
|
1671 |
|
1672 Vehicle *v = (Vehicle *)VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum); |
|
1673 |
|
1674 if (v != NULL) return v; |
|
1675 |
|
1676 dir = ReverseDiagDir(dir); |
|
1677 tile_from = tile + TileOffsByDiagDir(dir); |
|
1678 |
|
1679 return (Vehicle *)VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum); |
|
1680 } |
|
1681 |
|
1682 |
|
1683 /** |
|
1684 * Sets correct crossing state |
|
1685 * @param tile tile to update |
|
1686 * @param sound should we play sound? |
|
1687 * @pre tile is a rail-road crossing |
|
1688 */ |
|
1689 void UpdateLevelCrossing(TileIndex tile, bool sound) |
|
1690 { |
|
1691 assert(IsLevelCrossingTile(tile)); |
|
1692 |
|
1693 /* train on crossing || train approaching crossing */ |
|
1694 bool new_state = VehicleFromPos(tile, NULL, &TrainOnTileEnum) || TrainApproachingCrossing(tile); |
|
1695 |
|
1696 if (new_state != IsCrossingBarred(tile)) { |
|
1697 if (new_state && sound) { |
|
1698 SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile); |
|
1699 } |
|
1700 SetCrossingBarred(tile, new_state); |
|
1540 MarkTileDirtyByTile(tile); |
1701 MarkTileDirtyByTile(tile); |
1541 } |
1702 } |
1542 } |
1703 } |
1704 |
|
1705 |
|
1706 /** |
|
1707 * Bars crossing and plays ding-ding sound if not barred already |
|
1708 * @param tile tile with crossing |
|
1709 * @pre tile is a rail-road crossing |
|
1710 */ |
|
1711 static inline void MaybeBarCrossingWithSound(TileIndex tile) |
|
1712 { |
|
1713 if (!IsCrossingBarred(tile)) { |
|
1714 BarCrossing(tile); |
|
1715 SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile); |
|
1716 MarkTileDirtyByTile(tile); |
|
1717 } |
|
1718 } |
|
1719 |
|
1543 |
1720 |
1544 /** |
1721 /** |
1545 * Advances wagons for train reversing, needed for variable length wagons. |
1722 * Advances wagons for train reversing, needed for variable length wagons. |
1546 * Needs to be called once before the train is reversed, and once after it. |
1723 * Needs to be called once before the train is reversed, and once after it. |
1547 * @param v First vehicle in chain |
1724 * @param v First vehicle in chain |
1565 if (differential > 0) { |
1742 if (differential > 0) { |
1566 /* disconnect last car to make sure only this subset moves */ |
1743 /* disconnect last car to make sure only this subset moves */ |
1567 Vehicle *tempnext = last->Next(); |
1744 Vehicle *tempnext = last->Next(); |
1568 last->SetNext(NULL); |
1745 last->SetNext(NULL); |
1569 |
1746 |
1747 /* do not update images now because the wagons are disconnected |
|
1748 * and that could cause problems with NewGRFs */ |
|
1570 for (int i = 0; i < differential; i++) TrainController(first, false); |
1749 for (int i = 0; i < differential; i++) TrainController(first, false); |
1571 |
1750 |
1572 last->SetNext(tempnext); |
1751 last->SetNext(tempnext); |
1573 } |
1752 } |
1574 |
1753 |
1584 if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) { |
1763 if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) { |
1585 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
1764 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
1586 } |
1765 } |
1587 |
1766 |
1588 /* Check if we were approaching a rail/road-crossing */ |
1767 /* Check if we were approaching a rail/road-crossing */ |
1589 { |
1768 TileIndex crossing = TrainApproachingCrossingTile(v); |
1590 TileIndex tile = v->tile; |
|
1591 DiagDirection dir = DirToDiagDir(v->direction); |
|
1592 |
|
1593 /* Determine the diagonal direction in which we will exit this tile */ |
|
1594 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[dir]) { |
|
1595 dir = ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT); |
|
1596 } |
|
1597 /* Calculate next tile */ |
|
1598 tile += TileOffsByDiagDir(dir); |
|
1599 |
|
1600 /* Check if the train left a rail/road-crossing */ |
|
1601 DisableTrainCrossing(tile); |
|
1602 } |
|
1603 |
1769 |
1604 /* count number of vehicles */ |
1770 /* count number of vehicles */ |
1605 int r = -1; |
1771 int r = 0; ///< number of vehicles - 1 |
1606 const Vehicle *u = v; |
1772 for (const Vehicle *u = v; (u = u->Next()) != NULL;) { r++; } |
1607 do r++; while ((u = u->Next()) != NULL); |
|
1608 |
1773 |
1609 AdvanceWagons(v, true); |
1774 AdvanceWagons(v, true); |
1610 |
1775 |
1611 /* swap start<>end, start+1<>end-1, ... */ |
1776 /* swap start<>end, start+1<>end-1, ... */ |
1612 int l = 0; |
1777 int l = 0; |
1618 |
1783 |
1619 if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) { |
1784 if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) { |
1620 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
1785 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
1621 } |
1786 } |
1622 |
1787 |
1788 /* update all images */ |
|
1789 for (Vehicle *u = v; u != NULL; u = u->Next()) { u->cur_image = u->GetImage(u->direction); } |
|
1790 |
|
1623 ClrBit(v->u.rail.flags, VRF_REVERSING); |
1791 ClrBit(v->u.rail.flags, VRF_REVERSING); |
1792 |
|
1793 /* update crossing we were approaching */ |
|
1794 if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing); |
|
1795 |
|
1796 /* maybe we are approaching crossing now, after reversal */ |
|
1797 crossing = TrainApproachingCrossingTile(v); |
|
1798 if (crossing != INVALID_TILE) MaybeBarCrossingWithSound(crossing); |
|
1624 } |
1799 } |
1625 |
1800 |
1626 /** Reverse train. |
1801 /** Reverse train. |
1627 * @param tile unused |
1802 * @param tile unused |
1628 * @param flags type of operation |
1803 * @param flags type of operation |
1711 |
1886 |
1712 Vehicle *v = GetVehicle(p1); |
1887 Vehicle *v = GetVehicle(p1); |
1713 |
1888 |
1714 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1889 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1715 if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED); |
1890 if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED); |
1891 if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_CAN_T_REFIT_DESTROYED_VEHICLE); |
|
1716 |
1892 |
1717 /* Check cargo */ |
1893 /* Check cargo */ |
1718 if (new_cid >= NUM_CARGO) return CMD_ERROR; |
1894 if (new_cid >= NUM_CARGO) return CMD_ERROR; |
1719 |
1895 |
1720 SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN); |
1896 CommandCost cost(EXPENSES_TRAIN_RUN); |
1721 |
|
1722 CommandCost cost; |
|
1723 uint num = 0; |
1897 uint num = 0; |
1724 |
1898 |
1725 do { |
1899 do { |
1726 /* XXX: We also refit all the attached wagons en-masse if they |
1900 /* XXX: We also refit all the attached wagons en-masse if they |
1727 * can be refitted. This is how TTDPatch does it. TODO: Have |
1901 * can be refitted. This is how TTDPatch does it. TODO: Have |
1856 tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH; |
2030 tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH; |
1857 if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true; |
2031 if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true; |
1858 } |
2032 } |
1859 } else { |
2033 } else { |
1860 /* search in the forward direction first. */ |
2034 /* search in the forward direction first. */ |
1861 DiagDirection i = DirToDiagDir(v->direction); |
2035 DiagDirection i = TrainExitDir(v->direction, v->u.rail.track); |
1862 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { |
|
1863 i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT); |
|
1864 } |
|
1865 NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); |
2036 NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); |
1866 if (tfdd.best_length == (uint)-1){ |
2037 if (tfdd.best_length == (uint)-1){ |
1867 tfdd.reverse = true; |
2038 tfdd.reverse = true; |
1868 /* search in backwards direction */ |
2039 /* search in backwards direction */ |
1869 i = ReverseDiagDir(DirToDiagDir(v->direction)); |
2040 i = TrainExitDir(ReverseDir(v->direction), v->u.rail.track); |
1870 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { |
|
1871 i = ChangeDiagDir(i, DIAGDIRDIFF_90LEFT); |
|
1872 } |
|
1873 NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); |
2041 NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd); |
1874 } |
2042 } |
1875 } |
2043 } |
1876 |
2044 |
1877 return tfdd; |
2045 return tfdd; |
1900 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
2068 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1901 |
2069 |
1902 if (v->vehstatus & VS_CRASHED) return CMD_ERROR; |
2070 if (v->vehstatus & VS_CRASHED) return CMD_ERROR; |
1903 |
2071 |
1904 if (v->current_order.type == OT_GOTO_DEPOT) { |
2072 if (v->current_order.type == OT_GOTO_DEPOT) { |
1905 if (!!(p2 & DEPOT_SERVICE) == HasBit(v->current_order.flags, OFB_HALT_IN_DEPOT)) { |
2073 if (!!(p2 & DEPOT_SERVICE) == HasBit(v->current_order.flags, OF_HALT_IN_DEPOT)) { |
1906 /* We called with a different DEPOT_SERVICE setting. |
2074 /* We called with a different DEPOT_SERVICE setting. |
1907 * Now we change the setting to apply the new one and let the vehicle head for the same depot. |
2075 * Now we change the setting to apply the new one and let the vehicle head for the same depot. |
1908 * Note: the if is (true for requesting service == true for ordered to stop in depot) */ |
2076 * Note: the if is (true for requesting service == true for ordered to stop in depot) */ |
1909 if (flags & DC_EXEC) { |
2077 if (flags & DC_EXEC) { |
1910 ClrBit(v->current_order.flags, OFB_PART_OF_ORDERS); |
2078 ClrBit(v->current_order.flags, OF_PART_OF_ORDERS); |
1911 ToggleBit(v->current_order.flags, OFB_HALT_IN_DEPOT); |
2079 ToggleBit(v->current_order.flags, OF_HALT_IN_DEPOT); |
1912 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2080 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
1913 } |
2081 } |
1914 return CommandCost(); |
2082 return CommandCost(); |
1915 } |
2083 } |
1916 |
2084 |
1917 if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders |
2085 if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders |
1918 if (flags & DC_EXEC) { |
2086 if (flags & DC_EXEC) { |
1919 if (HasBit(v->current_order.flags, OFB_PART_OF_ORDERS)) { |
2087 if (HasBit(v->current_order.flags, OF_PART_OF_ORDERS)) { |
1920 v->cur_order_index++; |
2088 v->cur_order_index++; |
1921 } |
2089 } |
1922 |
2090 |
1923 v->current_order.type = OT_DUMMY; |
2091 v->current_order.type = OT_DUMMY; |
1924 v->current_order.flags = 0; |
2092 v->current_order.flags = 0; |
1925 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2093 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
1926 } |
2094 } |
1927 return CommandCost(); |
2095 return CommandCost(); |
1928 } |
2096 } |
1929 |
2097 |
1930 /* check if at a standstill (not stopped only) in a depot |
2098 /* check if at a standstill (not stopped only) in a depot |
1937 if (flags & DC_EXEC) { |
2105 if (flags & DC_EXEC) { |
1938 if (v->current_order.type == OT_LOADING) v->LeaveStation(); |
2106 if (v->current_order.type == OT_LOADING) v->LeaveStation(); |
1939 |
2107 |
1940 v->dest_tile = tfdd.tile; |
2108 v->dest_tile = tfdd.tile; |
1941 v->current_order.type = OT_GOTO_DEPOT; |
2109 v->current_order.type = OT_GOTO_DEPOT; |
1942 v->current_order.flags = OF_NON_STOP; |
2110 v->current_order.flags = OFB_NON_STOP; |
1943 if (!(p2 & DEPOT_SERVICE)) SetBit(v->current_order.flags, OFB_HALT_IN_DEPOT); |
2111 if (!(p2 & DEPOT_SERVICE)) SetBit(v->current_order.flags, OF_HALT_IN_DEPOT); |
1944 v->current_order.dest = GetDepotByTile(tfdd.tile)->index; |
2112 v->current_order.dest = GetDepotByTile(tfdd.tile)->index; |
1945 v->current_order.refit_cargo = CT_INVALID; |
2113 v->current_order.refit_cargo = CT_INVALID; |
1946 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2114 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
1947 /* If there is no depot in front, reverse automatically */ |
2115 /* If there is no depot in front, reverse automatically */ |
1948 if (tfdd.reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION); |
2116 if (tfdd.reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION); |
1949 } |
2117 } |
1950 |
2118 |
1951 return CommandCost(); |
2119 return CommandCost(); |
2075 return true; |
2243 return true; |
2076 } |
2244 } |
2077 |
2245 |
2078 v->load_unload_time_rem = 0; |
2246 v->load_unload_time_rem = 0; |
2079 |
2247 |
2080 if (UpdateSignalsOnSegment(v->tile, DirToDiagDir(v->direction))) { |
2248 if (UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner)) { |
2081 InvalidateWindowClasses(WC_TRAINS_LIST); |
2249 InvalidateWindowClasses(WC_TRAINS_LIST); |
2082 return true; |
2250 return true; |
2083 } |
2251 } |
2084 } |
2252 } |
2085 |
2253 |
2094 v->cur_speed = 0; |
2262 v->cur_speed = 0; |
2095 |
2263 |
2096 v->UpdateDeltaXY(v->direction); |
2264 v->UpdateDeltaXY(v->direction); |
2097 v->cur_image = v->GetImage(v->direction); |
2265 v->cur_image = v->GetImage(v->direction); |
2098 VehiclePositionChanged(v); |
2266 VehiclePositionChanged(v); |
2099 UpdateSignalsOnSegment(v->tile, DirToDiagDir(v->direction)); |
2267 UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner); |
2100 UpdateTrainAcceleration(v); |
2268 UpdateTrainAcceleration(v); |
2101 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
2269 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
2102 |
2270 |
2103 return false; |
2271 return false; |
2104 } |
2272 } |
2388 |
2556 |
2389 static bool ProcessTrainOrder(Vehicle *v) |
2557 static bool ProcessTrainOrder(Vehicle *v) |
2390 { |
2558 { |
2391 switch (v->current_order.type) { |
2559 switch (v->current_order.type) { |
2392 case OT_GOTO_DEPOT: |
2560 case OT_GOTO_DEPOT: |
2393 if (!(v->current_order.flags & OF_PART_OF_ORDERS)) return false; |
2561 if (!(v->current_order.flags & OFB_PART_OF_ORDERS)) return false; |
2394 if ((v->current_order.flags & OF_SERVICE_IF_NEEDED) && |
2562 if ((v->current_order.flags & OFB_SERVICE_IF_NEEDED) && |
2395 !VehicleNeedsService(v)) { |
2563 !VehicleNeedsService(v)) { |
2396 UpdateVehicleTimetable(v, true); |
2564 UpdateVehicleTimetable(v, true); |
2397 v->cur_order_index++; |
2565 v->cur_order_index++; |
2398 } |
2566 } |
2399 break; |
2567 break; |
2420 v->cur_order_index++; |
2588 v->cur_order_index++; |
2421 } |
2589 } |
2422 |
2590 |
2423 /* check if we've reached a non-stop station while TTDPatch nonstop is enabled.. */ |
2591 /* check if we've reached a non-stop station while TTDPatch nonstop is enabled.. */ |
2424 if (_patches.new_nonstop && |
2592 if (_patches.new_nonstop && |
2425 v->current_order.flags & OF_NON_STOP && |
2593 v->current_order.flags & OFB_NON_STOP && |
2426 IsTileType(v->tile, MP_STATION) && |
2594 IsTileType(v->tile, MP_STATION) && |
2427 v->current_order.dest == GetStationIndex(v->tile)) { |
2595 v->current_order.dest == GetStationIndex(v->tile)) { |
2428 UpdateVehicleTimetable(v, true); |
2596 UpdateVehicleTimetable(v, true); |
2429 v->cur_order_index++; |
2597 v->cur_order_index++; |
2430 } |
2598 } |
2479 void Train::MarkDirty() |
2647 void Train::MarkDirty() |
2480 { |
2648 { |
2481 Vehicle *v = this; |
2649 Vehicle *v = this; |
2482 do { |
2650 do { |
2483 v->cur_image = v->GetImage(v->direction); |
2651 v->cur_image = v->GetImage(v->direction); |
2484 MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1); |
2652 MarkSingleVehicleDirty(v); |
2485 } while ((v = v->Next()) != NULL); |
2653 } while ((v = v->Next()) != NULL); |
2486 |
2654 |
2487 /* need to update acceleration and cached values since the goods on the train changed. */ |
2655 /* need to update acceleration and cached values since the goods on the train changed. */ |
2488 TrainCargoChanged(this); |
2656 TrainCargoChanged(this); |
2489 UpdateTrainAcceleration(this); |
2657 UpdateTrainAcceleration(this); |
2592 TileX(new_tile) - TileX(old_tile) + 1; |
2760 TileX(new_tile) - TileX(old_tile) + 1; |
2593 assert(offs < 11); |
2761 assert(offs < 11); |
2594 return _new_vehicle_direction_table[offs]; |
2762 return _new_vehicle_direction_table[offs]; |
2595 } |
2763 } |
2596 |
2764 |
2597 static Direction GetNewVehicleDirection(const Vehicle *v, int x, int y) |
|
2598 { |
|
2599 uint offs = (y - v->y_pos + 1) * 4 + (x - v->x_pos + 1); |
|
2600 assert(offs < 11); |
|
2601 return _new_vehicle_direction_table[offs]; |
|
2602 } |
|
2603 |
|
2604 static int GetDirectionToVehicle(const Vehicle *v, int x, int y) |
2765 static int GetDirectionToVehicle(const Vehicle *v, int x, int y) |
2605 { |
2766 { |
2606 byte offs; |
2767 byte offs; |
2607 |
2768 |
2608 x -= v->x_pos; |
2769 x -= v->x_pos; |
2682 static void TrainMovedChangeSignals(TileIndex tile, DiagDirection dir) |
2843 static void TrainMovedChangeSignals(TileIndex tile, DiagDirection dir) |
2683 { |
2844 { |
2684 if (IsTileType(tile, MP_RAILWAY) && |
2845 if (IsTileType(tile, MP_RAILWAY) && |
2685 GetRailTileType(tile) == RAIL_TILE_SIGNALS) { |
2846 GetRailTileType(tile) == RAIL_TILE_SIGNALS) { |
2686 uint i = FindFirstBit2x64(GetTrackBits(tile) * 0x101 & _reachable_tracks[dir]); |
2847 uint i = FindFirstBit2x64(GetTrackBits(tile) * 0x101 & _reachable_tracks[dir]); |
2687 UpdateSignalsOnSegment(tile, _otherside_signal_directions[i]); |
2848 UpdateSignalsOnSegment(tile, _otherside_signal_directions[i], GetTileOwner(tile)); |
2688 } |
2849 } |
2689 } |
2850 } |
2690 |
2851 |
2691 |
2852 |
2692 static void SetVehicleCrashed(Vehicle *v) |
2853 static void SetVehicleCrashed(Vehicle *v) |
2693 { |
2854 { |
2694 if (v->u.rail.crash_anim_pos != 0) return; |
2855 if (v->u.rail.crash_anim_pos != 0) return; |
2695 |
2856 |
2857 /* we may need to update crossing we were approaching */ |
|
2858 TileIndex crossing = TrainApproachingCrossingTile(v); |
|
2859 |
|
2696 v->u.rail.crash_anim_pos++; |
2860 v->u.rail.crash_anim_pos++; |
2697 |
2861 |
2698 Vehicle *u = v; |
2862 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
2863 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
|
2864 |
|
2865 if (v->u.rail.track == TRACK_BIT_DEPOT) { |
|
2866 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
|
2867 } |
|
2868 |
|
2869 RebuildVehicleLists(); |
|
2870 |
|
2699 BEGIN_ENUM_WAGONS(v) |
2871 BEGIN_ENUM_WAGONS(v) |
2700 v->vehstatus |= VS_CRASHED; |
2872 v->vehstatus |= VS_CRASHED; |
2873 MarkSingleVehicleDirty(v); |
|
2701 END_ENUM_WAGONS(v) |
2874 END_ENUM_WAGONS(v) |
2702 |
2875 |
2703 InvalidateWindowWidget(WC_VEHICLE_VIEW, u->index, STATUS_BAR); |
2876 /* must be updated after the train has been marked crashed */ |
2877 if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing); |
|
2704 } |
2878 } |
2705 |
2879 |
2706 static uint CountPassengersInTrain(const Vehicle* v) |
2880 static uint CountPassengersInTrain(const Vehicle* v) |
2707 { |
2881 { |
2708 uint num = 0; |
2882 uint num = 0; |
2712 return num; |
2886 return num; |
2713 } |
2887 } |
2714 |
2888 |
2715 struct TrainCollideChecker { |
2889 struct TrainCollideChecker { |
2716 Vehicle *v; |
2890 Vehicle *v; |
2717 const Vehicle *v_skip; |
|
2718 uint num; |
2891 uint num; |
2719 }; |
2892 }; |
2720 |
2893 |
2721 static void *FindTrainCollideEnum(Vehicle *v, void *data) |
2894 static void *FindTrainCollideEnum(Vehicle *v, void *data) |
2722 { |
2895 { |
2723 TrainCollideChecker* tcc = (TrainCollideChecker*)data; |
2896 TrainCollideChecker* tcc = (TrainCollideChecker*)data; |
2724 |
2897 |
2725 if (v != tcc->v && |
2898 if (v->type != VEH_TRAIN) return NULL; |
2726 v != tcc->v_skip && |
2899 |
2727 v->type == VEH_TRAIN && |
2900 /* get first vehicle now to make most usual checks faster */ |
2728 v->u.rail.track != TRACK_BIT_DEPOT && |
2901 Vehicle *coll = v->First(); |
2729 abs(v->z_pos - tcc->v->z_pos) < 6 && |
2902 |
2730 abs(v->x_pos - tcc->v->x_pos) < 6 && |
2903 /* can't collide with own wagons && can't crash in depot && the same height level */ |
2731 abs(v->y_pos - tcc->v->y_pos) < 6 ) { |
2904 if (coll != tcc->v && v->u.rail.track != TRACK_BIT_DEPOT && abs(v->z_pos - tcc->v->z_pos) < 6) { |
2732 |
2905 int x_diff = v->x_pos - tcc->v->x_pos; |
2733 Vehicle *coll = v->First(); |
2906 int y_diff = v->y_pos - tcc->v->y_pos; |
2734 |
2907 |
2735 /* it can't collide with its own wagons */ |
2908 /* needed to disable possible crash of competitor train in station by building diagonal track at its end */ |
2736 if (tcc->v == coll || |
2909 if (x_diff * x_diff + y_diff * y_diff > 25) return NULL; |
2737 (tcc->v->u.rail.track == TRACK_BIT_WORMHOLE && (tcc->v->direction & 2) != (v->direction & 2))) |
2910 |
2738 return NULL; |
|
2739 |
|
2740 /* two drivers + passengers killed in train tcc->v (if it was not crashed already) */ |
|
2741 if (!(tcc->v->vehstatus & VS_CRASHED)) { |
2911 if (!(tcc->v->vehstatus & VS_CRASHED)) { |
2912 /* two drivers + passengers killed in train tcc->v (if it was not crashed already) */ |
|
2742 tcc->num += 2 + CountPassengersInTrain(tcc->v); |
2913 tcc->num += 2 + CountPassengersInTrain(tcc->v); |
2743 SetVehicleCrashed(tcc->v); |
2914 SetVehicleCrashed(tcc->v); |
2744 } |
2915 } |
2745 |
2916 |
2746 if (!(coll->vehstatus & VS_CRASHED)) { |
2917 if (!(coll->vehstatus & VS_CRASHED)) { |
2766 |
2937 |
2767 assert(v->u.rail.track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile); |
2938 assert(v->u.rail.track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile); |
2768 |
2939 |
2769 TrainCollideChecker tcc; |
2940 TrainCollideChecker tcc; |
2770 tcc.v = v; |
2941 tcc.v = v; |
2771 tcc.v_skip = v->Next(); |
|
2772 tcc.num = 0; |
2942 tcc.num = 0; |
2773 |
2943 |
2774 /* find colliding vehicles */ |
2944 /* find colliding vehicles */ |
2775 if (v->u.rail.track == TRACK_BIT_WORMHOLE) { |
2945 if (v->u.rail.track == TRACK_BIT_WORMHOLE) { |
2776 VehicleFromPos(v->tile, &tcc, FindTrainCollideEnum); |
2946 VehicleFromPos(v->tile, &tcc, FindTrainCollideEnum); |
2777 if (IsBridgeTile(v->tile)) { |
2947 VehicleFromPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum); |
2778 VehicleFromPos(GetOtherBridgeEnd(v->tile), &tcc, FindTrainCollideEnum); |
|
2779 } else { |
|
2780 VehicleFromPos(GetOtherTunnelEnd(v->tile), &tcc, FindTrainCollideEnum); |
|
2781 } |
|
2782 } else { |
2948 } else { |
2783 VehicleFromPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum); |
2949 VehicleFromPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum); |
2784 } |
2950 } |
2785 |
2951 |
2786 /* any dead -> no crash */ |
2952 /* any dead -> no crash */ |
2795 |
2961 |
2796 ModifyStationRatingAround(v->tile, v->owner, -160, 30); |
2962 ModifyStationRatingAround(v->tile, v->owner, -160, 30); |
2797 SndPlayVehicleFx(SND_13_BIG_CRASH, v); |
2963 SndPlayVehicleFx(SND_13_BIG_CRASH, v); |
2798 } |
2964 } |
2799 |
2965 |
2800 struct VehicleAtSignalData { |
|
2801 TileIndex tile; |
|
2802 Direction direction; |
|
2803 }; |
|
2804 |
|
2805 static void *CheckVehicleAtSignal(Vehicle *v, void *data) |
2966 static void *CheckVehicleAtSignal(Vehicle *v, void *data) |
2806 { |
2967 { |
2807 const VehicleAtSignalData* vasd = (VehicleAtSignalData*)data; |
2968 Direction dir = *(Direction*)data; |
2808 |
2969 |
2809 if (v->type == VEH_TRAIN && IsFrontEngine(v) && v->tile == vasd->tile) { |
2970 if (v->type == VEH_TRAIN && IsFrontEngine(v)) { |
2810 DirDiff diff = ChangeDirDiff(DirDifference(v->direction, vasd->direction), DIRDIFF_90RIGHT); |
2971 DirDiff diff = ChangeDirDiff(DirDifference(v->direction, dir), DIRDIFF_90RIGHT); |
2811 |
2972 |
2812 if (diff == DIRDIFF_90RIGHT || (v->cur_speed <= 5 && diff <= DIRDIFF_REVERSE)) return v; |
2973 if (diff == DIRDIFF_90RIGHT || (v->cur_speed <= 5 && diff <= DIRDIFF_REVERSE)) return v; |
2813 } |
2974 } |
2814 return NULL; |
2975 return NULL; |
2815 } |
2976 } |
2819 Vehicle *prev; |
2980 Vehicle *prev; |
2820 |
2981 |
2821 /* For every vehicle after and including the given vehicle */ |
2982 /* For every vehicle after and including the given vehicle */ |
2822 for (prev = v->Previous(); v != NULL; prev = v, v = v->Next()) { |
2983 for (prev = v->Previous(); v != NULL; prev = v, v = v->Next()) { |
2823 DiagDirection enterdir = DIAGDIR_BEGIN; |
2984 DiagDirection enterdir = DIAGDIR_BEGIN; |
2824 bool update_signals = false; |
2985 bool update_signals_crossing = false; // will we update signals or crossing state? |
2825 BeginVehicleMove(v); |
2986 BeginVehicleMove(v); |
2826 |
2987 |
2827 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
2988 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
2828 if (v->u.rail.track != TRACK_BIT_WORMHOLE) { |
2989 if (v->u.rail.track != TRACK_BIT_WORMHOLE) { |
2829 /* Not inside tunnel */ |
2990 /* Not inside tunnel */ |
2847 return; |
3008 return; |
2848 } |
3009 } |
2849 |
3010 |
2850 if (v->current_order.type == OT_LEAVESTATION) { |
3011 if (v->current_order.type == OT_LEAVESTATION) { |
2851 v->current_order.Free(); |
3012 v->current_order.Free(); |
2852 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
3013 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
2853 } |
3014 } |
2854 } |
3015 } |
2855 } else { |
3016 } else { |
2856 /* A new tile is about to be entered. */ |
3017 /* A new tile is about to be entered. */ |
2857 |
3018 |
2904 v->cur_speed = 0; |
3065 v->cur_speed = 0; |
2905 v->subspeed = 0; |
3066 v->subspeed = 0; |
2906 v->progress = 255 - 10; |
3067 v->progress = 255 - 10; |
2907 if (++v->load_unload_time_rem < _patches.wait_twoway_signal * 73) { |
3068 if (++v->load_unload_time_rem < _patches.wait_twoway_signal * 73) { |
2908 TileIndex o_tile = gp.new_tile + TileOffsByDiagDir(enterdir); |
3069 TileIndex o_tile = gp.new_tile + TileOffsByDiagDir(enterdir); |
2909 VehicleAtSignalData vasd; |
3070 Direction rdir = ReverseDir(dir); |
2910 vasd.tile = o_tile; |
|
2911 vasd.direction = ReverseDir(dir); |
|
2912 |
3071 |
2913 /* check if a train is waiting on the other side */ |
3072 /* check if a train is waiting on the other side */ |
2914 if (VehicleFromPos(o_tile, &vasd, CheckVehicleAtSignal) == NULL) return; |
3073 if (VehicleFromPos(o_tile, &rdir, &CheckVehicleAtSignal) == NULL) return; |
2915 } |
3074 } |
2916 } |
3075 } |
2917 goto reverse_train_direction; |
3076 goto reverse_train_direction; |
2918 } |
3077 } |
2919 } else { |
3078 } else { |
2944 uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
3103 uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
2945 if (HasBit(r, VETS_CANNOT_ENTER)) { |
3104 if (HasBit(r, VETS_CANNOT_ENTER)) { |
2946 goto invalid_rail; |
3105 goto invalid_rail; |
2947 } |
3106 } |
2948 |
3107 |
2949 if (IsLevelCrossingTile(v->tile) && v->Next() == NULL) { |
|
2950 UnbarCrossing(v->tile); |
|
2951 MarkTileDirtyByTile(v->tile); |
|
2952 } |
|
2953 |
|
2954 if (IsFrontEngine(v)) v->load_unload_time_rem = 0; |
3108 if (IsFrontEngine(v)) v->load_unload_time_rem = 0; |
2955 |
3109 |
2956 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { |
3110 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { |
2957 v->tile = gp.new_tile; |
3111 v->tile = gp.new_tile; |
2958 |
3112 |
2964 assert(v->u.rail.track); |
3118 assert(v->u.rail.track); |
2965 } |
3119 } |
2966 |
3120 |
2967 /* We need to update signal status, but after the vehicle position hash |
3121 /* We need to update signal status, but after the vehicle position hash |
2968 * has been updated by AfterSetTrainPos() */ |
3122 * has been updated by AfterSetTrainPos() */ |
2969 update_signals = true; |
3123 update_signals_crossing = true; |
2970 |
3124 |
2971 if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir); |
3125 if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir); |
2972 |
3126 |
2973 v->direction = chosen_dir; |
3127 v->direction = chosen_dir; |
2974 } |
3128 } |
2975 } else { |
3129 } else { |
2976 /* In tunnel or on a bridge */ |
3130 /* In a tunnel or on a bridge |
3131 * - for tunnels, only the part when the vehicle is not visible (part of enter/exit tile too) |
|
3132 * - for bridges, only the middle part - without the bridge heads */ |
|
2977 if (!(v->vehstatus & VS_HIDDEN)) { |
3133 if (!(v->vehstatus & VS_HIDDEN)) { |
2978 v->cur_speed = |
3134 v->cur_speed = |
2979 min(v->cur_speed, GetBridge(GetBridgeType(v->tile))->speed); |
3135 min(v->cur_speed, GetBridge(GetBridgeType(v->tile))->speed); |
2980 } |
3136 } |
2981 |
3137 |
2987 continue; |
3143 continue; |
2988 } |
3144 } |
2989 } |
3145 } |
2990 |
3146 |
2991 /* update image of train, as well as delta XY */ |
3147 /* update image of train, as well as delta XY */ |
2992 Direction newdir = GetNewVehicleDirection(v, gp.x, gp.y); |
3148 v->UpdateDeltaXY(v->direction); |
2993 v->UpdateDeltaXY(newdir); |
3149 if (update_image) v->cur_image = v->GetImage(v->direction); |
2994 if (update_image) v->cur_image = v->GetImage(newdir); |
|
2995 |
3150 |
2996 v->x_pos = gp.x; |
3151 v->x_pos = gp.x; |
2997 v->y_pos = gp.y; |
3152 v->y_pos = gp.y; |
2998 |
3153 |
2999 /* update the Z position of the vehicle */ |
3154 /* update the Z position of the vehicle */ |
3002 if (prev == NULL) { |
3157 if (prev == NULL) { |
3003 /* This is the first vehicle in the train */ |
3158 /* This is the first vehicle in the train */ |
3004 AffectSpeedByZChange(v, old_z); |
3159 AffectSpeedByZChange(v, old_z); |
3005 } |
3160 } |
3006 |
3161 |
3007 if (update_signals) { |
3162 if (update_signals_crossing) { |
3008 if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir); |
3163 if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir); |
3009 |
3164 |
3010 /* Signals can only change when the first |
3165 /* Signals can only change when the first |
3011 * (above) or the last vehicle moves. */ |
3166 * (above) or the last vehicle moves. */ |
3012 if (v->Next() == NULL) TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); |
3167 if (v->Next() == NULL) { |
3168 TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); |
|
3169 if (IsLevelCrossingTile(gp.old_tile)) UpdateLevelCrossing(gp.old_tile); |
|
3170 } |
|
3013 } |
3171 } |
3014 } |
3172 } |
3015 return; |
3173 return; |
3016 |
3174 |
3017 invalid_rail: |
3175 invalid_rail: |
3023 v->cur_speed = 0; |
3181 v->cur_speed = 0; |
3024 v->subspeed = 0; |
3182 v->subspeed = 0; |
3025 ReverseTrainDirection(v); |
3183 ReverseTrainDirection(v); |
3026 } |
3184 } |
3027 |
3185 |
3028 extern TileIndex CheckTunnelBusy(TileIndex tile, uint *length); |
|
3029 |
|
3030 /** |
3186 /** |
3031 * Deletes/Clears the last wagon of a crashed train. It takes the engine of the |
3187 * Deletes/Clears the last wagon of a crashed train. It takes the engine of the |
3032 * train, then goes to the last wagon and deletes that. Each call to this function |
3188 * train, then goes to the last wagon and deletes that. Each call to this function |
3033 * will remove the last wagon of a crashed train. If this wagon was on a crossing, |
3189 * will remove the last wagon of a crashed train. If this wagon was on a crossing, |
3034 * or inside a tunnel, recalculate the signals as they might need updating |
3190 * or inside a tunnel/bridge, recalculate the signals as they might need updating |
3035 * @param v the Vehicle of which last wagon is to be removed |
3191 * @param v the Vehicle of which last wagon is to be removed |
3036 */ |
3192 */ |
3037 static void DeleteLastWagon(Vehicle *v) |
3193 static void DeleteLastWagon(Vehicle *v) |
3038 { |
3194 { |
3195 Vehicle *first = v->First(); |
|
3196 |
|
3039 /* Go to the last wagon and delete the link pointing there |
3197 /* Go to the last wagon and delete the link pointing there |
3040 * *u is then the one-before-last wagon, and *v the last |
3198 * *u is then the one-before-last wagon, and *v the last |
3041 * one which will physicially be removed */ |
3199 * one which will physicially be removed */ |
3042 Vehicle *u = v; |
3200 Vehicle *u = v; |
3043 for (; v->Next() != NULL; v = v->Next()) u = v; |
3201 for (; v->Next() != NULL; v = v->Next()) u = v; |
3044 u->SetNext(NULL); |
3202 u->SetNext(NULL); |
3045 |
3203 |
3046 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
3204 if (first == v) { |
3047 DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
3205 /* Removing front vehicle (the last to go) */ |
3206 DeleteWindowById(WC_VEHICLE_VIEW, v->index); |
|
3207 InvalidateWindow(WC_COMPANY, v->owner); |
|
3208 } else { |
|
3209 /* Recalculate cached train properties */ |
|
3210 TrainConsistChanged(first); |
|
3211 InvalidateWindow(WC_VEHICLE_DETAILS, first->index); |
|
3212 /* Update the depot window if the first vehicle is in depot - |
|
3213 * if v == first, then it is updated in PreDestructor() */ |
|
3214 if (first->u.rail.track == TRACK_BIT_DEPOT) { |
|
3215 InvalidateWindow(WC_VEHICLE_DEPOT, first->tile); |
|
3216 } |
|
3217 } |
|
3218 |
|
3048 RebuildVehicleLists(); |
3219 RebuildVehicleLists(); |
3049 InvalidateWindow(WC_COMPANY, v->owner); |
3220 |
3050 |
3221 MarkSingleVehicleDirty(v); |
3051 BeginVehicleMove(v); |
3222 |
3052 EndVehicleMove(v); |
3223 /* 'v' shouldn't be accessed after it has been deleted */ |
3224 TrackBits track = v->u.rail.track; |
|
3225 TileIndex tile = v->tile; |
|
3226 Owner owner = v->owner; |
|
3053 |
3227 |
3054 delete v; |
3228 delete v; |
3055 |
3229 v = NULL; // make sure nobody will won't try to read 'v' anymore |
3056 if (v->u.rail.track != TRACK_BIT_DEPOT && v->u.rail.track != TRACK_BIT_WORMHOLE) |
3230 |
3057 SetSignalsOnBothDir(v->tile, FIND_FIRST_BIT(v->u.rail.track)); |
3231 /* check if the wagon was on a road/rail-crossing */ |
3058 |
3232 if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile); |
3059 /* Check if the wagon was on a road/rail-crossing and disable it if no |
3233 |
3060 * others are on it */ |
3234 /* Update signals */ |
3061 DisableTrainCrossing(v->tile); |
3235 if (IsTileType(tile, MP_TUNNELBRIDGE) || IsTileDepotType(tile, TRANSPORT_RAIL)) { |
3062 |
3236 UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner); |
3063 if ((v->u.rail.track == TRACK_BIT_WORMHOLE && v->vehstatus & VS_HIDDEN)) { // inside a tunnel |
3237 } else { |
3064 TileIndex endtile = CheckTunnelBusy(v->tile, NULL); |
3238 SetSignalsOnBothDir(tile, (Track)(FIND_FIRST_BIT(track)), owner); |
3065 |
|
3066 if (endtile == INVALID_TILE) return; // tunnel is busy (error returned) |
|
3067 |
|
3068 switch (v->direction) { |
|
3069 case 1: |
|
3070 case 5: |
|
3071 SetSignalsOnBothDir(v->tile, 0); |
|
3072 SetSignalsOnBothDir(endtile, 0); |
|
3073 break; |
|
3074 |
|
3075 case 3: |
|
3076 case 7: |
|
3077 SetSignalsOnBothDir(v->tile, 1); |
|
3078 SetSignalsOnBothDir(endtile, 1); |
|
3079 break; |
|
3080 |
|
3081 default: |
|
3082 break; |
|
3083 } |
|
3084 } |
3239 } |
3085 } |
3240 } |
3086 |
3241 |
3087 static void ChangeTrainDirRandomly(Vehicle *v) |
3242 static void ChangeTrainDirRandomly(Vehicle *v) |
3088 { |
3243 { |
3169 InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
3324 InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
3170 } |
3325 } |
3171 } |
3326 } |
3172 } |
3327 } |
3173 |
3328 |
3174 static const byte _breakdown_speeds[16] = { |
3329 /** Maximum speeds for train that is broken down or approaching line end */ |
3330 static const uint16 _breakdown_speeds[16] = { |
|
3175 225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15 |
3331 225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15 |
3176 }; |
3332 }; |
3177 |
3333 |
3334 |
|
3335 /** |
|
3336 * Train is approaching line end, slow down and possibly reverse |
|
3337 * |
|
3338 * @param v front train engine |
|
3339 * @param signal not line end, just a red signal |
|
3340 * @return true iff we did NOT have to reverse |
|
3341 */ |
|
3342 static bool TrainApproachingLineEnd(Vehicle *v, bool signal) |
|
3343 { |
|
3344 /* Calc position within the current tile */ |
|
3345 uint x = v->x_pos & 0xF; |
|
3346 uint y = v->y_pos & 0xF; |
|
3347 |
|
3348 /* for diagonal directions, 'x' will be 0..15 - |
|
3349 * for other directions, it will be 1, 3, 5, ..., 15 */ |
|
3350 switch (v->direction) { |
|
3351 case DIR_N : x = ~x + ~y + 25; break; |
|
3352 case DIR_NW: x = y; /* FALLTHROUGH */ |
|
3353 case DIR_NE: x = ~x + 16; break; |
|
3354 case DIR_E : x = ~x + y + 9; break; |
|
3355 case DIR_SE: x = y; break; |
|
3356 case DIR_S : x = x + y - 7; break; |
|
3357 case DIR_W : x = ~y + x + 9; break; |
|
3358 default: break; |
|
3359 } |
|
3360 |
|
3361 /* do not reverse when approaching red signal */ |
|
3362 if (!signal && x + 4 >= TILE_SIZE) { |
|
3363 /* we are too near the tile end, reverse now */ |
|
3364 v->cur_speed = 0; |
|
3365 ReverseTrainDirection(v); |
|
3366 return false; |
|
3367 } |
|
3368 |
|
3369 /* slow down */ |
|
3370 v->vehstatus |= VS_TRAIN_SLOWING; |
|
3371 uint16 break_speed = _breakdown_speeds[x & 0xF]; |
|
3372 if (break_speed < v->cur_speed) v->cur_speed = break_speed; |
|
3373 |
|
3374 return true; |
|
3375 } |
|
3376 |
|
3377 |
|
3378 /** |
|
3379 * Determines whether train would like to leave the tile |
|
3380 * @param v train to test |
|
3381 * @return true iff vehicle is NOT entering or inside a depot or tunnel/bridge |
|
3382 */ |
|
3383 static bool TrainCanLeaveTile(const Vehicle *v) |
|
3384 { |
|
3385 /* Exit if inside a tunnel/bridge or a depot */ |
|
3386 if (v->u.rail.track == TRACK_BIT_WORMHOLE || v->u.rail.track == TRACK_BIT_DEPOT) return false; |
|
3387 |
|
3388 TileIndex tile = v->tile; |
|
3389 |
|
3390 /* entering a tunnel/bridge? */ |
|
3391 if (IsTileType(tile, MP_TUNNELBRIDGE)) { |
|
3392 DiagDirection dir = GetTunnelBridgeDirection(tile); |
|
3393 if (DiagDirToDir(dir) == v->direction) return false; |
|
3394 } |
|
3395 |
|
3396 /* entering a depot? */ |
|
3397 if (IsTileDepotType(tile, TRANSPORT_RAIL)) { |
|
3398 DiagDirection dir = ReverseDiagDir(GetRailDepotDirection(tile)); |
|
3399 if (DiagDirToDir(dir) == v->direction) return false; |
|
3400 } |
|
3401 |
|
3402 return true; |
|
3403 } |
|
3404 |
|
3405 |
|
3406 /** |
|
3407 * Determines whether train is approaching a rail-road crossing |
|
3408 * (thus making it barred) |
|
3409 * @param v front engine of train |
|
3410 * @return TileIndex of crossing the train is approaching, else INVALID_TILE |
|
3411 * @pre v in non-crashed front engine |
|
3412 */ |
|
3413 static TileIndex TrainApproachingCrossingTile(const Vehicle *v) |
|
3414 { |
|
3415 assert(IsFrontEngine(v)); |
|
3416 assert(!(v->vehstatus & VS_CRASHED)); |
|
3417 |
|
3418 if (!TrainCanLeaveTile(v)) return INVALID_TILE; |
|
3419 |
|
3420 DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); |
|
3421 TileIndex tile = v->tile + TileOffsByDiagDir(dir); |
|
3422 |
|
3423 /* not a crossing || wrong axis || wrong railtype || wrong owner */ |
|
3424 if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) || |
|
3425 !CheckCompatibleRail(v, tile) || GetTileOwner(tile) != v->owner) { |
|
3426 return INVALID_TILE; |
|
3427 } |
|
3428 |
|
3429 return tile; |
|
3430 } |
|
3431 |
|
3432 |
|
3433 /** |
|
3434 * Checks for line end. Also, bars crossing at next tile if needed |
|
3435 * |
|
3436 * @param v vehicle we are checking |
|
3437 * @return true iff we did NOT have to reverse |
|
3438 */ |
|
3178 static bool TrainCheckIfLineEnds(Vehicle *v) |
3439 static bool TrainCheckIfLineEnds(Vehicle *v) |
3179 { |
3440 { |
3441 /* First, handle broken down train */ |
|
3442 |
|
3180 int t = v->breakdown_ctr; |
3443 int t = v->breakdown_ctr; |
3181 if (t > 1) { |
3444 if (t > 1) { |
3182 v->vehstatus |= VS_TRAIN_SLOWING; |
3445 v->vehstatus |= VS_TRAIN_SLOWING; |
3183 |
3446 |
3184 uint16 break_speed = _breakdown_speeds[GB(~t, 4, 4)]; |
3447 uint16 break_speed = _breakdown_speeds[GB(~t, 4, 4)]; |
3185 if (break_speed < v->cur_speed) v->cur_speed = break_speed; |
3448 if (break_speed < v->cur_speed) v->cur_speed = break_speed; |
3186 } else { |
3449 } else { |
3187 v->vehstatus &= ~VS_TRAIN_SLOWING; |
3450 v->vehstatus &= ~VS_TRAIN_SLOWING; |
3188 } |
3451 } |
3189 |
3452 |
3190 if (v->u.rail.track == TRACK_BIT_WORMHOLE) return true; // exit if inside a tunnel |
3453 if (!TrainCanLeaveTile(v)) return true; |
3191 if (v->u.rail.track == TRACK_BIT_DEPOT) return true; // exit if inside a depot |
|
3192 |
|
3193 TileIndex tile = v->tile; |
|
3194 |
|
3195 if (IsTileType(tile, MP_TUNNELBRIDGE)) { |
|
3196 DiagDirection dir = IsTunnel(tile) ? GetTunnelDirection(tile) : GetBridgeRampDirection(tile); |
|
3197 if (DiagDirToDir(dir) == v->direction) return true; |
|
3198 } |
|
3199 |
|
3200 // depot? |
|
3201 /* XXX -- When enabled, this makes it possible to crash trains of others |
|
3202 (by building a depot right against a station) */ |
|
3203 /* if (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == RAIL_TILE_DEPOT_WAYPOINT) |
|
3204 return true;*/ |
|
3205 |
3454 |
3206 /* Determine the non-diagonal direction in which we will exit this tile */ |
3455 /* Determine the non-diagonal direction in which we will exit this tile */ |
3207 DiagDirection dir = DirToDiagDir(v->direction); |
3456 DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); |
3208 if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[dir]) { |
|
3209 dir = ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT); |
|
3210 } |
|
3211 /* Calculate next tile */ |
3457 /* Calculate next tile */ |
3212 tile += TileOffsByDiagDir(dir); |
3458 TileIndex tile = v->tile + TileOffsByDiagDir(dir); |
3213 // determine the track status on the next tile. |
3459 |
3460 /* Determine the track status on the next tile */ |
|
3214 uint32 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _reachable_tracks[dir]; |
3461 uint32 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _reachable_tracks[dir]; |
3215 |
3462 |
3216 /* Calc position within the current tile ?? */ |
3463 /* We are sure the train is not entering a depot, it is detected above */ |
3217 uint x = v->x_pos & 0xF; |
3464 |
3218 uint y = v->y_pos & 0xF; |
3465 /* no suitable trackbits at all || wrong railtype || not our track || |
3219 |
3466 * tunnel/bridge from opposite side || depot from opposite side */ |
3220 switch (v->direction) { |
3467 if (GB(ts, 0, 16) == 0 || !CheckCompatibleRail(v, tile) || GetTileOwner(tile) != v->owner || |
3221 case DIR_N : x = ~x + ~y + 24; break; |
3468 (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(tile) != dir) || |
3222 case DIR_NW: x = y; /* FALLTHROUGH */ |
3469 (IsTileDepotType(tile, TRANSPORT_RAIL) && GetRailDepotDirection(tile) == dir) ) { |
3223 case DIR_NE: x = ~x + 16; break; |
3470 return TrainApproachingLineEnd(v, false); |
3224 case DIR_E : x = ~x + y + 8; break; |
3471 } |
3225 case DIR_SE: x = y; break; |
3472 |
3226 case DIR_S : x = x + y - 8; break; |
3473 /* approaching red signal */ |
3227 case DIR_W : x = ~y + x + 8; break; |
3474 if ((ts & (ts >> 16)) != 0) return TrainApproachingLineEnd(v, true); |
3228 default: break; |
3475 |
3229 } |
3476 /* approaching a rail/road crossing? then make it red */ |
3230 |
3477 if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile); |
3231 if (GB(ts, 0, 16) != 0) { |
|
3232 /* If we approach a rail-piece which we can't enter, or the back of a depot, don't enter it! */ |
|
3233 if (x + 4 >= TILE_SIZE && |
|
3234 (!CheckCompatibleRail(v, tile) || |
|
3235 (IsTileDepotType(tile, TRANSPORT_RAIL) && |
|
3236 GetRailDepotDirection(tile) == dir))) { |
|
3237 v->cur_speed = 0; |
|
3238 ReverseTrainDirection(v); |
|
3239 return false; |
|
3240 } |
|
3241 if ((ts &= (ts >> 16)) == 0) { |
|
3242 /* make a rail/road crossing red */ |
|
3243 if (IsLevelCrossingTile(tile)) { |
|
3244 if (!IsCrossingBarred(tile)) { |
|
3245 BarCrossing(tile); |
|
3246 SndPlayVehicleFx(SND_0E_LEVEL_CROSSING, v); |
|
3247 MarkTileDirtyByTile(tile); |
|
3248 } |
|
3249 } |
|
3250 return true; |
|
3251 } |
|
3252 } else if (x + 4 >= TILE_SIZE) { |
|
3253 v->cur_speed = 0; |
|
3254 ReverseTrainDirection(v); |
|
3255 return false; |
|
3256 } |
|
3257 |
|
3258 /* slow down */ |
|
3259 v->vehstatus |= VS_TRAIN_SLOWING; |
|
3260 uint16 break_speed = _breakdown_speeds[x & 0xF]; |
|
3261 if (!(v->direction & 1)) break_speed >>= 1; |
|
3262 if (break_speed < v->cur_speed) v->cur_speed = break_speed; |
|
3263 |
3478 |
3264 return true; |
3479 return true; |
3265 } |
3480 } |
3481 |
|
3266 |
3482 |
3267 static void TrainLocoHandler(Vehicle *v, bool mode) |
3483 static void TrainLocoHandler(Vehicle *v, bool mode) |
3268 { |
3484 { |
3269 /* train has crashed? */ |
3485 /* train has crashed? */ |
3270 if (v->vehstatus & VS_CRASHED) { |
3486 if (v->vehstatus & VS_CRASHED) { |
3381 /* If we were already heading for a depot but it has |
3597 /* If we were already heading for a depot but it has |
3382 * suddenly moved farther away, we continue our normal |
3598 * suddenly moved farther away, we continue our normal |
3383 * schedule? */ |
3599 * schedule? */ |
3384 v->current_order.type = OT_DUMMY; |
3600 v->current_order.type = OT_DUMMY; |
3385 v->current_order.flags = 0; |
3601 v->current_order.flags = 0; |
3386 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
3602 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
3387 } |
3603 } |
3388 return; |
3604 return; |
3389 } |
3605 } |
3390 |
3606 |
3391 const Depot* depot = GetDepotByTile(tfdd.tile); |
3607 const Depot* depot = GetDepotByTile(tfdd.tile); |
3395 !Chance16(3, 16)) { |
3611 !Chance16(3, 16)) { |
3396 return; |
3612 return; |
3397 } |
3613 } |
3398 |
3614 |
3399 v->current_order.type = OT_GOTO_DEPOT; |
3615 v->current_order.type = OT_GOTO_DEPOT; |
3400 v->current_order.flags = OF_NON_STOP; |
3616 v->current_order.flags = OFB_NON_STOP; |
3401 v->current_order.dest = depot->index; |
3617 v->current_order.dest = depot->index; |
3402 v->dest_tile = tfdd.tile; |
3618 v->dest_tile = tfdd.tile; |
3403 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
3619 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
3404 } |
3620 } |
3405 |
3621 |
3406 void OnNewDay_Train(Vehicle *v) |
3622 void OnNewDay_Train(Vehicle *v) |
3407 { |
3623 { |
3408 if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v); |
3624 if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v); |
3421 if (tile != 0) v->dest_tile = tile; |
3637 if (tile != 0) v->dest_tile = tile; |
3422 } |
3638 } |
3423 |
3639 |
3424 if ((v->vehstatus & VS_STOPPED) == 0) { |
3640 if ((v->vehstatus & VS_STOPPED) == 0) { |
3425 /* running costs */ |
3641 /* running costs */ |
3426 CommandCost cost(v->GetRunningCost() / 364); |
3642 CommandCost cost(EXPENSES_TRAIN_RUN, v->GetRunningCost() / 364); |
3427 |
3643 |
3428 v->profit_this_year -= cost.GetCost() >> 8; |
3644 v->profit_this_year -= cost.GetCost() >> 8; |
3429 |
3645 |
3430 SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN); |
|
3431 SubtractMoneyFromPlayerFract(v->owner, cost); |
3646 SubtractMoneyFromPlayerFract(v->owner, cost); |
3432 |
3647 |
3433 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
3648 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
3434 InvalidateWindowClasses(WC_TRAINS_LIST); |
3649 InvalidateWindowClasses(WC_TRAINS_LIST); |
3435 } |
3650 } |