138 */ |
138 */ |
139 void TrainConsistChanged(Vehicle* v) |
139 void TrainConsistChanged(Vehicle* v) |
140 { |
140 { |
141 uint16 max_speed = 0xFFFF; |
141 uint16 max_speed = 0xFFFF; |
142 |
142 |
143 assert(v->type == VEH_Train); |
143 assert(v->type == VEH_TRAIN); |
144 assert(IsFrontEngine(v) || IsFreeWagon(v)); |
144 assert(IsFrontEngine(v) || IsFreeWagon(v)); |
145 |
145 |
146 const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type); |
146 const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type); |
147 EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE; |
147 EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE; |
148 v->u.rail.cached_total_length = 0; |
148 v->u.rail.cached_total_length = 0; |
260 static bool TrainShouldStop(const Vehicle* v, TileIndex tile) |
260 static bool TrainShouldStop(const Vehicle* v, TileIndex tile) |
261 { |
261 { |
262 const Order* o = &v->current_order; |
262 const Order* o = &v->current_order; |
263 StationID sid = GetStationIndex(tile); |
263 StationID sid = GetStationIndex(tile); |
264 |
264 |
265 assert(v->type == VEH_Train); |
265 assert(v->type == VEH_TRAIN); |
266 //When does a train drive through a station |
266 //When does a train drive through a station |
267 //first we deal with the "new nonstop handling" |
267 //first we deal with the "new nonstop handling" |
268 if (_patches.new_nonstop && o->flags & OF_NON_STOP && sid == o->dest) { |
268 if (_patches.new_nonstop && o->flags & OF_NON_STOP && sid == o->dest) { |
269 return false; |
269 return false; |
270 } |
270 } |
634 VehiclePositionChanged(v); |
634 VehiclePositionChanged(v); |
635 TrainConsistChanged(GetFirstVehicleInChain(v)); |
635 TrainConsistChanged(GetFirstVehicleInChain(v)); |
636 |
636 |
637 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
637 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); |
638 if (IsLocalPlayer()) { |
638 if (IsLocalPlayer()) { |
639 InvalidateAutoreplaceWindow(VEH_Train); // updates the replace Train window |
639 InvalidateAutoreplaceWindow(VEH_TRAIN); // updates the replace Train window |
640 } |
640 } |
641 GetPlayer(_current_player)->num_engines[engine]++; |
641 GetPlayer(_current_player)->num_engines[engine]++; |
642 } |
642 } |
643 } |
643 } |
644 |
644 |
649 static void NormalizeTrainVehInDepot(const Vehicle* u) |
649 static void NormalizeTrainVehInDepot(const Vehicle* u) |
650 { |
650 { |
651 const Vehicle* v; |
651 const Vehicle* v; |
652 |
652 |
653 FOR_ALL_VEHICLES(v) { |
653 FOR_ALL_VEHICLES(v) { |
654 if (v->type == VEH_Train && IsFreeWagon(v) && |
654 if (v->type == VEH_TRAIN && IsFreeWagon(v) && |
655 v->tile == u->tile && |
655 v->tile == u->tile && |
656 v->u.rail.track == TRACK_BIT_DEPOT) { |
656 v->u.rail.track == TRACK_BIT_DEPOT) { |
657 if (CmdFailed(DoCommand(0, v->index | (u->index << 16), 1, DC_EXEC, |
657 if (CmdFailed(DoCommand(0, v->index | (u->index << 16), 1, DC_EXEC, |
658 CMD_MOVE_RAIL_VEHICLE))) |
658 CMD_MOVE_RAIL_VEHICLE))) |
659 break; |
659 break; |
687 if (building) v->next = u; |
687 if (building) v->next = u; |
688 u->engine_type = v->engine_type; |
688 u->engine_type = v->engine_type; |
689 u->build_year = v->build_year; |
689 u->build_year = v->build_year; |
690 if (building) v->value >>= 1; |
690 if (building) v->value >>= 1; |
691 u->value = v->value; |
691 u->value = v->value; |
692 u->type = VEH_Train; |
692 u->type = VEH_TRAIN; |
693 u->cur_image = 0xAC2; |
693 u->cur_image = 0xAC2; |
694 u->random_bits = VehicleRandomBits(); |
694 u->random_bits = VehicleRandomBits(); |
695 VehiclePositionChanged(u); |
695 VehiclePositionChanged(u); |
696 } |
696 } |
697 |
697 |
702 * bit 1 prevents any free cars from being added to the train |
702 * bit 1 prevents any free cars from being added to the train |
703 */ |
703 */ |
704 int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
704 int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
705 { |
705 { |
706 /* Check if the engine-type is valid (for the player) */ |
706 /* Check if the engine-type is valid (for the player) */ |
707 if (!IsEngineBuildable(p1, VEH_Train, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE); |
707 if (!IsEngineBuildable(p1, VEH_TRAIN, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE); |
708 |
708 |
709 /* Check if the train is actually being built in a depot belonging |
709 /* Check if the train is actually being built in a depot belonging |
710 * to the player. Doesn't matter if only the cost is queried */ |
710 * to the player. Doesn't matter if only the cost is queried */ |
711 if (!(flags & DC_QUERY_COST)) { |
711 if (!(flags & DC_QUERY_COST)) { |
712 if (!IsTileDepotType(tile, TRANSPORT_RAIL)) return CMD_ERROR; |
712 if (!IsTileDepotType(tile, TRANSPORT_RAIL)) return CMD_ERROR; |
737 if (!AllocateVehicles(vl, num_vehicles)) |
737 if (!AllocateVehicles(vl, num_vehicles)) |
738 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
738 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
739 |
739 |
740 Vehicle *v = vl[0]; |
740 Vehicle *v = vl[0]; |
741 |
741 |
742 UnitID unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Train); |
742 UnitID unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_TRAIN); |
743 if (unit_num > _patches.max_trains) |
743 if (unit_num > _patches.max_trains) |
744 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
744 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
745 |
745 |
746 if (flags & DC_EXEC) { |
746 if (flags & DC_EXEC) { |
747 DiagDirection dir = GetRailDepotDirection(tile); |
747 DiagDirection dir = GetRailDepotDirection(tile); |
779 _new_vehicle_id = v->index; |
779 _new_vehicle_id = v->index; |
780 |
780 |
781 v->service_interval = _patches.servint_trains; |
781 v->service_interval = _patches.servint_trains; |
782 v->date_of_last_service = _date; |
782 v->date_of_last_service = _date; |
783 v->build_year = _cur_year; |
783 v->build_year = _cur_year; |
784 v->type = VEH_Train; |
784 v->type = VEH_TRAIN; |
785 v->cur_image = 0xAC2; |
785 v->cur_image = 0xAC2; |
786 v->random_bits = VehicleRandomBits(); |
786 v->random_bits = VehicleRandomBits(); |
787 |
787 |
788 v->vehicle_flags = 0; |
788 v->vehicle_flags = 0; |
789 if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SETBIT(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); |
789 if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SETBIT(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); |
816 |
816 |
817 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
817 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
818 RebuildVehicleLists(); |
818 RebuildVehicleLists(); |
819 InvalidateWindow(WC_COMPANY, v->owner); |
819 InvalidateWindow(WC_COMPANY, v->owner); |
820 if (IsLocalPlayer()) |
820 if (IsLocalPlayer()) |
821 InvalidateAutoreplaceWindow(VEH_Train); // updates the replace Train window |
821 InvalidateAutoreplaceWindow(VEH_TRAIN); // updates the replace Train window |
822 |
822 |
823 GetPlayer(_current_player)->num_engines[p1]++; |
823 GetPlayer(_current_player)->num_engines[p1]++; |
824 } |
824 } |
825 } |
825 } |
826 |
826 |
895 Vehicle *dst; |
895 Vehicle *dst; |
896 EngineID eng = src->engine_type; |
896 EngineID eng = src->engine_type; |
897 TileIndex tile = src->tile; |
897 TileIndex tile = src->tile; |
898 |
898 |
899 FOR_ALL_VEHICLES(dst) { |
899 FOR_ALL_VEHICLES(dst) { |
900 if (dst->type == VEH_Train && IsFreeWagon(dst) && dst->tile == tile) { |
900 if (dst->type == VEH_TRAIN && IsFreeWagon(dst) && dst->tile == tile) { |
901 // check so all vehicles in the line have the same engine. |
901 // check so all vehicles in the line have the same engine. |
902 Vehicle *v = dst; |
902 Vehicle *v = dst; |
903 |
903 |
904 while (v->engine_type == eng) { |
904 while (v->engine_type == eng) { |
905 v = v->next; |
905 v = v->next; |
962 |
962 |
963 if (!IsValidVehicleID(s)) return CMD_ERROR; |
963 if (!IsValidVehicleID(s)) return CMD_ERROR; |
964 |
964 |
965 Vehicle *src = GetVehicle(s); |
965 Vehicle *src = GetVehicle(s); |
966 |
966 |
967 if (src->type != VEH_Train || !CheckOwnership(src->owner)) return CMD_ERROR; |
967 if (src->type != VEH_TRAIN || !CheckOwnership(src->owner)) return CMD_ERROR; |
968 |
968 |
969 // if nothing is selected as destination, try and find a matching vehicle to drag to. |
969 // if nothing is selected as destination, try and find a matching vehicle to drag to. |
970 Vehicle *dst; |
970 Vehicle *dst; |
971 if (d == INVALID_VEHICLE) { |
971 if (d == INVALID_VEHICLE) { |
972 dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src); |
972 dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src); |
973 } else { |
973 } else { |
974 if (!IsValidVehicleID(d)) return CMD_ERROR; |
974 if (!IsValidVehicleID(d)) return CMD_ERROR; |
975 dst = GetVehicle(d); |
975 dst = GetVehicle(d); |
976 if (dst->type != VEH_Train || !CheckOwnership(dst->owner)) return CMD_ERROR; |
976 if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR; |
977 } |
977 } |
978 |
978 |
979 // if an articulated part is being handled, deal with its parent vehicle |
979 // if an articulated part is being handled, deal with its parent vehicle |
980 while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src); |
980 while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src); |
981 if (dst != NULL) { |
981 if (dst != NULL) { |
1076 } |
1076 } |
1077 } |
1077 } |
1078 |
1078 |
1079 // moving a loco to a new line?, then we need to assign a unitnumber. |
1079 // moving a loco to a new line?, then we need to assign a unitnumber. |
1080 if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) { |
1080 if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) { |
1081 UnitID unit_num = GetFreeUnitNumber(VEH_Train); |
1081 UnitID unit_num = GetFreeUnitNumber(VEH_TRAIN); |
1082 if (unit_num > _patches.max_trains) |
1082 if (unit_num > _patches.max_trains) |
1083 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
1083 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME); |
1084 |
1084 |
1085 if (flags & DC_EXEC) src->unitnumber = unit_num; |
1085 if (flags & DC_EXEC) src->unitnumber = unit_num; |
1086 } |
1086 } |
1240 { |
1240 { |
1241 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1241 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1242 |
1242 |
1243 Vehicle *v = GetVehicle(p1); |
1243 Vehicle *v = GetVehicle(p1); |
1244 |
1244 |
1245 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1245 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1246 |
1246 |
1247 /* Check if this train can be started/stopped. The callback will fail or |
1247 /* Check if this train can be started/stopped. The callback will fail or |
1248 * return 0xFF if it can. */ |
1248 * return 0xFF if it can. */ |
1249 uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); |
1249 uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); |
1250 if (callback != CALLBACK_FAILED && callback != 0xFF) { |
1250 if (callback != CALLBACK_FAILED && callback != 0xFF) { |
1281 { |
1281 { |
1282 if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR; |
1282 if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR; |
1283 |
1283 |
1284 Vehicle *v = GetVehicle(p1); |
1284 Vehicle *v = GetVehicle(p1); |
1285 |
1285 |
1286 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1286 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1287 |
1287 |
1288 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1288 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
1289 |
1289 |
1290 while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v); |
1290 while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v); |
1291 Vehicle *first = GetFirstVehicleInChain(v); |
1291 Vehicle *first = GetFirstVehicleInChain(v); |
1332 |
1332 |
1333 /* 2.1 If the first wagon is sold, update the first-> pointers to NULL */ |
1333 /* 2.1 If the first wagon is sold, update the first-> pointers to NULL */ |
1334 for (Vehicle *tmp = first; tmp != NULL; tmp = tmp->next) tmp->first = NULL; |
1334 for (Vehicle *tmp = first; tmp != NULL; tmp = tmp->next) tmp->first = NULL; |
1335 |
1335 |
1336 /* 2.2 If there are wagons present after the deleted front engine, check |
1336 /* 2.2 If there are wagons present after the deleted front engine, check |
1337 * if the second wagon (which will be first) is an engine. If it is one, |
1337 * if the second wagon (which will be first) is an engine. If it is one, |
1338 * promote it as a new train, retaining the unitnumber, orders */ |
1338 * promote it as a new train, retaining the unitnumber, orders */ |
1339 if (new_f != NULL) { |
1339 if (new_f != NULL && IsTrainEngine(new_f)) { |
1340 if (IsTrainEngine(new_f)) { |
1340 switch_engine = true; |
1341 switch_engine = true; |
1341 /* Copy important data from the front engine */ |
1342 /* Copy important data from the front engine */ |
1342 new_f->unitnumber = first->unitnumber; |
1343 new_f->unitnumber = first->unitnumber; |
1343 new_f->current_order = first->current_order; |
1344 new_f->current_order = first->current_order; |
1344 new_f->cur_order_index = first->cur_order_index; |
1345 new_f->cur_order_index = first->cur_order_index; |
1345 new_f->orders = first->orders; |
1346 new_f->orders = first->orders; |
1346 new_f->num_orders = first->num_orders; |
1347 if (first->prev_shared != NULL) { |
1347 |
1348 first->prev_shared->next_shared = new_f; |
1348 if (first->prev_shared != NULL) { |
1349 new_f->prev_shared = first->prev_shared; |
1349 first->prev_shared->next_shared = new_f; |
1350 } |
1350 new_f->prev_shared = first->prev_shared; |
1351 |
|
1352 if (first->next_shared != NULL) { |
|
1353 first->next_shared->prev_shared = new_f; |
|
1354 new_f->next_shared = first->next_shared; |
|
1355 } |
|
1356 |
|
1357 new_f->num_orders = first->num_orders; |
|
1358 first->orders = NULL; // XXX - to not to delete the orders */ |
|
1359 if (IsLocalPlayer()) ShowTrainViewWindow(new_f); |
|
1360 } |
1351 } |
|
1352 |
|
1353 if (first->next_shared != NULL) { |
|
1354 first->next_shared->prev_shared = new_f; |
|
1355 new_f->next_shared = first->next_shared; |
|
1356 } |
|
1357 |
|
1358 /* |
|
1359 * Remove all order information from the front train, to |
|
1360 * prevent the order and the shared order list to be |
|
1361 * destroyed by Destroy/DeleteVehicle. |
|
1362 */ |
|
1363 first->orders = NULL; |
|
1364 first->prev_shared = NULL; |
|
1365 first->next_shared = NULL; |
|
1366 |
|
1367 if (IsLocalPlayer()) ShowTrainViewWindow(new_f); |
1361 } |
1368 } |
1362 } |
1369 } |
1363 |
1370 |
1364 /* 3. Delete the requested wagon */ |
1371 /* 3. Delete the requested wagon */ |
1365 cost -= v->value; |
1372 cost -= v->value; |
1738 |
1745 |
1739 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1746 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1740 |
1747 |
1741 Vehicle *v = GetVehicle(p1); |
1748 Vehicle *v = GetVehicle(p1); |
1742 |
1749 |
1743 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1750 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1744 if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED); |
1751 if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED); |
1745 |
1752 |
1746 /* Check cargo */ |
1753 /* Check cargo */ |
1747 if (new_cid > NUM_CARGO) return CMD_ERROR; |
1754 if (new_cid >= NUM_CARGO) return CMD_ERROR; |
1748 |
1755 |
1749 SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN); |
1756 SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN); |
1750 |
1757 |
1751 int32 cost = 0; |
1758 int32 cost = 0; |
1752 uint num = 0; |
1759 uint num = 0; |
1820 if (flags & DC_EXEC) TrainConsistChanged(GetFirstVehicleInChain(GetVehicle(p1))); |
1827 if (flags & DC_EXEC) TrainConsistChanged(GetFirstVehicleInChain(GetVehicle(p1))); |
1821 |
1828 |
1822 return cost; |
1829 return cost; |
1823 } |
1830 } |
1824 |
1831 |
1825 typedef struct TrainFindDepotData { |
1832 struct TrainFindDepotData { |
1826 uint best_length; |
1833 uint best_length; |
1827 TileIndex tile; |
1834 TileIndex tile; |
1828 PlayerID owner; |
1835 PlayerID owner; |
1829 /** |
1836 /** |
1830 * true if reversing is necessary for the train to get to this depot |
1837 * true if reversing is necessary for the train to get to this depot |
1831 * This value is unused when new depot finding and NPF are both disabled |
1838 * This value is unused when new depot finding and NPF are both disabled |
1832 */ |
1839 */ |
1833 bool reverse; |
1840 bool reverse; |
1834 } TrainFindDepotData; |
1841 }; |
1835 |
1842 |
1836 static bool NtpCallbFindDepot(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length) |
1843 static bool NtpCallbFindDepot(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length) |
1837 { |
1844 { |
1838 if (IsTileType(tile, MP_RAILWAY) && |
1845 if (IsTileType(tile, MP_RAILWAY) && |
1839 IsTileOwner(tile, tfdd->owner) && |
1846 IsTileOwner(tile, tfdd->owner) && |
1916 int32 CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1923 int32 CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1917 { |
1924 { |
1918 if (p2 & DEPOT_MASS_SEND) { |
1925 if (p2 & DEPOT_MASS_SEND) { |
1919 /* Mass goto depot requested */ |
1926 /* Mass goto depot requested */ |
1920 if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR; |
1927 if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR; |
1921 return SendAllVehiclesToDepot(VEH_Train, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1); |
1928 return SendAllVehiclesToDepot(VEH_TRAIN, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1); |
1922 } |
1929 } |
1923 |
1930 |
1924 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1931 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1925 |
1932 |
1926 Vehicle *v = GetVehicle(p1); |
1933 Vehicle *v = GetVehicle(p1); |
1927 |
1934 |
1928 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1935 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1929 |
1936 |
1930 if (v->vehstatus & VS_CRASHED) return CMD_ERROR; |
1937 if (v->vehstatus & VS_CRASHED) return CMD_ERROR; |
1931 |
1938 |
1932 if (v->current_order.type == OT_GOTO_DEPOT) { |
1939 if (v->current_order.type == OT_GOTO_DEPOT) { |
1933 if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) { |
1940 if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) { |
2132 |
2139 |
2133 return false; |
2140 return false; |
2134 } |
2141 } |
2135 |
2142 |
2136 /* Check for station tiles */ |
2143 /* Check for station tiles */ |
2137 typedef struct TrainTrackFollowerData { |
2144 struct TrainTrackFollowerData { |
2138 TileIndex dest_coords; |
2145 TileIndex dest_coords; |
2139 StationID station_index; // station index we're heading for |
2146 StationID station_index; // station index we're heading for |
2140 uint best_bird_dist; |
2147 uint best_bird_dist; |
2141 uint best_track_dist; |
2148 uint best_track_dist; |
2142 TrackdirByte best_track; |
2149 TrackdirByte best_track; |
2143 } TrainTrackFollowerData; |
2150 }; |
2144 |
2151 |
2145 static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, Trackdir track, uint length) |
2152 static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, Trackdir track, uint length) |
2146 { |
2153 { |
2147 // heading for nowhere? |
2154 // heading for nowhere? |
2148 if (ttfd->dest_coords == 0) return false; |
2155 if (ttfd->dest_coords == 0) return false; |
2156 /* We do not check for dest_coords if we have a station_index, |
2163 /* We do not check for dest_coords if we have a station_index, |
2157 * because in that case the dest_coords are just an |
2164 * because in that case the dest_coords are just an |
2158 * approximation of where the station is */ |
2165 * approximation of where the station is */ |
2159 // found station |
2166 // found station |
2160 ttfd->best_track = track; |
2167 ttfd->best_track = track; |
|
2168 ttfd->best_bird_dist = 0; |
2161 return true; |
2169 return true; |
2162 } else { |
2170 } else { |
2163 // didn't find station, keep track of the best path so far. |
2171 // didn't find station, keep track of the best path so far. |
2164 uint dist = DistanceManhattan(tile, ttfd->dest_coords); |
2172 uint dist = DistanceManhattan(tile, ttfd->dest_coords); |
2165 if (dist < ttfd->best_bird_dist) { |
2173 if (dist < ttfd->best_bird_dist) { |
2452 |
2460 |
2453 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
2461 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
2454 |
2462 |
2455 // If no order, do nothing. |
2463 // If no order, do nothing. |
2456 if (order == NULL) { |
2464 if (order == NULL) { |
2457 v->current_order.type = OT_NOTHING; |
2465 v->current_order.Free(); |
2458 v->current_order.flags = 0; |
|
2459 v->dest_tile = 0; |
2466 v->dest_tile = 0; |
2460 return false; |
2467 return false; |
2461 } |
2468 } |
2462 |
2469 |
2463 // If it is unchanged, keep it. |
2470 // If it is unchanged, keep it. |
2710 !IsFrontEngine(v) || |
2717 !IsFrontEngine(v) || |
2711 HASBIT(v->u.rail.compatible_railtypes, GetRailType(tile)) |
2718 HASBIT(v->u.rail.compatible_railtypes, GetRailType(tile)) |
2712 ); |
2719 ); |
2713 } |
2720 } |
2714 |
2721 |
2715 typedef struct { |
2722 struct RailtypeSlowdownParams { |
2716 byte small_turn, large_turn; |
2723 byte small_turn, large_turn; |
2717 byte z_up; // fraction to remove when moving up |
2724 byte z_up; // fraction to remove when moving up |
2718 byte z_down; // fraction to remove when moving down |
2725 byte z_down; // fraction to remove when moving down |
2719 } RailtypeSlowdownParams; |
2726 }; |
2720 |
2727 |
2721 static const RailtypeSlowdownParams _railtype_slowdown[] = { |
2728 static const RailtypeSlowdownParams _railtype_slowdown[] = { |
2722 // normal accel |
2729 // normal accel |
2723 {256 / 4, 256 / 2, 256 / 4, 2}, // normal |
2730 {256 / 4, 256 / 2, 256 / 4, 2}, // normal |
2724 {256 / 4, 256 / 2, 256 / 4, 2}, // electrified |
2731 {256 / 4, 256 / 2, 256 / 4, 2}, // electrified |
2766 UpdateSignalsOnSegment(tile, _otherside_signal_directions[i]); |
2773 UpdateSignalsOnSegment(tile, _otherside_signal_directions[i]); |
2767 } |
2774 } |
2768 } |
2775 } |
2769 |
2776 |
2770 |
2777 |
2771 typedef struct TrainCollideChecker { |
2778 struct TrainCollideChecker { |
2772 const Vehicle *v; |
2779 const Vehicle *v; |
2773 const Vehicle *v_skip; |
2780 const Vehicle *v_skip; |
2774 } TrainCollideChecker; |
2781 }; |
2775 |
2782 |
2776 static void *FindTrainCollideEnum(Vehicle *v, void *data) |
2783 static void *FindTrainCollideEnum(Vehicle *v, void *data) |
2777 { |
2784 { |
2778 const TrainCollideChecker* tcc = (TrainCollideChecker*)data; |
2785 const TrainCollideChecker* tcc = (TrainCollideChecker*)data; |
2779 |
2786 |
2780 if (v != tcc->v && |
2787 if (v != tcc->v && |
2781 v != tcc->v_skip && |
2788 v != tcc->v_skip && |
2782 v->type == VEH_Train && |
2789 v->type == VEH_TRAIN && |
2783 v->u.rail.track != TRACK_BIT_DEPOT && |
2790 v->u.rail.track != TRACK_BIT_DEPOT && |
2784 myabs(v->z_pos - tcc->v->z_pos) <= 6 && |
2791 myabs(v->z_pos - tcc->v->z_pos) <= 6 && |
2785 myabs(v->x_pos - tcc->v->x_pos) < 6 && |
2792 myabs(v->x_pos - tcc->v->x_pos) < 6 && |
2786 myabs(v->y_pos - tcc->v->y_pos) < 6) { |
2793 myabs(v->y_pos - tcc->v->y_pos) < 6) { |
2787 return v; |
2794 return v; |
2859 |
2866 |
2860 ModifyStationRatingAround(v->tile, v->owner, -160, 30); |
2867 ModifyStationRatingAround(v->tile, v->owner, -160, 30); |
2861 SndPlayVehicleFx(SND_13_BIG_CRASH, v); |
2868 SndPlayVehicleFx(SND_13_BIG_CRASH, v); |
2862 } |
2869 } |
2863 |
2870 |
2864 typedef struct VehicleAtSignalData { |
2871 struct VehicleAtSignalData { |
2865 TileIndex tile; |
2872 TileIndex tile; |
2866 Direction direction; |
2873 Direction direction; |
2867 } VehicleAtSignalData; |
2874 }; |
2868 |
2875 |
2869 static void *CheckVehicleAtSignal(Vehicle *v, void *data) |
2876 static void *CheckVehicleAtSignal(Vehicle *v, void *data) |
2870 { |
2877 { |
2871 const VehicleAtSignalData* vasd = (VehicleAtSignalData*)data; |
2878 const VehicleAtSignalData* vasd = (VehicleAtSignalData*)data; |
2872 |
2879 |
2873 if (v->type == VEH_Train && IsFrontEngine(v) && v->tile == vasd->tile) { |
2880 if (v->type == VEH_TRAIN && IsFrontEngine(v) && v->tile == vasd->tile) { |
2874 DirDiff diff = ChangeDirDiff(DirDifference(v->direction, vasd->direction), DIRDIFF_90RIGHT); |
2881 DirDiff diff = ChangeDirDiff(DirDifference(v->direction, vasd->direction), DIRDIFF_90RIGHT); |
2875 |
2882 |
2876 if (diff == DIRDIFF_90RIGHT || (v->cur_speed <= 5 && diff <= DIRDIFF_REVERSE)) return v; |
2883 if (diff == DIRDIFF_90RIGHT || (v->cur_speed <= 5 && diff <= DIRDIFF_REVERSE)) return v; |
2877 } |
2884 } |
2878 return NULL; |
2885 return NULL; |
2908 TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET); |
2915 TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET); |
2909 return; |
2916 return; |
2910 } |
2917 } |
2911 |
2918 |
2912 if (v->current_order.type == OT_LEAVESTATION) { |
2919 if (v->current_order.type == OT_LEAVESTATION) { |
2913 v->current_order.type = OT_NOTHING; |
2920 v->current_order.Free(); |
2914 v->current_order.flags = 0; |
|
2915 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2921 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2916 } |
2922 } |
2917 } |
2923 } |
2918 } else { |
2924 } else { |
2919 /* A new tile is about to be entered. */ |
2925 /* A new tile is about to be entered. */ |
3389 |
3395 |
3390 if (IsFrontEngine(v)) { |
3396 if (IsFrontEngine(v)) { |
3391 TrainLocoHandler(v, false); |
3397 TrainLocoHandler(v, false); |
3392 |
3398 |
3393 // make sure vehicle wasn't deleted. |
3399 // make sure vehicle wasn't deleted. |
3394 if (v->type == VEH_Train && IsFrontEngine(v)) |
3400 if (v->type == VEH_TRAIN && IsFrontEngine(v)) |
3395 TrainLocoHandler(v, true); |
3401 TrainLocoHandler(v, true); |
3396 } else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) { |
3402 } else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) { |
3397 // Delete flooded standalone wagon |
3403 // Delete flooded standalone wagon |
3398 if (++v->u.rail.crash_anim_pos >= 4400) |
3404 if (++v->u.rail.crash_anim_pos >= 4400) |
3399 DeleteVehicle(v); |
3405 DeleteVehicle(v); |
3493 InvalidateWindowClasses(WC_TRAINS_LIST); |
3499 InvalidateWindowClasses(WC_TRAINS_LIST); |
3494 } |
3500 } |
3495 } |
3501 } |
3496 } |
3502 } |
3497 |
3503 |
3498 void TrainsYearlyLoop(void) |
3504 void TrainsYearlyLoop() |
3499 { |
3505 { |
3500 Vehicle *v; |
3506 Vehicle *v; |
3501 |
3507 |
3502 FOR_ALL_VEHICLES(v) { |
3508 FOR_ALL_VEHICLES(v) { |
3503 if (v->type == VEH_Train && IsFrontEngine(v)) { |
3509 if (v->type == VEH_TRAIN && IsFrontEngine(v)) { |
3504 // show warning if train is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) |
3510 // show warning if train is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) |
3505 if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->profit_this_year < 0) { |
3511 if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->profit_this_year < 0) { |
3506 SetDParam(1, v->profit_this_year); |
3512 SetDParam(1, v->profit_this_year); |
3507 SetDParam(0, v->unitnumber); |
3513 SetDParam(0, v->unitnumber); |
3508 AddNewsItem( |
3514 AddNewsItem( |
3518 } |
3524 } |
3519 } |
3525 } |
3520 } |
3526 } |
3521 |
3527 |
3522 |
3528 |
3523 void InitializeTrains(void) |
3529 void InitializeTrains() |
3524 { |
3530 { |
3525 _age_cargo_skip_counter = 1; |
3531 _age_cargo_skip_counter = 1; |
3526 } |
3532 } |
3527 |
3533 |
3528 /* |
3534 /* |
3529 * Link front and rear multiheaded engines to each other |
3535 * Link front and rear multiheaded engines to each other |
3530 * This is done when loading a savegame |
3536 * This is done when loading a savegame |
3531 */ |
3537 */ |
3532 void ConnectMultiheadedTrains(void) |
3538 void ConnectMultiheadedTrains() |
3533 { |
3539 { |
3534 Vehicle *v; |
3540 Vehicle *v; |
3535 |
3541 |
3536 FOR_ALL_VEHICLES(v) { |
3542 FOR_ALL_VEHICLES(v) { |
3537 if (v->type == VEH_Train) { |
3543 if (v->type == VEH_TRAIN) { |
3538 v->u.rail.other_multiheaded_part = NULL; |
3544 v->u.rail.other_multiheaded_part = NULL; |
3539 } |
3545 } |
3540 } |
3546 } |
3541 |
3547 |
3542 FOR_ALL_VEHICLES(v) { |
3548 FOR_ALL_VEHICLES(v) { |
3543 if (v->type == VEH_Train && IsFrontEngine(v)) { |
3549 if (v->type == VEH_TRAIN && IsFrontEngine(v)) { |
3544 Vehicle *u = v; |
3550 Vehicle *u = v; |
3545 |
3551 |
3546 BEGIN_ENUM_WAGONS(u) { |
3552 BEGIN_ENUM_WAGONS(u) { |
3547 if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one |
3553 if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one |
3548 |
3554 |
3575 |
3581 |
3576 /* |
3582 /* |
3577 * Converts all trains to the new subtype format introduced in savegame 16.2 |
3583 * Converts all trains to the new subtype format introduced in savegame 16.2 |
3578 * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found |
3584 * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found |
3579 */ |
3585 */ |
3580 void ConvertOldMultiheadToNew(void) |
3586 void ConvertOldMultiheadToNew() |
3581 { |
3587 { |
3582 Vehicle *v; |
3588 Vehicle *v; |
3583 FOR_ALL_VEHICLES(v) { |
3589 FOR_ALL_VEHICLES(v) { |
3584 if (v->type == VEH_Train) { |
3590 if (v->type == VEH_TRAIN) { |
3585 SETBIT(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop |
3591 SETBIT(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop |
3586 } |
3592 } |
3587 } |
3593 } |
3588 |
3594 |
3589 FOR_ALL_VEHICLES(v) { |
3595 FOR_ALL_VEHICLES(v) { |
3590 if (v->type == VEH_Train) { |
3596 if (v->type == VEH_TRAIN) { |
3591 if (HASBIT(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) { |
3597 if (HASBIT(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) { |
3592 Vehicle *u = v; |
3598 Vehicle *u = v; |
3593 |
3599 |
3594 BEGIN_ENUM_WAGONS(u) { |
3600 BEGIN_ENUM_WAGONS(u) { |
3595 const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); |
3601 const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); |