summaryrefslogtreecommitdiff
path: root/src/vehicle_gui.cpp
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2009-12-14 19:17:18 +0000
committerrubidium <rubidium@openttd.org>2009-12-14 19:17:18 +0000
commita190ae9a71cd51d50c03be53d7695b8b85f2bdc0 (patch)
tree9839c6593863802f54fd6ce0d3cdd3201c94e317 /src/vehicle_gui.cpp
parent620ca5e6c18cc0929f255d5ced094f214c6df15a (diff)
downloadopenttd-a190ae9a71cd51d50c03be53d7695b8b85f2bdc0.tar.xz
(svn r18498) -Fix [FS#2616]: cloning of vehicles could create vehicles with invalid cargo sub types for the build year of the vehicle. Fall back to another cargo sub type with the exact same name, otherwise fallback to cargo sub type 0.
Diffstat (limited to 'src/vehicle_gui.cpp')
-rw-r--r--src/vehicle_gui.cpp63
1 files changed, 63 insertions, 0 deletions
diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp
index 614259e34..a9401784f 100644
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -159,6 +159,69 @@ static void DrawVehicleProfitButton(const Vehicle *v, int x, int y)
/** Maximum number of refit cycles we try, to prevent infinite loops. */
static const int MAX_REFIT_CYCLE = 16;
+/**
+ * Get the best fitting subtype when 'cloning'/'replacing' v_from with v_for.
+ * Assuming they are going to carry the same cargo ofcourse!
+ * @param v_from the vehicle to match the subtype from
+ * @param v_for the vehicle to get the subtype for
+ * @return the best sub type
+ */
+byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for)
+{
+ const Engine *e_from = Engine::Get(v_from->engine_type);
+ const Engine *e_for = Engine::Get(v_for->engine_type);
+
+ /* If one them doesn't carry cargo, there's no need to find a sub type */
+ if (!e_from->CanCarryCargo() || !e_for->CanCarryCargo()) return 0;
+
+ if (!HasBit(e_from->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX) ||
+ !HasBit(e_for->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) {
+ /* One of the engines doesn't have cargo suffixes, i.e. sub types. */
+ return 0;
+ }
+
+ /* It has to be possible for v_for to carry the cargo of v_from. */
+ assert(HasBit(e_for->info.refit_mask, v_from->cargo_type));
+
+ StringID expected_string = GetCargoSubtypeText(v_from);
+
+ CargoID old_cargo_type = v_for->cargo_type;
+ byte old_cargo_subtype = v_for->cargo_subtype;
+ byte ret_refit_cyc = 0;
+
+ /* Set the 'destination' cargo */
+ v_for->cargo_type = v_from->cargo_type;
+
+ /* Cycle through the refits */
+ for (byte refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) {
+ v_for->cargo_subtype = refit_cyc;
+
+ /* Make sure we don't pick up anything cached. */
+ v_for->First()->InvalidateNewGRFCache();
+ v_for->InvalidateNewGRFCache();
+ uint16 callback = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, v_for->engine_type, v_for);
+
+ if (callback == 0xFF) callback = CALLBACK_FAILED;
+ if (callback == CALLBACK_FAILED) break;
+
+ if (GetCargoSubtypeText(v_for) != expected_string) continue;
+
+ /* We found something matching. */
+ ret_refit_cyc = refit_cyc;
+ break;
+ }
+
+ /* Reset the vehicle's cargo type */
+ v_for->cargo_type = old_cargo_type;
+ v_for->cargo_subtype = old_cargo_subtype;
+
+ /* Make sure we don't taint the vehicle. */
+ v_for->First()->InvalidateNewGRFCache();
+ v_for->InvalidateNewGRFCache();
+
+ return ret_refit_cyc;
+}
+
struct RefitOption {
CargoID cargo;
byte subtype;