500 } |
500 } |
501 } |
501 } |
502 DrawSprite(image, pal, x, y); |
502 DrawSprite(image, pal, x, y); |
503 } |
503 } |
504 |
504 |
505 static int32 CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags) |
505 static CommandCost CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags) |
506 { |
506 { |
507 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
507 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
508 |
508 |
509 const RailVehicleInfo *rvi = RailVehInfo(engine); |
509 const RailVehicleInfo *rvi = RailVehInfo(engine); |
510 int32 value = (GetEngineProperty(engine, 0x17, rvi->base_cost) * _eco->GetPrice(CEconomy::BUILD_RAILWAGON)) >> 8; |
510 CommandCost value = (GetEngineProperty(engine, 0x17, rvi->base_cost) * _eco->GetPrice(CEconomy::BUILD_RAILWAGON)) >> 8; |
511 |
511 |
512 uint num_vehicles = 1 + CountArticulatedParts(engine); |
512 uint num_vehicles = 1 + CountArticulatedParts(engine); |
513 |
513 |
514 if (!(flags & DC_QUERY_COST)) { |
514 if (!(flags & DC_QUERY_COST)) { |
515 Vehicle *vl[11]; // Allow for wagon and upto 10 artic parts. |
515 Vehicle *vl[11]; // Allow for wagon and upto 10 artic parts. |
609 break; |
609 break; |
610 } |
610 } |
611 } |
611 } |
612 } |
612 } |
613 |
613 |
614 static int32 EstimateTrainCost(EngineID engine, const RailVehicleInfo* rvi) |
614 static CommandCost EstimateTrainCost(EngineID engine, const RailVehicleInfo* rvi) |
615 { |
615 { |
616 return GetEngineProperty(engine, 0x17, rvi->base_cost) * (_eco->GetPrice(CEconomy::BUILD_RAILVEHICLE) >> 3) >> 5; |
616 return GetEngineProperty(engine, 0x17, rvi->base_cost) * (_eco->GetPrice(CEconomy::BUILD_RAILVEHICLE) >> 3) >> 5; |
617 } |
617 } |
618 |
618 |
619 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building) |
619 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building) |
649 * @param flags type of operation |
649 * @param flags type of operation |
650 * @param p1 engine type id |
650 * @param p1 engine type id |
651 * @param p2 bit 0 when set, the train will get number 0, otherwise it will get a free number |
651 * @param p2 bit 0 when set, the train will get number 0, otherwise it will get a free number |
652 * bit 1 prevents any free cars from being added to the train |
652 * bit 1 prevents any free cars from being added to the train |
653 */ |
653 */ |
654 int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
654 CommandCost CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
655 { |
655 { |
656 /* Check if the engine-type is valid (for the player) */ |
656 /* Check if the engine-type is valid (for the player) */ |
657 if (!IsEngineBuildable(p1, VEH_TRAIN, _current_player)) return_cmd_error(STR_RAIL_VEHICLE_NOT_AVAILABLE); |
657 if (!IsEngineBuildable(p1, VEH_TRAIN, _current_player)) return_cmd_error(STR_RAIL_VEHICLE_NOT_AVAILABLE); |
658 |
658 |
659 /* Check if the train is actually being built in a depot belonging |
659 /* Check if the train is actually being built in a depot belonging |
671 /* We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */ |
671 /* We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */ |
672 if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; |
672 if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; |
673 |
673 |
674 if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags); |
674 if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags); |
675 |
675 |
676 int32 value = EstimateTrainCost(p1, rvi); |
676 CommandCost value = EstimateTrainCost(p1, rvi); |
677 |
677 |
678 uint num_vehicles = |
678 uint num_vehicles = |
679 (rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + |
679 (rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + |
680 CountArticulatedParts(p1); |
680 CountArticulatedParts(p1); |
681 |
681 |
907 * @param p1 various bitstuffed elements |
907 * @param p1 various bitstuffed elements |
908 * - p1 (bit 0 - 15) source vehicle index |
908 * - p1 (bit 0 - 15) source vehicle index |
909 * - p1 (bit 16 - 31) what wagon to put the source wagon AFTER, XXX - INVALID_VEHICLE to make a new line |
909 * - p1 (bit 16 - 31) what wagon to put the source wagon AFTER, XXX - INVALID_VEHICLE to make a new line |
910 * @param p2 (bit 0) move all vehicles following the source vehicle |
910 * @param p2 (bit 0) move all vehicles following the source vehicle |
911 */ |
911 */ |
912 int32 CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
912 CommandCost CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
913 { |
913 { |
914 VehicleID s = GB(p1, 0, 16); |
914 VehicleID s = GB(p1, 0, 16); |
915 VehicleID d = GB(p1, 16, 16); |
915 VehicleID d = GB(p1, 16, 16); |
916 |
916 |
917 if (!IsValidVehicleID(s)) return CMD_ERROR; |
917 if (!IsValidVehicleID(s)) return CMD_ERROR; |
1160 * @param tile unused |
1160 * @param tile unused |
1161 * @param flags type of operation |
1161 * @param flags type of operation |
1162 * @param p1 train to start/stop |
1162 * @param p1 train to start/stop |
1163 * @param p2 unused |
1163 * @param p2 unused |
1164 */ |
1164 */ |
1165 int32 CmdStartStopTrain(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1165 CommandCost CmdStartStopTrain(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1166 { |
1166 { |
1167 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1167 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1168 |
1168 |
1169 Vehicle *v = GetVehicle(p1); |
1169 Vehicle *v = GetVehicle(p1); |
1170 |
1170 |
1201 * - p2 = 1: sell the vehicle and all vehicles following it in the chain |
1201 * - p2 = 1: sell the vehicle and all vehicles following it in the chain |
1202 if the wagon is dragged, don't delete the possibly belonging rear-engine to some front |
1202 if the wagon is dragged, don't delete the possibly belonging rear-engine to some front |
1203 * - p2 = 2: when selling attached locos, rearrange all vehicles after it to separate lines; |
1203 * - p2 = 2: when selling attached locos, rearrange all vehicles after it to separate lines; |
1204 * all wagons of the same type will go on the same line. Used by the AI currently |
1204 * all wagons of the same type will go on the same line. Used by the AI currently |
1205 */ |
1205 */ |
1206 int32 CmdSellRailWagon(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1206 CommandCost CmdSellRailWagon(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1207 { |
1207 { |
1208 /* Check if we deleted a vehicle window */ |
1208 /* Check if we deleted a vehicle window */ |
1209 Window *w = NULL; |
1209 Window *w = NULL; |
1210 |
1210 |
1211 if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR; |
1211 if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR; |
1233 } |
1233 } |
1234 InvalidateWindow(WC_VEHICLE_DEPOT, first->tile); |
1234 InvalidateWindow(WC_VEHICLE_DEPOT, first->tile); |
1235 RebuildVehicleLists(); |
1235 RebuildVehicleLists(); |
1236 } |
1236 } |
1237 |
1237 |
1238 int32 cost = 0; |
1238 CommandCost cost = 0; |
1239 switch (p2) { |
1239 switch (p2) { |
1240 case 0: case 2: { /* Delete given wagon */ |
1240 case 0: case 2: { /* Delete given wagon */ |
1241 bool switch_engine = false; // update second wagon to engine? |
1241 bool switch_engine = false; // update second wagon to engine? |
1242 byte ori_subtype = v->subtype; // backup subtype of deleted wagon in case DeleteVehicle() changes |
1242 byte ori_subtype = v->subtype; // backup subtype of deleted wagon in case DeleteVehicle() changes |
1243 |
1243 |
1614 * @param tile unused |
1614 * @param tile unused |
1615 * @param flags type of operation |
1615 * @param flags type of operation |
1616 * @param p1 train to reverse |
1616 * @param p1 train to reverse |
1617 * @param p2 if true, reverse a unit in a train (needs to be in a depot) |
1617 * @param p2 if true, reverse a unit in a train (needs to be in a depot) |
1618 */ |
1618 */ |
1619 int32 CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1619 CommandCost CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1620 { |
1620 { |
1621 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1621 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1622 |
1622 |
1623 Vehicle *v = GetVehicle(p1); |
1623 Vehicle *v = GetVehicle(p1); |
1624 |
1624 |
1663 * @param tile unused |
1663 * @param tile unused |
1664 * @param flags type of operation |
1664 * @param flags type of operation |
1665 * @param p1 train to ignore the red signal |
1665 * @param p1 train to ignore the red signal |
1666 * @param p2 unused |
1666 * @param p2 unused |
1667 */ |
1667 */ |
1668 int32 CmdForceTrainProceed(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1668 CommandCost CmdForceTrainProceed(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1669 { |
1669 { |
1670 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1670 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1671 |
1671 |
1672 Vehicle *v = GetVehicle(p1); |
1672 Vehicle *v = GetVehicle(p1); |
1673 |
1673 |
1686 * - p2 = (bit 0-7) - the new cargo type to refit to |
1686 * - p2 = (bit 0-7) - the new cargo type to refit to |
1687 * - p2 = (bit 8-15) - the new cargo subtype to refit to |
1687 * - p2 = (bit 8-15) - the new cargo subtype to refit to |
1688 * - p2 = (bit 16) - refit only this vehicle |
1688 * - p2 = (bit 16) - refit only this vehicle |
1689 * @return cost of refit or error |
1689 * @return cost of refit or error |
1690 */ |
1690 */ |
1691 int32 CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1691 CommandCost CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1692 { |
1692 { |
1693 CargoID new_cid = GB(p2, 0, 8); |
1693 CargoID new_cid = GB(p2, 0, 8); |
1694 byte new_subtype = GB(p2, 8, 8); |
1694 byte new_subtype = GB(p2, 8, 8); |
1695 bool only_this = HASBIT(p2, 16); |
1695 bool only_this = HASBIT(p2, 16); |
1696 |
1696 |
1870 * @param p1 train to send to the depot |
1870 * @param p1 train to send to the depot |
1871 * @param p2 various bitmasked elements |
1871 * @param p2 various bitmasked elements |
1872 * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h) |
1872 * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h) |
1873 * - p2 bit 8-10 - VLW flag (for mass goto depot) |
1873 * - p2 bit 8-10 - VLW flag (for mass goto depot) |
1874 */ |
1874 */ |
1875 int32 CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1875 CommandCost CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1876 { |
1876 { |
1877 if (p2 & DEPOT_MASS_SEND) { |
1877 if (p2 & DEPOT_MASS_SEND) { |
1878 /* Mass goto depot requested */ |
1878 /* Mass goto depot requested */ |
1879 if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR; |
1879 if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR; |
1880 return SendAllVehiclesToDepot(VEH_TRAIN, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1); |
1880 return SendAllVehiclesToDepot(VEH_TRAIN, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1); |
2720 TrainCollideChecker tcc; |
2720 TrainCollideChecker tcc; |
2721 tcc.v = v; |
2721 tcc.v = v; |
2722 tcc.v_skip = v->next; |
2722 tcc.v_skip = v->next; |
2723 |
2723 |
2724 /* find colliding vehicle */ |
2724 /* find colliding vehicle */ |
2725 Vehicle *realcoll = (Vehicle*)VehicleFromPos(TileVirtXY(v->x_pos, v->y_pos), &tcc, FindTrainCollideEnum); |
2725 Vehicle *realcoll = (Vehicle*)VehicleFromPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum); |
2726 if (realcoll == NULL) return; |
2726 if (realcoll == NULL) return; |
2727 |
2727 |
2728 Vehicle *coll = GetFirstVehicleInChain(realcoll); |
2728 Vehicle *coll = GetFirstVehicleInChain(realcoll); |
2729 |
2729 |
2730 /* it can't collide with its own wagons */ |
2730 /* it can't collide with its own wagons */ |
2731 if (v == coll || |
2731 if (v == coll || |
2732 (v->u.rail.track == TRACK_BIT_WORMHOLE && (v->direction & 2) != (realcoll->direction & 2))) |
2732 (v->u.rail.track == TRACK_BIT_WORMHOLE && (v->direction & 2) != (realcoll->direction & 2))) |
2733 return; |
2733 return; |
2734 |
2734 |
2735 /* two drivers + passangers killed in train v */ |
2735 /* two drivers + passengers killed in train v */ |
2736 uint num = 2 + CountPassengersInTrain(v); |
2736 uint num = 2 + CountPassengersInTrain(v); |
2737 if (!(coll->vehstatus & VS_CRASHED)) |
2737 if (!(coll->vehstatus & VS_CRASHED)) |
2738 /* two drivers + passangers killed in train coll (if it was not crashed already) */ |
2738 /* two drivers + passengers killed in train coll (if it was not crashed already) */ |
2739 num += 2 + CountPassengersInTrain(coll); |
2739 num += 2 + CountPassengersInTrain(coll); |
2740 |
2740 |
2741 SetVehicleCrashed(v); |
2741 SetVehicleCrashed(v); |
2742 if (IsFrontEngine(coll)) SetVehicleCrashed(coll); |
2742 if (IsFrontEngine(coll)) SetVehicleCrashed(coll); |
2743 |
2743 |
2773 { |
2773 { |
2774 Vehicle *prev; |
2774 Vehicle *prev; |
2775 |
2775 |
2776 /* For every vehicle after and including the given vehicle */ |
2776 /* For every vehicle after and including the given vehicle */ |
2777 for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) { |
2777 for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) { |
|
2778 DiagDirection enterdir = DIAGDIR_BEGIN; |
|
2779 bool update_signals = false; |
2778 BeginVehicleMove(v); |
2780 BeginVehicleMove(v); |
2779 |
2781 |
2780 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
2782 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
2781 if (v->u.rail.track != TRACK_BIT_WORMHOLE) { |
2783 if (v->u.rail.track != TRACK_BIT_WORMHOLE) { |
2782 /* Not inside tunnel */ |
2784 /* Not inside tunnel */ |
2808 } else { |
2810 } else { |
2809 /* A new tile is about to be entered. */ |
2811 /* A new tile is about to be entered. */ |
2810 |
2812 |
2811 /* Determine what direction we're entering the new tile from */ |
2813 /* Determine what direction we're entering the new tile from */ |
2812 Direction dir = GetNewVehicleDirectionByTile(gp.new_tile, gp.old_tile); |
2814 Direction dir = GetNewVehicleDirectionByTile(gp.new_tile, gp.old_tile); |
2813 DiagDirection enterdir = DirToDiagDir(dir); |
2815 enterdir = DirToDiagDir(dir); |
2814 assert(IsValidDiagDirection(enterdir)); |
2816 assert(IsValidDiagDirection(enterdir)); |
2815 |
2817 |
2816 /* Get the status of the tracks in the new tile and mask |
2818 /* Get the status of the tracks in the new tile and mask |
2817 * away the bits that aren't reachable. */ |
2819 * away the bits that aren't reachable. */ |
2818 uint32 ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0) & _reachable_tracks[enterdir]; |
2820 uint32 ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0) & _reachable_tracks[enterdir]; |
2915 |
2917 |
2916 v->u.rail.track = chosen_track; |
2918 v->u.rail.track = chosen_track; |
2917 assert(v->u.rail.track); |
2919 assert(v->u.rail.track); |
2918 } |
2920 } |
2919 |
2921 |
2920 if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir); |
2922 /* We need to update signal status, but after the vehicle position hash |
2921 |
2923 * has been updated by AfterSetTrainPos() */ |
2922 /* Signals can only change when the first |
2924 update_signals = true; |
2923 * (above) or the last vehicle moves. */ |
|
2924 if (v->next == NULL) TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); |
|
2925 |
2925 |
2926 if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir); |
2926 if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir); |
2927 |
2927 |
2928 v->direction = chosen_dir; |
2928 v->direction = chosen_dir; |
2929 } |
2929 } |
2955 byte old_z = AfterSetTrainPos(v, (gp.new_tile != gp.old_tile)); |
2955 byte old_z = AfterSetTrainPos(v, (gp.new_tile != gp.old_tile)); |
2956 |
2956 |
2957 if (prev == NULL) { |
2957 if (prev == NULL) { |
2958 /* This is the first vehicle in the train */ |
2958 /* This is the first vehicle in the train */ |
2959 AffectSpeedByZChange(v, old_z); |
2959 AffectSpeedByZChange(v, old_z); |
|
2960 } |
|
2961 |
|
2962 if (update_signals) { |
|
2963 if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir); |
|
2964 |
|
2965 /* Signals can only change when the first |
|
2966 * (above) or the last vehicle moves. */ |
|
2967 if (v->next == NULL) TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); |
2960 } |
2968 } |
2961 } |
2969 } |
2962 return; |
2970 return; |
2963 |
2971 |
2964 invalid_rail: |
2972 invalid_rail: |
3385 if (tile != 0) v->dest_tile = tile; |
3393 if (tile != 0) v->dest_tile = tile; |
3386 } |
3394 } |
3387 |
3395 |
3388 if ((v->vehstatus & VS_STOPPED) == 0) { |
3396 if ((v->vehstatus & VS_STOPPED) == 0) { |
3389 /* running costs */ |
3397 /* running costs */ |
3390 int32 cost = GetTrainRunningCost(v) / 364; |
3398 CommandCost cost = GetTrainRunningCost(v) / 364; |
3391 |
3399 |
3392 v->profit_this_year -= cost >> 8; |
3400 v->profit_this_year -= cost >> 8; |
3393 |
3401 |
3394 SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN); |
3402 SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN); |
3395 SubtractMoneyFromPlayerFract(v->owner, cost); |
3403 SubtractMoneyFromPlayerFract(v->owner, cost); |