3 /** @file roadveh_cmd.cpp */ |
3 /** @file roadveh_cmd.cpp */ |
4 |
4 |
5 #include "stdafx.h" |
5 #include "stdafx.h" |
6 #include "openttd.h" |
6 #include "openttd.h" |
7 #include "debug.h" |
7 #include "debug.h" |
8 #include "functions.h" |
8 #include "tile_cmd.h" |
9 #include "landscape.h" |
9 #include "landscape.h" |
10 #include "road_map.h" |
10 #include "road_map.h" |
11 #include "roadveh.h" |
11 #include "roadveh.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 "vehicle.h" |
|
18 #include "timetable.h" |
13 #include "timetable.h" |
19 #include "engine.h" |
14 #include "engine.h" |
20 #include "command.h" |
15 #include "command_func.h" |
21 #include "station.h" |
16 #include "station.h" |
22 #include "news.h" |
17 #include "news.h" |
23 #include "pathfind.h" |
18 #include "pathfind.h" |
24 #include "npf.h" |
19 #include "npf.h" |
25 #include "player.h" |
20 #include "player_func.h" |
26 #include "sound.h" |
21 #include "player_base.h" |
27 #include "depot.h" |
22 #include "depot.h" |
28 #include "bridge.h" |
23 #include "bridge.h" |
29 #include "tunnel_map.h" |
24 #include "tunnel_map.h" |
30 #include "bridge_map.h" |
25 #include "bridge_map.h" |
31 #include "vehicle_gui.h" |
26 #include "vehicle_gui.h" |
33 #include "newgrf_callbacks.h" |
28 #include "newgrf_callbacks.h" |
34 #include "newgrf_engine.h" |
29 #include "newgrf_engine.h" |
35 #include "newgrf_text.h" |
30 #include "newgrf_text.h" |
36 #include "newgrf_sound.h" |
31 #include "newgrf_sound.h" |
37 #include "yapf/yapf.h" |
32 #include "yapf/yapf.h" |
38 #include "date.h" |
|
39 #include "cargotype.h" |
33 #include "cargotype.h" |
|
34 #include "strings_func.h" |
|
35 #include "tunnelbridge_map.h" |
|
36 #include "functions.h" |
|
37 #include "window_func.h" |
|
38 #include "date_func.h" |
|
39 #include "vehicle_func.h" |
|
40 #include "sound_func.h" |
|
41 #include "variables.h" |
|
42 #include "autoreplace_gui.h" |
|
43 #include "gfx_func.h" |
|
44 #include "settings_type.h" |
|
45 |
|
46 #include "table/strings.h" |
40 |
47 |
41 static const uint16 _roadveh_images[63] = { |
48 static const uint16 _roadveh_images[63] = { |
42 0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14, |
49 0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14, |
43 0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74, |
50 0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74, |
44 0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C, |
51 0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C, |
92 int image; |
99 int image; |
93 |
100 |
94 if (is_custom_sprite(img)) { |
101 if (is_custom_sprite(img)) { |
95 image = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img))); |
102 image = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img))); |
96 if (image != 0) return image; |
103 if (image != 0) return image; |
97 img = orig_road_vehicle_info[this->engine_type - ROAD_ENGINES_INDEX].image_index; |
104 img = _orig_road_vehicle_info[this->engine_type - ROAD_ENGINES_INDEX].image_index; |
98 } |
105 } |
99 |
106 |
100 image = direction + _roadveh_images[img]; |
107 image = direction + _roadveh_images[img]; |
101 if (this->cargo.Count() >= this->cargo_cap / 2U) image += _roadveh_full_adder[img]; |
108 if (this->cargo.Count() >= this->cargo_cap / 2U) image += _roadveh_full_adder[img]; |
102 return image; |
109 return image; |
111 |
118 |
112 if (sprite != 0) { |
119 if (sprite != 0) { |
113 DrawSprite(sprite, pal, x, y); |
120 DrawSprite(sprite, pal, x, y); |
114 return; |
121 return; |
115 } |
122 } |
116 spritenum = orig_road_vehicle_info[engine - ROAD_ENGINES_INDEX].image_index; |
123 spritenum = _orig_road_vehicle_info[engine - ROAD_ENGINES_INDEX].image_index; |
117 } |
124 } |
118 DrawSprite(6 + _roadveh_images[spritenum], pal, x, y); |
125 DrawSprite(6 + _roadveh_images[spritenum], pal, x, y); |
119 } |
126 } |
120 |
127 |
121 static CommandCost EstimateRoadVehCost(EngineID engine_type) |
128 static CommandCost EstimateRoadVehCost(EngineID engine_type) |
122 { |
129 { |
123 return CommandCost(((_price.roadveh_base >> 3) * GetEngineProperty(engine_type, 0x11, RoadVehInfo(engine_type)->base_cost)) >> 5); |
130 return CommandCost(EXPENSES_NEW_VEHICLES, ((_price.roadveh_base >> 3) * GetEngineProperty(engine_type, 0x11, RoadVehInfo(engine_type)->base_cost)) >> 5); |
124 } |
131 } |
125 |
132 |
126 byte GetRoadVehLength(const Vehicle *v) |
133 byte GetRoadVehLength(const Vehicle *v) |
127 { |
134 { |
128 byte length = 8; |
135 byte length = 8; |
164 Vehicle *v; |
171 Vehicle *v; |
165 UnitID unit_num; |
172 UnitID unit_num; |
166 Engine *e; |
173 Engine *e; |
167 |
174 |
168 if (!IsEngineBuildable(p1, VEH_ROAD, _current_player)) return_cmd_error(STR_ROAD_VEHICLE_NOT_AVAILABLE); |
175 if (!IsEngineBuildable(p1, VEH_ROAD, _current_player)) return_cmd_error(STR_ROAD_VEHICLE_NOT_AVAILABLE); |
169 |
|
170 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
171 |
176 |
172 cost = EstimateRoadVehCost(p1); |
177 cost = EstimateRoadVehCost(p1); |
173 if (flags & DC_QUERY_COST) return cost; |
178 if (flags & DC_QUERY_COST) return cost; |
174 |
179 |
175 /* The ai_new queries the vehicle cost before building the route, |
180 /* The ai_new queries the vehicle cost before building the route, |
231 // v->u.road.unk2 = 0; |
236 // v->u.road.unk2 = 0; |
232 // v->u.road.overtaking = 0; |
237 // v->u.road.overtaking = 0; |
233 |
238 |
234 v->last_station_visited = INVALID_STATION; |
239 v->last_station_visited = INVALID_STATION; |
235 v->max_speed = rvi->max_speed; |
240 v->max_speed = rvi->max_speed; |
236 v->engine_type = (byte)p1; |
241 v->engine_type = (EngineID)p1; |
237 |
242 |
238 e = GetEngine(p1); |
243 e = GetEngine(p1); |
239 v->reliability = e->reliability; |
244 v->reliability = e->reliability; |
240 v->reliability_spd_dec = e->reliability_spd_dec; |
245 v->reliability_spd_dec = e->reliability_spd_dec; |
241 v->max_age = e->lifelength * 366; |
246 v->max_age = e->lifelength * 366; |
242 _new_vehicle_id = v->index; |
247 _new_vehicle_id = v->index; |
243 |
248 |
244 v->string_id = STR_SV_ROADVEH_NAME; |
249 v->name = NULL; |
245 |
250 |
246 v->service_interval = _patches.servint_roadveh; |
251 v->service_interval = _patches.servint_roadveh; |
247 |
252 |
248 v->date_of_last_service = _date; |
253 v->date_of_last_service = _date; |
249 v->build_year = _cur_year; |
254 v->build_year = _cur_year; |
307 DeleteVehicleNews(p1, STR_9016_ROAD_VEHICLE_IS_WAITING); |
312 DeleteVehicleNews(p1, STR_9016_ROAD_VEHICLE_IS_WAITING); |
308 } |
313 } |
309 |
314 |
310 v->vehstatus ^= VS_STOPPED; |
315 v->vehstatus ^= VS_STOPPED; |
311 v->cur_speed = 0; |
316 v->cur_speed = 0; |
312 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
317 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
313 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
318 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
314 } |
319 } |
315 |
320 |
316 return CommandCost(); |
321 return CommandCost(); |
317 } |
322 } |
359 |
364 |
360 if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR; |
365 if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR; |
361 |
366 |
362 if (HASBITS(v->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE); |
367 if (HASBITS(v->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE); |
363 |
368 |
364 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
|
365 |
|
366 if (!CheckRoadVehInDepotStopped(v)) { |
369 if (!CheckRoadVehInDepotStopped(v)) { |
367 return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE); |
370 return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE); |
368 } |
371 } |
369 |
372 |
370 CommandCost ret(-v->value); |
373 CommandCost ret(EXPENSES_NEW_VEHICLES, -v->value); |
371 |
374 |
372 if (flags & DC_EXEC) { |
375 if (flags & DC_EXEC) { |
373 // Invalidate depot |
376 // Invalidate depot |
374 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
377 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
375 RebuildVehicleLists(); |
378 RebuildVehicleLists(); |
419 } else if (_patches.new_pathfinding_all) { |
422 } else if (_patches.new_pathfinding_all) { |
420 NPFFoundTargetData ftd; |
423 NPFFoundTargetData ftd; |
421 /* See where we are now */ |
424 /* See where we are now */ |
422 Trackdir trackdir = GetVehicleTrackdir(v); |
425 Trackdir trackdir = GetVehicleTrackdir(v); |
423 |
426 |
424 ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, v->tile, ReverseTrackdir(trackdir), TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPE, 0); |
427 ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, v->tile, ReverseTrackdir(trackdir), TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES, 0); |
425 if (ftd.best_bird_dist == 0) { |
428 if (ftd.best_bird_dist == 0) { |
426 return GetDepotByTile(ftd.node.tile); /* Target found */ |
429 return GetDepotByTile(ftd.node.tile); /* Target found */ |
427 } else { |
430 } else { |
428 return NULL; /* Target not found */ |
431 return NULL; /* Target not found */ |
429 } |
432 } |
474 |
477 |
475 if (v->IsInDepot()) return CMD_ERROR; |
478 if (v->IsInDepot()) return CMD_ERROR; |
476 |
479 |
477 /* If the current orders are already goto-depot */ |
480 /* If the current orders are already goto-depot */ |
478 if (v->current_order.type == OT_GOTO_DEPOT) { |
481 if (v->current_order.type == OT_GOTO_DEPOT) { |
479 if (!!(p2 & DEPOT_SERVICE) == HasBit(v->current_order.flags, OFB_HALT_IN_DEPOT)) { |
482 if (!!(p2 & DEPOT_SERVICE) == HasBit(v->current_order.flags, OF_HALT_IN_DEPOT)) { |
480 /* We called with a different DEPOT_SERVICE setting. |
483 /* We called with a different DEPOT_SERVICE setting. |
481 * Now we change the setting to apply the new one and let the vehicle head for the same depot. |
484 * Now we change the setting to apply the new one and let the vehicle head for the same depot. |
482 * Note: the if is (true for requesting service == true for ordered to stop in depot) */ |
485 * Note: the if is (true for requesting service == true for ordered to stop in depot) */ |
483 if (flags & DC_EXEC) { |
486 if (flags & DC_EXEC) { |
484 ClrBit(v->current_order.flags, OFB_PART_OF_ORDERS); |
487 ClrBit(v->current_order.flags, OF_PART_OF_ORDERS); |
485 ToggleBit(v->current_order.flags, OFB_HALT_IN_DEPOT); |
488 ToggleBit(v->current_order.flags, OF_HALT_IN_DEPOT); |
486 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
489 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
487 } |
490 } |
488 return CommandCost(); |
491 return CommandCost(); |
489 } |
492 } |
490 |
493 |
491 if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders |
494 if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders |
492 if (flags & DC_EXEC) { |
495 if (flags & DC_EXEC) { |
493 /* If the orders to 'goto depot' are in the orders list (forced servicing), |
496 /* If the orders to 'goto depot' are in the orders list (forced servicing), |
494 * then skip to the next order; effectively cancelling this forced service */ |
497 * then skip to the next order; effectively cancelling this forced service */ |
495 if (HasBit(v->current_order.flags, OFB_PART_OF_ORDERS)) |
498 if (HasBit(v->current_order.flags, OF_PART_OF_ORDERS)) |
496 v->cur_order_index++; |
499 v->cur_order_index++; |
497 |
500 |
498 v->current_order.type = OT_DUMMY; |
501 v->current_order.type = OT_DUMMY; |
499 v->current_order.flags = 0; |
502 v->current_order.flags = 0; |
500 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
503 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
501 } |
504 } |
502 return CommandCost(); |
505 return CommandCost(); |
503 } |
506 } |
504 |
507 |
505 dep = FindClosestRoadDepot(v); |
508 dep = FindClosestRoadDepot(v); |
508 if (flags & DC_EXEC) { |
511 if (flags & DC_EXEC) { |
509 if (v->current_order.type == OT_LOADING) v->LeaveStation(); |
512 if (v->current_order.type == OT_LOADING) v->LeaveStation(); |
510 |
513 |
511 ClearSlot(v); |
514 ClearSlot(v); |
512 v->current_order.type = OT_GOTO_DEPOT; |
515 v->current_order.type = OT_GOTO_DEPOT; |
513 v->current_order.flags = OF_NON_STOP; |
516 v->current_order.flags = OFB_NON_STOP; |
514 if (!(p2 & DEPOT_SERVICE)) SetBit(v->current_order.flags, OFB_HALT_IN_DEPOT); |
517 if (!(p2 & DEPOT_SERVICE)) SetBit(v->current_order.flags, OF_HALT_IN_DEPOT); |
515 v->current_order.refit_cargo = CT_INVALID; |
518 v->current_order.refit_cargo = CT_INVALID; |
516 v->current_order.dest = dep->index; |
519 v->current_order.dest = dep->index; |
517 v->dest_tile = dep->xy; |
520 v->dest_tile = dep->xy; |
518 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
521 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
519 } |
522 } |
520 |
523 |
521 return CommandCost(); |
524 return CommandCost(); |
522 } |
525 } |
523 |
526 |
547 return CMD_ERROR; |
550 return CMD_ERROR; |
548 } |
551 } |
549 |
552 |
550 if (IsTileType(v->tile, MP_ROAD) && GetRoadTileType(v->tile) == ROAD_TILE_NORMAL && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR; |
553 if (IsTileType(v->tile, MP_ROAD) && GetRoadTileType(v->tile) == ROAD_TILE_NORMAL && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR; |
551 |
554 |
552 if (IsTunnelTile(v->tile) && DirToDiagDir(v->direction) == GetTunnelDirection(v->tile)) return CMD_ERROR; |
555 if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR; |
553 if (IsBridgeTile(v->tile) && DirToDiagDir(v->direction) == GetBridgeRampDirection(v->tile)) return CMD_ERROR; |
|
554 |
556 |
555 if (flags & DC_EXEC) v->u.road.reverse_ctr = 180; |
557 if (flags & DC_EXEC) v->u.road.reverse_ctr = 180; |
556 |
558 |
557 return CommandCost(); |
559 return CommandCost(); |
558 } |
560 } |
611 RebuildVehicleLists(); |
613 RebuildVehicleLists(); |
612 InvalidateWindow(WC_COMPANY, v->owner); |
614 InvalidateWindow(WC_COMPANY, v->owner); |
613 |
615 |
614 if (IsTileType(v->tile, MP_STATION)) ClearCrashedStation(v); |
616 if (IsTileType(v->tile, MP_STATION)) ClearCrashedStation(v); |
615 |
617 |
616 BeginVehicleMove(v); |
618 MarkSingleVehicleDirty(v); |
617 EndVehicleMove(v); |
|
618 |
619 |
619 delete v; |
620 delete v; |
620 } |
621 } |
621 |
622 |
622 static byte SetRoadVehPosition(Vehicle *v, int x, int y) |
623 static byte SetRoadVehPosition(Vehicle *v, int x, int y) |
686 for (Vehicle *u = v; u != NULL; u = u->Next()) { |
687 for (Vehicle *u = v; u != NULL; u = u->Next()) { |
687 if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count(); |
688 if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count(); |
688 |
689 |
689 u->vehstatus |= VS_CRASHED; |
690 u->vehstatus |= VS_CRASHED; |
690 |
691 |
691 MarkAllViewportsDirty(u->left_coord, u->top_coord, u->right_coord + 1, u->bottom_coord + 1); |
692 MarkSingleVehicleDirty(u); |
692 } |
693 } |
693 |
694 |
694 ClearSlot(v); |
695 ClearSlot(v); |
695 |
696 |
696 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
697 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
697 |
698 |
698 SetDParam(0, pass); |
699 SetDParam(0, pass); |
699 AddNewsItem( |
700 AddNewsItem( |
700 (pass == 1) ? |
701 (pass == 1) ? |
701 STR_9031_ROAD_VEHICLE_CRASH_DRIVER : STR_9032_ROAD_VEHICLE_CRASH_DIE, |
702 STR_9031_ROAD_VEHICLE_CRASH_DRIVER : STR_9032_ROAD_VEHICLE_CRASH_DIE, |
760 const Order *order; |
761 const Order *order; |
761 |
762 |
762 switch (v->current_order.type) { |
763 switch (v->current_order.type) { |
763 case OT_GOTO_DEPOT: |
764 case OT_GOTO_DEPOT: |
764 /* Let a depot order in the orderlist interrupt. */ |
765 /* Let a depot order in the orderlist interrupt. */ |
765 if (!(v->current_order.flags & OF_PART_OF_ORDERS)) return; |
766 if (!(v->current_order.flags & OFB_PART_OF_ORDERS)) return; |
766 if (v->current_order.flags & OF_SERVICE_IF_NEEDED && |
767 if (v->current_order.flags & OFB_SERVICE_IF_NEEDED && |
767 !VehicleNeedsService(v)) { |
768 !VehicleNeedsService(v)) { |
768 UpdateVehicleTimetable(v, true); |
769 UpdateVehicleTimetable(v, true); |
769 v->cur_order_index++; |
770 v->cur_order_index++; |
770 } |
771 } |
771 break; |
772 break; |
892 rvf.y = y; |
893 rvf.y = y; |
893 rvf.dir = dir; |
894 rvf.dir = dir; |
894 rvf.veh = v; |
895 rvf.veh = v; |
895 if (front->u.road.state == RVSB_WORMHOLE) { |
896 if (front->u.road.state == RVSB_WORMHOLE) { |
896 u = (Vehicle*)VehicleFromPos(v->tile, &rvf, EnumCheckRoadVehClose); |
897 u = (Vehicle*)VehicleFromPos(v->tile, &rvf, EnumCheckRoadVehClose); |
|
898 if (u == NULL) u = (Vehicle*)VehicleFromPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose); |
897 } else { |
899 } else { |
898 u = (Vehicle*)VehicleFromPosXY(x, y, &rvf, EnumCheckRoadVehClose); |
900 u = (Vehicle*)VehicleFromPosXY(x, y, &rvf, EnumCheckRoadVehClose); |
899 } |
901 } |
900 |
902 |
901 /* This code protects a roadvehicle from being blocked for ever |
903 /* This code protects a roadvehicle from being blocked for ever |
959 |
961 |
960 /* updates statusbar only if speed have changed to save CPU time */ |
962 /* updates statusbar only if speed have changed to save CPU time */ |
961 if (spd != v->cur_speed) { |
963 if (spd != v->cur_speed) { |
962 v->cur_speed = spd; |
964 v->cur_speed = spd; |
963 if (_patches.vehicle_speed) { |
965 if (_patches.vehicle_speed) { |
964 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
966 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
965 } |
967 } |
966 } |
968 } |
967 |
969 |
968 /* Decrease somewhat when turning */ |
970 /* Decrease somewhat when turning */ |
969 if (!(v->direction & 1)) spd = spd * 3 >> 2; |
971 if (!(v->direction & 1)) spd = spd * 3 >> 2; |
1124 frd->mindist = dist; |
1126 frd->mindist = dist; |
1125 } |
1127 } |
1126 return false; |
1128 return false; |
1127 } |
1129 } |
1128 |
1130 |
1129 static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, uint sub_type, Owner owner, RailTypeMask railtypes) |
1131 static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, NPFFindStationOrTileData* target, TransportType type, uint sub_type, Owner owner, RailTypes railtypes) |
1130 { |
1132 { |
1131 |
1133 |
1132 void* perf = NpfBeginInterval(); |
1134 void* perf = NpfBeginInterval(); |
1133 NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, target, type, sub_type, owner, railtypes); |
1135 NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, target, type, sub_type, owner, railtypes); |
1134 int t = NpfEndInterval(perf); |
1136 int t = NpfEndInterval(perf); |
1226 |
1228 |
1227 NPFFillWithOrderData(&fstd, v); |
1229 NPFFillWithOrderData(&fstd, v); |
1228 trackdir = DiagdirToDiagTrackdir(enterdir); |
1230 trackdir = DiagdirToDiagTrackdir(enterdir); |
1229 //debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir); |
1231 //debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir); |
1230 |
1232 |
1231 ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPE); |
1233 ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES); |
1232 if (ftd.best_trackdir == INVALID_TRACKDIR) { |
1234 if (ftd.best_trackdir == INVALID_TRACKDIR) { |
1233 /* We are already at our target. Just do something |
1235 /* We are already at our target. Just do something |
1234 * @todo: maybe display error? |
1236 * @todo: maybe display error? |
1235 * @todo: go straight ahead if possible? */ |
1237 * @todo: go straight ahead if possible? */ |
1236 return_track(FindFirstBit2x64(trackdirs)); |
1238 return_track(FindFirstBit2x64(trackdirs)); |
1308 assert(trackdir != INVALID_TRACKDIR); |
1310 assert(trackdir != INVALID_TRACKDIR); |
1309 |
1311 |
1310 fstd.dest_coords = tile; |
1312 fstd.dest_coords = tile; |
1311 fstd.station_index = INVALID_STATION; // indicates that the destination is a tile, not a station |
1313 fstd.station_index = INVALID_STATION; // indicates that the destination is a tile, not a station |
1312 |
1314 |
1313 dist = NPFRouteToStationOrTile(v->tile, trackdir, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPE).best_path_dist; |
1315 dist = NPFRouteToStationOrTile(v->tile, trackdir, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES).best_path_dist; |
1314 /* change units from NPF_TILE_LENGTH to # of tiles */ |
1316 /* change units from NPF_TILE_LENGTH to # of tiles */ |
1315 if (dist != UINT_MAX) |
1317 if (dist != UINT_MAX) |
1316 dist = (dist + NPF_TILE_LENGTH - 1) / NPF_TILE_LENGTH; |
1318 dist = (dist + NPF_TILE_LENGTH - 1) / NPF_TILE_LENGTH; |
1317 } |
1319 } |
1318 return dist; |
1320 return dist; |
1403 Trackdir dir; |
1405 Trackdir dir; |
1404 |
1406 |
1405 if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) { |
1407 if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) { |
1406 DiagDirection diag_dir = INVALID_DIAGDIR; |
1408 DiagDirection diag_dir = INVALID_DIAGDIR; |
1407 |
1409 |
1408 if (IsTunnelTile(tile)) { |
1410 if (IsTileType(tile, MP_TUNNELBRIDGE)) { |
1409 diag_dir = GetTunnelDirection(tile); |
1411 diag_dir = GetTunnelBridgeDirection(tile); |
1410 } else if (IsBridgeTile(tile)) { |
|
1411 diag_dir = GetBridgeRampDirection(tile); |
|
1412 } else if (IsTileType(tile, MP_ROAD) && GetRoadTileType(tile) == ROAD_TILE_DEPOT) { |
1412 } else if (IsTileType(tile, MP_ROAD) && GetRoadTileType(tile) == ROAD_TILE_DEPOT) { |
1413 diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile)); |
1413 diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile)); |
1414 } |
1414 } |
1415 |
1415 |
1416 if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR; |
1416 if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR; |
1417 dir = DiagdirToDiagTrackdir(diag_dir); |
1417 dir = DiagdirToDiagTrackdir(diag_dir); |
1418 } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) { |
1418 } else { |
1419 dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK); |
|
1420 } else if (prev_state < TRACKDIR_END) { |
|
1421 if (already_reversed && prev->tile != tile) { |
1419 if (already_reversed && prev->tile != tile) { |
1422 /* |
1420 /* |
1423 * The vehicle has reversed, but did not go straight back. |
1421 * The vehicle has reversed, but did not go straight back. |
1424 * It immediatelly turn onto another tile. This means that |
1422 * It immediatelly turn onto another tile. This means that |
1425 * the roadstate of the previous vehicle cannot be used |
1423 * the roadstate of the previous vehicle cannot be used |
1436 */ |
1434 */ |
1437 Trackdir reversed_turn_lookup[2][DIAGDIR_END] = { |
1435 Trackdir reversed_turn_lookup[2][DIAGDIR_END] = { |
1438 { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N, TRACKDIR_UPPER_E }, |
1436 { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N, TRACKDIR_UPPER_E }, |
1439 { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S }}; |
1437 { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S }}; |
1440 dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)]; |
1438 dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)]; |
|
1439 } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) { |
|
1440 dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK); |
|
1441 } else if (prev_state < TRACKDIR_END) { |
|
1442 dir = (Trackdir)prev_state; |
1441 } else { |
1443 } else { |
1442 dir = (Trackdir)prev_state; |
1444 return INVALID_TRACKDIR; |
1443 } |
1445 } |
1444 } else { |
|
1445 return INVALID_TRACKDIR; |
|
1446 } |
1446 } |
1447 |
1447 |
1448 /* Do some sanity checking. */ |
1448 /* Do some sanity checking. */ |
1449 static const RoadBits required_roadbits[] = { |
1449 static const RoadBits required_roadbits[] = { |
1450 ROAD_X, ROAD_Y, ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE, |
1450 ROAD_X, ROAD_Y, ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE, |
1459 return dir; |
1459 return dir; |
1460 } |
1460 } |
1461 |
1461 |
1462 /** |
1462 /** |
1463 * Can a tram track build without destruction on the given tile? |
1463 * Can a tram track build without destruction on the given tile? |
|
1464 * @param p the player that would be building the tram tracks |
1464 * @param t the tile to build on. |
1465 * @param t the tile to build on. |
|
1466 * @param r the road bits needed. |
1465 * @return true when a track track can be build on 't' |
1467 * @return true when a track track can be build on 't' |
1466 */ |
1468 */ |
1467 static bool CanBuildTramTrackOnTile(TileIndex t) |
1469 static bool CanBuildTramTrackOnTile(PlayerID p, TileIndex t, RoadBits r) |
1468 { |
1470 { |
1469 switch (GetTileType(t)) { |
1471 /* The 'current' player is not necessarily the owner of the vehicle. */ |
1470 case MP_CLEAR: |
1472 PlayerID original_player = _current_player; |
1471 case MP_TREES: |
1473 _current_player = p; |
1472 return true; |
1474 |
1473 |
1475 CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, 0, CMD_BUILD_ROAD); |
1474 case MP_ROAD: |
1476 |
1475 return GetRoadTileType(t) == ROAD_TILE_NORMAL; |
1477 _current_player = original_player; |
1476 |
1478 return CmdSucceeded(ret); |
1477 case MP_WATER: |
|
1478 return IsCoast(t); |
|
1479 |
|
1480 default: |
|
1481 return false; |
|
1482 } |
|
1483 } |
1479 } |
1484 |
1480 |
1485 static bool IndividualRoadVehicleController(Vehicle *v, const Vehicle *prev) |
1481 static bool IndividualRoadVehicleController(Vehicle *v, const Vehicle *prev) |
1486 { |
1482 { |
1487 Direction new_dir; |
1483 Direction new_dir; |
1489 RoadDriveEntry rd; |
1485 RoadDriveEntry rd; |
1490 int x,y; |
1486 int x,y; |
1491 uint32 r; |
1487 uint32 r; |
1492 |
1488 |
1493 if (v->u.road.overtaking != 0) { |
1489 if (v->u.road.overtaking != 0) { |
1494 if (++v->u.road.overtaking_ctr >= 35) |
1490 if (IsTileType(v->tile, MP_STATION)) { |
|
1491 /* Force us to be not overtaking! */ |
|
1492 v->u.road.overtaking = 0; |
|
1493 } else if (++v->u.road.overtaking_ctr >= 35) { |
1495 /* If overtaking just aborts at a random moment, we can have a out-of-bound problem, |
1494 /* If overtaking just aborts at a random moment, we can have a out-of-bound problem, |
1496 * if the vehicle started a corner. To protect that, only allow an abort of |
1495 * if the vehicle started a corner. To protect that, only allow an abort of |
1497 * overtake if we are on straight roads */ |
1496 * overtake if we are on straight roads */ |
1498 if (v->u.road.state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->u.road.state)) { |
1497 if (v->u.road.state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->u.road.state)) { |
1499 v->u.road.overtaking = 0; |
1498 v->u.road.overtaking = 0; |
1500 } |
1499 } |
|
1500 } |
1501 } |
1501 } |
1502 |
1502 |
1503 /* If this vehicle is in a depot and we've reached this point it must be |
1503 /* If this vehicle is in a depot and we've reached this point it must be |
1504 * one of the articulated parts. It will stay in the depot until activated |
1504 * one of the articulated parts. It will stay in the depot until activated |
1505 * by the previous vehicle in the chain when it gets to the right place. */ |
1505 * by the previous vehicle in the chain when it gets to the right place. */ |
1510 |
1510 |
1511 if (v->u.road.state == RVSB_WORMHOLE) { |
1511 if (v->u.road.state == RVSB_WORMHOLE) { |
1512 /* Vehicle is entering a depot or is on a bridge or in a tunnel */ |
1512 /* Vehicle is entering a depot or is on a bridge or in a tunnel */ |
1513 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
1513 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
1514 |
1514 |
1515 const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction); |
1515 if (IsRoadVehFront(v)) { |
1516 if (u != NULL && u->First()->cur_speed < v->cur_speed) { |
1516 const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction); |
1517 v->cur_speed = u->First()->cur_speed; |
1517 if (u != NULL) { |
1518 return false; |
1518 v->cur_speed = u->First()->cur_speed; |
|
1519 return false; |
|
1520 } |
1519 } |
1521 } |
1520 |
1522 |
1521 if ((IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) { |
1523 if ((IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) { |
1522 /* Vehicle has just entered a bridge or tunnel */ |
1524 /* Vehicle has just entered a bridge or tunnel */ |
1523 v->cur_image = v->GetImage(v->direction); |
1525 v->cur_image = v->GetImage(v->direction); |
1587 * doing a reversing turn when the piece of tram track on the next |
1589 * doing a reversing turn when the piece of tram track on the next |
1588 * tile did not exist yet. Do not use the big tram loop as that is |
1590 * tile did not exist yet. Do not use the big tram loop as that is |
1589 * going to cause the tram to split up. |
1591 * going to cause the tram to split up. |
1590 * - Or the front of the tram can drive over the next tile. |
1592 * - Or the front of the tram can drive over the next tile. |
1591 */ |
1593 */ |
1592 } else if (!IsRoadVehFront(v) || !CanBuildTramTrackOnTile(tile)) { |
1594 } else if (!IsRoadVehFront(v) || !CanBuildTramTrackOnTile(v->owner, tile, needed)) { |
1593 /* |
1595 /* |
1594 * Taking the 'small' corner for trams only happens when: |
1596 * Taking the 'small' corner for trams only happens when: |
1595 * - We are not the from vehicle of an articulated tram. |
1597 * - We are not the from vehicle of an articulated tram. |
1596 * - Or when the player cannot build on the next tile. |
1598 * - Or when the player cannot build on the next tile. |
1597 * |
1599 * |
1888 DEBUG(ms, 2, " force a slot clearing"); |
1890 DEBUG(ms, 2, " force a slot clearing"); |
1889 ClearSlot(v); |
1891 ClearSlot(v); |
1890 } |
1892 } |
1891 |
1893 |
1892 StartRoadVehSound(v); |
1894 StartRoadVehSound(v); |
1893 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
1895 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
1894 } |
1896 } |
1895 |
1897 |
1896 /* Check tile position conditions - i.e. stop position in depot, |
1898 /* Check tile position conditions - i.e. stop position in depot, |
1897 * entry onto bridge or into tunnel */ |
1899 * entry onto bridge or into tunnel */ |
1898 r = VehicleEnterTile(v, v->tile, x, y); |
1900 r = VehicleEnterTile(v, v->tile, x, y); |
1979 |
1981 |
1980 if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > 12) { |
1982 if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > 12) { |
1981 if (v->current_order.type == OT_GOTO_DEPOT) { |
1983 if (v->current_order.type == OT_GOTO_DEPOT) { |
1982 v->current_order.type = OT_DUMMY; |
1984 v->current_order.type = OT_DUMMY; |
1983 v->current_order.flags = 0; |
1985 v->current_order.flags = 0; |
1984 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
1986 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
1985 } |
1987 } |
1986 return; |
1988 return; |
1987 } |
1989 } |
1988 |
1990 |
1989 if (v->current_order.type == OT_GOTO_DEPOT && |
1991 if (v->current_order.type == OT_GOTO_DEPOT && |
1990 v->current_order.flags & OF_NON_STOP && |
1992 v->current_order.flags & OFB_NON_STOP && |
1991 !Chance16(1, 20)) { |
1993 !Chance16(1, 20)) { |
1992 return; |
1994 return; |
1993 } |
1995 } |
1994 |
1996 |
1995 if (v->current_order.type == OT_LOADING) v->LeaveStation(); |
1997 if (v->current_order.type == OT_LOADING) v->LeaveStation(); |
1996 ClearSlot(v); |
1998 ClearSlot(v); |
1997 |
1999 |
1998 v->current_order.type = OT_GOTO_DEPOT; |
2000 v->current_order.type = OT_GOTO_DEPOT; |
1999 v->current_order.flags = OF_NON_STOP; |
2001 v->current_order.flags = OFB_NON_STOP; |
2000 v->current_order.dest = depot->index; |
2002 v->current_order.dest = depot->index; |
2001 v->dest_tile = depot->xy; |
2003 v->dest_tile = depot->xy; |
2002 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2004 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
2003 } |
2005 } |
2004 |
2006 |
2005 void OnNewDay_RoadVeh(Vehicle *v) |
2007 void OnNewDay_RoadVeh(Vehicle *v) |
2006 { |
2008 { |
2007 CommandCost cost; |
2009 CommandCost cost(EXPENSES_ROADVEH_RUN); |
2008 |
2010 |
2009 if (!IsRoadVehFront(v)) return; |
2011 if (!IsRoadVehFront(v)) return; |
2010 |
2012 |
2011 if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v); |
2013 if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v); |
2012 if (v->u.road.blocked_ctr == 0) CheckVehicleBreakdown(v); |
2014 if (v->u.road.blocked_ctr == 0) CheckVehicleBreakdown(v); |
2082 DEBUG(ms, 4, "No road stop for vehicle %d (index %d) at station %d (0x%X)", |
2084 DEBUG(ms, 4, "No road stop for vehicle %d (index %d) at station %d (0x%X)", |
2083 v->unitnumber, v->index, st->index, st->xy); |
2085 v->unitnumber, v->index, st->index, st->xy); |
2084 } |
2086 } |
2085 } |
2087 } |
2086 |
2088 |
2087 cost = RoadVehInfo(v->engine_type)->running_cost * _price.roadveh_running / 364; |
2089 cost = CommandCost(EXPENSES_ROADVEH_RUN, RoadVehInfo(v->engine_type)->running_cost * _price.roadveh_running / 364); |
2088 |
2090 |
2089 v->profit_this_year -= cost.GetCost() >> 8; |
2091 v->profit_this_year -= cost.GetCost() >> 8; |
2090 |
2092 |
2091 SET_EXPENSES_TYPE(EXPENSES_ROADVEH_RUN); |
2093 SubtractMoneyFromPlayerFract(v->owner, cost); |
2092 SubtractMoneyFromPlayerFract(v->owner, CommandCost(cost)); |
|
2093 |
2094 |
2094 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
2095 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
2095 InvalidateWindowClasses(WC_ROADVEH_LIST); |
2096 InvalidateWindowClasses(WC_ROADVEH_LIST); |
2096 } |
2097 } |
2097 |
2098 |
2120 * @return cost of refit or error |
2121 * @return cost of refit or error |
2121 */ |
2122 */ |
2122 CommandCost CmdRefitRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
2123 CommandCost CmdRefitRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
2123 { |
2124 { |
2124 Vehicle *v; |
2125 Vehicle *v; |
2125 CommandCost cost; |
2126 CommandCost cost(EXPENSES_ROADVEH_RUN); |
2126 CargoID new_cid = GB(p2, 0, 8); |
2127 CargoID new_cid = GB(p2, 0, 8); |
2127 byte new_subtype = GB(p2, 8, 8); |
2128 byte new_subtype = GB(p2, 8, 8); |
2128 bool only_this = HasBit(p2, 16); |
2129 bool only_this = HasBit(p2, 16); |
2129 uint16 capacity = CALLBACK_FAILED; |
2130 uint16 capacity = CALLBACK_FAILED; |
2130 uint total_capacity = 0; |
2131 uint total_capacity = 0; |
2133 |
2134 |
2134 v = GetVehicle(p1); |
2135 v = GetVehicle(p1); |
2135 |
2136 |
2136 if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR; |
2137 if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR; |
2137 if (!CheckRoadVehInDepotStopped(v)) return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE); |
2138 if (!CheckRoadVehInDepotStopped(v)) return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE); |
|
2139 if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_CAN_T_REFIT_DESTROYED_VEHICLE); |
2138 |
2140 |
2139 if (new_cid >= NUM_CARGO) return CMD_ERROR; |
2141 if (new_cid >= NUM_CARGO) return CMD_ERROR; |
2140 |
|
2141 SET_EXPENSES_TYPE(EXPENSES_ROADVEH_RUN); |
|
2142 |
2142 |
2143 for (; v != NULL; v = v->Next()) { |
2143 for (; v != NULL; v = v->Next()) { |
2144 /* XXX: We refit all the attached wagons en-masse if they can be |
2144 /* XXX: We refit all the attached wagons en-masse if they can be |
2145 * refitted. This is how TTDPatch does it. TODO: Have some nice |
2145 * refitted. This is how TTDPatch does it. TODO: Have some nice |
2146 * [Refit] button near each wagon. */ |
2146 * [Refit] button near each wagon. */ |