src/train_cmd.cpp
branchgamebalance
changeset 9913 e79cd19772dd
parent 9912 1ac8aac92385
equal deleted inserted replaced
9912:1ac8aac92385 9913:e79cd19772dd
   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 
  1704 	/* Check cargo */
  1704 	/* Check cargo */
  1705 	if (new_cid >= NUM_CARGO) return CMD_ERROR;
  1705 	if (new_cid >= NUM_CARGO) return CMD_ERROR;
  1706 
  1706 
  1707 	SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN);
  1707 	SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN);
  1708 
  1708 
  1709 	int32 cost = 0;
  1709 	CommandCost cost = 0;
  1710 	uint num = 0;
  1710 	uint num = 0;
  1711 
  1711 
  1712 	do {
  1712 	do {
  1713 		/* XXX: We also refit all the attached wagons en-masse if they
  1713 		/* XXX: We also refit all the attached wagons en-masse if they
  1714 		 * can be refitted. This is how TTDPatch does it.  TODO: Have
  1714 		 * can be refitted. This is how TTDPatch does it.  TODO: Have
  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);