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 } |
543 u->cargo_cap = rvi_artic->capacity; |
543 u->cargo_cap = rvi_artic->capacity; |
544 u->max_speed = 0; |
544 u->max_speed = 0; |
545 u->max_age = 0; |
545 u->max_age = 0; |
546 u->engine_type = engine_type; |
546 u->engine_type = engine_type; |
547 u->value = 0; |
547 u->value = 0; |
548 u->type = VEH_Train; |
548 u->type = VEH_TRAIN; |
549 u->subtype = 0; |
549 u->subtype = 0; |
550 SetArticulatedPart(u); |
550 SetArticulatedPart(u); |
551 u->cur_image = 0xAC2; |
551 u->cur_image = 0xAC2; |
552 u->random_bits = VehicleRandomBits(); |
552 u->random_bits = VehicleRandomBits(); |
553 |
553 |
621 // v->day_counter = 0; |
621 // v->day_counter = 0; |
622 |
622 |
623 v->u.rail.railtype = rvi->railtype; |
623 v->u.rail.railtype = rvi->railtype; |
624 |
624 |
625 v->build_year = _cur_year; |
625 v->build_year = _cur_year; |
626 v->type = VEH_Train; |
626 v->type = VEH_TRAIN; |
627 v->cur_image = 0xAC2; |
627 v->cur_image = 0xAC2; |
628 v->random_bits = VehicleRandomBits(); |
628 v->random_bits = VehicleRandomBits(); |
629 |
629 |
630 AddArticulatedParts(vl); |
630 AddArticulatedParts(vl); |
631 |
631 |
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); |
1560 } |
1560 } |
1561 |
1561 |
1562 /* Check if the vehicle is a train and is on the tile we are testing */ |
1562 /* Check if the vehicle is a train and is on the tile we are testing */ |
1563 static void *TestTrainOnCrossing(Vehicle *v, void *data) |
1563 static void *TestTrainOnCrossing(Vehicle *v, void *data) |
1564 { |
1564 { |
1565 if (v->tile != *(const TileIndex*)data || v->type != VEH_Train) return NULL; |
1565 if (v->tile != *(const TileIndex*)data || v->type != VEH_TRAIN) return NULL; |
1566 return v; |
1566 return v; |
1567 } |
1567 } |
1568 |
1568 |
1569 static void DisableTrainCrossing(TileIndex tile) |
1569 static void DisableTrainCrossing(TileIndex tile) |
1570 { |
1570 { |
1667 { |
1667 { |
1668 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1668 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1669 |
1669 |
1670 Vehicle *v = GetVehicle(p1); |
1670 Vehicle *v = GetVehicle(p1); |
1671 |
1671 |
1672 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1672 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1673 |
1673 |
1674 if (p2) { |
1674 if (p2) { |
1675 // turn a single unit around |
1675 // turn a single unit around |
1676 |
1676 |
1677 if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) { |
1677 if (IsMultiheaded(v) || HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_ARTIC_ENGINE)) { |
1738 |
1738 |
1739 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1739 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1740 |
1740 |
1741 Vehicle *v = GetVehicle(p1); |
1741 Vehicle *v = GetVehicle(p1); |
1742 |
1742 |
1743 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1743 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1744 if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED); |
1744 if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED); |
1745 |
1745 |
1746 /* Check cargo */ |
1746 /* Check cargo */ |
1747 if (new_cid > NUM_CARGO) return CMD_ERROR; |
1747 if (new_cid > NUM_CARGO) return CMD_ERROR; |
1748 |
1748 |
1820 if (flags & DC_EXEC) TrainConsistChanged(GetFirstVehicleInChain(GetVehicle(p1))); |
1820 if (flags & DC_EXEC) TrainConsistChanged(GetFirstVehicleInChain(GetVehicle(p1))); |
1821 |
1821 |
1822 return cost; |
1822 return cost; |
1823 } |
1823 } |
1824 |
1824 |
1825 typedef struct TrainFindDepotData { |
1825 struct TrainFindDepotData { |
1826 uint best_length; |
1826 uint best_length; |
1827 TileIndex tile; |
1827 TileIndex tile; |
1828 PlayerID owner; |
1828 PlayerID owner; |
1829 /** |
1829 /** |
1830 * true if reversing is necessary for the train to get to this depot |
1830 * 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 |
1831 * This value is unused when new depot finding and NPF are both disabled |
1832 */ |
1832 */ |
1833 bool reverse; |
1833 bool reverse; |
1834 } TrainFindDepotData; |
1834 }; |
1835 |
1835 |
1836 static bool NtpCallbFindDepot(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length) |
1836 static bool NtpCallbFindDepot(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length) |
1837 { |
1837 { |
1838 if (IsTileType(tile, MP_RAILWAY) && |
1838 if (IsTileType(tile, MP_RAILWAY) && |
1839 IsTileOwner(tile, tfdd->owner) && |
1839 IsTileOwner(tile, tfdd->owner) && |
1916 int32 CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1916 int32 CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1917 { |
1917 { |
1918 if (p2 & DEPOT_MASS_SEND) { |
1918 if (p2 & DEPOT_MASS_SEND) { |
1919 /* Mass goto depot requested */ |
1919 /* Mass goto depot requested */ |
1920 if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR; |
1920 if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR; |
1921 return SendAllVehiclesToDepot(VEH_Train, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1); |
1921 return SendAllVehiclesToDepot(VEH_TRAIN, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1); |
1922 } |
1922 } |
1923 |
1923 |
1924 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1924 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1925 |
1925 |
1926 Vehicle *v = GetVehicle(p1); |
1926 Vehicle *v = GetVehicle(p1); |
1927 |
1927 |
1928 if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR; |
1928 if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR; |
1929 |
1929 |
1930 if (v->vehstatus & VS_CRASHED) return CMD_ERROR; |
1930 if (v->vehstatus & VS_CRASHED) return CMD_ERROR; |
1931 |
1931 |
1932 if (v->current_order.type == OT_GOTO_DEPOT) { |
1932 if (v->current_order.type == OT_GOTO_DEPOT) { |
1933 if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) { |
1933 if (!!(p2 & DEPOT_SERVICE) == HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT)) { |
2132 |
2132 |
2133 return false; |
2133 return false; |
2134 } |
2134 } |
2135 |
2135 |
2136 /* Check for station tiles */ |
2136 /* Check for station tiles */ |
2137 typedef struct TrainTrackFollowerData { |
2137 struct TrainTrackFollowerData { |
2138 TileIndex dest_coords; |
2138 TileIndex dest_coords; |
2139 StationID station_index; // station index we're heading for |
2139 StationID station_index; // station index we're heading for |
2140 uint best_bird_dist; |
2140 uint best_bird_dist; |
2141 uint best_track_dist; |
2141 uint best_track_dist; |
2142 TrackdirByte best_track; |
2142 TrackdirByte best_track; |
2143 } TrainTrackFollowerData; |
2143 }; |
2144 |
2144 |
2145 static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, Trackdir track, uint length) |
2145 static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, Trackdir track, uint length) |
2146 { |
2146 { |
2147 // heading for nowhere? |
2147 // heading for nowhere? |
2148 if (ttfd->dest_coords == 0) return false; |
2148 if (ttfd->dest_coords == 0) return false; |
2452 |
2452 |
2453 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
2453 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
2454 |
2454 |
2455 // If no order, do nothing. |
2455 // If no order, do nothing. |
2456 if (order == NULL) { |
2456 if (order == NULL) { |
2457 v->current_order.type = OT_NOTHING; |
2457 v->current_order.Free(); |
2458 v->current_order.flags = 0; |
|
2459 v->dest_tile = 0; |
2458 v->dest_tile = 0; |
2460 return false; |
2459 return false; |
2461 } |
2460 } |
2462 |
2461 |
2463 // If it is unchanged, keep it. |
2462 // If it is unchanged, keep it. |
2710 !IsFrontEngine(v) || |
2709 !IsFrontEngine(v) || |
2711 HASBIT(v->u.rail.compatible_railtypes, GetRailType(tile)) |
2710 HASBIT(v->u.rail.compatible_railtypes, GetRailType(tile)) |
2712 ); |
2711 ); |
2713 } |
2712 } |
2714 |
2713 |
2715 typedef struct { |
2714 struct RailtypeSlowdownParams { |
2716 byte small_turn, large_turn; |
2715 byte small_turn, large_turn; |
2717 byte z_up; // fraction to remove when moving up |
2716 byte z_up; // fraction to remove when moving up |
2718 byte z_down; // fraction to remove when moving down |
2717 byte z_down; // fraction to remove when moving down |
2719 } RailtypeSlowdownParams; |
2718 }; |
2720 |
2719 |
2721 static const RailtypeSlowdownParams _railtype_slowdown[] = { |
2720 static const RailtypeSlowdownParams _railtype_slowdown[] = { |
2722 // normal accel |
2721 // normal accel |
2723 {256 / 4, 256 / 2, 256 / 4, 2}, // normal |
2722 {256 / 4, 256 / 2, 256 / 4, 2}, // normal |
2724 {256 / 4, 256 / 2, 256 / 4, 2}, // electrified |
2723 {256 / 4, 256 / 2, 256 / 4, 2}, // electrified |
2766 UpdateSignalsOnSegment(tile, _otherside_signal_directions[i]); |
2765 UpdateSignalsOnSegment(tile, _otherside_signal_directions[i]); |
2767 } |
2766 } |
2768 } |
2767 } |
2769 |
2768 |
2770 |
2769 |
2771 typedef struct TrainCollideChecker { |
2770 struct TrainCollideChecker { |
2772 const Vehicle *v; |
2771 const Vehicle *v; |
2773 const Vehicle *v_skip; |
2772 const Vehicle *v_skip; |
2774 } TrainCollideChecker; |
2773 }; |
2775 |
2774 |
2776 static void *FindTrainCollideEnum(Vehicle *v, void *data) |
2775 static void *FindTrainCollideEnum(Vehicle *v, void *data) |
2777 { |
2776 { |
2778 const TrainCollideChecker* tcc = (TrainCollideChecker*)data; |
2777 const TrainCollideChecker* tcc = (TrainCollideChecker*)data; |
2779 |
2778 |
2780 if (v != tcc->v && |
2779 if (v != tcc->v && |
2781 v != tcc->v_skip && |
2780 v != tcc->v_skip && |
2782 v->type == VEH_Train && |
2781 v->type == VEH_TRAIN && |
2783 v->u.rail.track != TRACK_BIT_DEPOT && |
2782 v->u.rail.track != TRACK_BIT_DEPOT && |
2784 myabs(v->z_pos - tcc->v->z_pos) <= 6 && |
2783 myabs(v->z_pos - tcc->v->z_pos) <= 6 && |
2785 myabs(v->x_pos - tcc->v->x_pos) < 6 && |
2784 myabs(v->x_pos - tcc->v->x_pos) < 6 && |
2786 myabs(v->y_pos - tcc->v->y_pos) < 6) { |
2785 myabs(v->y_pos - tcc->v->y_pos) < 6) { |
2787 return v; |
2786 return v; |
2859 |
2858 |
2860 ModifyStationRatingAround(v->tile, v->owner, -160, 30); |
2859 ModifyStationRatingAround(v->tile, v->owner, -160, 30); |
2861 SndPlayVehicleFx(SND_13_BIG_CRASH, v); |
2860 SndPlayVehicleFx(SND_13_BIG_CRASH, v); |
2862 } |
2861 } |
2863 |
2862 |
2864 typedef struct VehicleAtSignalData { |
2863 struct VehicleAtSignalData { |
2865 TileIndex tile; |
2864 TileIndex tile; |
2866 Direction direction; |
2865 Direction direction; |
2867 } VehicleAtSignalData; |
2866 }; |
2868 |
2867 |
2869 static void *CheckVehicleAtSignal(Vehicle *v, void *data) |
2868 static void *CheckVehicleAtSignal(Vehicle *v, void *data) |
2870 { |
2869 { |
2871 const VehicleAtSignalData* vasd = (VehicleAtSignalData*)data; |
2870 const VehicleAtSignalData* vasd = (VehicleAtSignalData*)data; |
2872 |
2871 |
2873 if (v->type == VEH_Train && IsFrontEngine(v) && v->tile == vasd->tile) { |
2872 if (v->type == VEH_TRAIN && IsFrontEngine(v) && v->tile == vasd->tile) { |
2874 DirDiff diff = ChangeDirDiff(DirDifference(v->direction, vasd->direction), DIRDIFF_90RIGHT); |
2873 DirDiff diff = ChangeDirDiff(DirDifference(v->direction, vasd->direction), DIRDIFF_90RIGHT); |
2875 |
2874 |
2876 if (diff == DIRDIFF_90RIGHT || (v->cur_speed <= 5 && diff <= DIRDIFF_REVERSE)) return v; |
2875 if (diff == DIRDIFF_90RIGHT || (v->cur_speed <= 5 && diff <= DIRDIFF_REVERSE)) return v; |
2877 } |
2876 } |
2878 return NULL; |
2877 return NULL; |
2908 TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET); |
2907 TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET); |
2909 return; |
2908 return; |
2910 } |
2909 } |
2911 |
2910 |
2912 if (v->current_order.type == OT_LEAVESTATION) { |
2911 if (v->current_order.type == OT_LEAVESTATION) { |
2913 v->current_order.type = OT_NOTHING; |
2912 v->current_order.Free(); |
2914 v->current_order.flags = 0; |
|
2915 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2913 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2916 } |
2914 } |
2917 } |
2915 } |
2918 } else { |
2916 } else { |
2919 /* A new tile is about to be entered. */ |
2917 /* A new tile is about to be entered. */ |
3389 |
3387 |
3390 if (IsFrontEngine(v)) { |
3388 if (IsFrontEngine(v)) { |
3391 TrainLocoHandler(v, false); |
3389 TrainLocoHandler(v, false); |
3392 |
3390 |
3393 // make sure vehicle wasn't deleted. |
3391 // make sure vehicle wasn't deleted. |
3394 if (v->type == VEH_Train && IsFrontEngine(v)) |
3392 if (v->type == VEH_TRAIN && IsFrontEngine(v)) |
3395 TrainLocoHandler(v, true); |
3393 TrainLocoHandler(v, true); |
3396 } else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) { |
3394 } else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) { |
3397 // Delete flooded standalone wagon |
3395 // Delete flooded standalone wagon |
3398 if (++v->u.rail.crash_anim_pos >= 4400) |
3396 if (++v->u.rail.crash_anim_pos >= 4400) |
3399 DeleteVehicle(v); |
3397 DeleteVehicle(v); |
3493 InvalidateWindowClasses(WC_TRAINS_LIST); |
3491 InvalidateWindowClasses(WC_TRAINS_LIST); |
3494 } |
3492 } |
3495 } |
3493 } |
3496 } |
3494 } |
3497 |
3495 |
3498 void TrainsYearlyLoop(void) |
3496 void TrainsYearlyLoop() |
3499 { |
3497 { |
3500 Vehicle *v; |
3498 Vehicle *v; |
3501 |
3499 |
3502 FOR_ALL_VEHICLES(v) { |
3500 FOR_ALL_VEHICLES(v) { |
3503 if (v->type == VEH_Train && IsFrontEngine(v)) { |
3501 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) |
3502 // 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) { |
3503 if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->profit_this_year < 0) { |
3506 SetDParam(1, v->profit_this_year); |
3504 SetDParam(1, v->profit_this_year); |
3507 SetDParam(0, v->unitnumber); |
3505 SetDParam(0, v->unitnumber); |
3508 AddNewsItem( |
3506 AddNewsItem( |
3518 } |
3516 } |
3519 } |
3517 } |
3520 } |
3518 } |
3521 |
3519 |
3522 |
3520 |
3523 void InitializeTrains(void) |
3521 void InitializeTrains() |
3524 { |
3522 { |
3525 _age_cargo_skip_counter = 1; |
3523 _age_cargo_skip_counter = 1; |
3526 } |
3524 } |
3527 |
3525 |
3528 /* |
3526 /* |
3529 * Link front and rear multiheaded engines to each other |
3527 * Link front and rear multiheaded engines to each other |
3530 * This is done when loading a savegame |
3528 * This is done when loading a savegame |
3531 */ |
3529 */ |
3532 void ConnectMultiheadedTrains(void) |
3530 void ConnectMultiheadedTrains() |
3533 { |
3531 { |
3534 Vehicle *v; |
3532 Vehicle *v; |
3535 |
3533 |
3536 FOR_ALL_VEHICLES(v) { |
3534 FOR_ALL_VEHICLES(v) { |
3537 if (v->type == VEH_Train) { |
3535 if (v->type == VEH_TRAIN) { |
3538 v->u.rail.other_multiheaded_part = NULL; |
3536 v->u.rail.other_multiheaded_part = NULL; |
3539 } |
3537 } |
3540 } |
3538 } |
3541 |
3539 |
3542 FOR_ALL_VEHICLES(v) { |
3540 FOR_ALL_VEHICLES(v) { |
3543 if (v->type == VEH_Train && IsFrontEngine(v)) { |
3541 if (v->type == VEH_TRAIN && IsFrontEngine(v)) { |
3544 Vehicle *u = v; |
3542 Vehicle *u = v; |
3545 |
3543 |
3546 BEGIN_ENUM_WAGONS(u) { |
3544 BEGIN_ENUM_WAGONS(u) { |
3547 if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one |
3545 if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one |
3548 |
3546 |
3575 |
3573 |
3576 /* |
3574 /* |
3577 * Converts all trains to the new subtype format introduced in savegame 16.2 |
3575 * 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 |
3576 * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found |
3579 */ |
3577 */ |
3580 void ConvertOldMultiheadToNew(void) |
3578 void ConvertOldMultiheadToNew() |
3581 { |
3579 { |
3582 Vehicle *v; |
3580 Vehicle *v; |
3583 FOR_ALL_VEHICLES(v) { |
3581 FOR_ALL_VEHICLES(v) { |
3584 if (v->type == VEH_Train) { |
3582 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 |
3583 SETBIT(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop |
3586 } |
3584 } |
3587 } |
3585 } |
3588 |
3586 |
3589 FOR_ALL_VEHICLES(v) { |
3587 FOR_ALL_VEHICLES(v) { |
3590 if (v->type == VEH_Train) { |
3588 if (v->type == VEH_TRAIN) { |
3591 if (HASBIT(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) { |
3589 if (HASBIT(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) { |
3592 Vehicle *u = v; |
3590 Vehicle *u = v; |
3593 |
3591 |
3594 BEGIN_ENUM_WAGONS(u) { |
3592 BEGIN_ENUM_WAGONS(u) { |
3595 const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); |
3593 const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); |