changeset 2611:d533d740bad1 draft

(svn r3148) -NewGRF, Feature: Add support for cargo refitting specification by cargo classes.
author peter1138 <peter1138@openttd.org>
date Sun, 06 Nov 2005 13:42:26 +0000
parents ce441a33fa17
children fba1eca4ee92
files engine.c engine.h newgrf.c table/engines.h train_gui.c vehicle.c vehicle_gui.c
diffstat 7 files changed, 110 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/engine.c
+++ b/engine.c
@@ -58,10 +58,10 @@
 const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE] =
 { /* LT_NORMAL: temperate */
 	MC(GC_PASSENGERS)|MC(GC_COAL)|MC(GC_MAIL)|MC(GC_OIL)|MC(GC_LIVESTOCK)|MC(GC_GOODS)|MC(GC_GRAIN)|MC(GC_WOOD)|
-	MC(GC_IRON_ORE)|MC(GC_STEEL)|MC(GC_VALUABLES)|MC(GC_FOOD)|MC(GC_UNDEFINED),
+	MC(GC_IRON_ORE)|MC(GC_STEEL)|MC(GC_VALUABLES),
 	/* LT_HILLY: arctic */
 	MC(GC_PASSENGERS)|MC(GC_COAL)|MC(GC_MAIL)|MC(GC_OIL)|MC(GC_LIVESTOCK)|MC(GC_GOODS)|
-	MC(GC_GRAIN)|MC(GC_WOOD)|MC(GC_VALUABLES)|MC(GC_PAPER)|MC(GC_FOOD)|MC(GC_UNDEFINED),
+	MC(GC_GRAIN)|MC(GC_WOOD)|MC(GC_VALUABLES)|MC(GC_PAPER)|MC(GC_FOOD),
 	/* LT_DESERT: rainforest/desert */
 	MC(GC_PASSENGERS)|MC(GC_MAIL)|MC(GC_OIL)|MC(GC_GOODS)|MC(GC_GRAIN)|MC(GC_WOOD)|
 	MC(GC_VALUABLES)|MC(GC_FOOD)|MC(GC_FRUIT)|MC(GC_COPPER_ORE)|MC(GC_WATER)|MC(GC_RUBBER),
@@ -91,6 +91,21 @@
 	/* Special/Disaster */
 	0,0
 };
+
+/**
+ * Bitmask of classes for cargo types.
+ */
+const uint32 cargo_classes[16] = {
+	/* Passengers */ MC(GC_PASSENGERS),
+	/* Mail       */ MC(GC_MAIL),
+	/* Express    */ MC(GC_GOODS)|MC(GC_FOOD)|MC(GC_CANDY),
+	/* Armoured   */ MC(GC_VALUABLES),
+	/* Bulk       */ MC(GC_COAL)|MC(GC_GRAIN)|MC(GC_IRON_ORE)|MC(GC_COPPER_ORE)|MC(GC_FRUIT)|MC(GC_SUGAR)|MC(GC_TOFFEE)|MC(GC_COTTON_CANDY),
+	/* Piece      */ MC(GC_LIVESTOCK)|MC(GC_WOOD)|MC(GC_STEEL)|MC(GC_PAPER)|MC(GC_TOYS)|MC(GC_BATTERIES)|MC(GC_BUBBLES)|MC(GC_FIZZY_DRINKS),
+	/* Liquids    */ MC(GC_OIL)|MC(GC_WATER)|MC(GC_RUBBER)|MC(GC_COLA)|MC(GC_PLASTIC),
+	/* Chilled    */ MC(GC_FOOD)|MC(GC_FRUIT),
+	/* Undefined  */ 0, 0, 0, 0, 0, 0, 0, 0
+};
 #undef MC
 
 void ShowEnginePreviewWindow(EngineID engine);
@@ -232,9 +247,6 @@
 	AdjustAvailAircraft();
 }
 
-uint32 _engine_refit_masks[TOTAL_NUM_ENGINES];
-
-
 // TODO: We don't support cargo-specific wagon overrides. Pretty exotic... ;-) --pasky
 
 typedef struct WagonOverride {
--- a/engine.h
+++ b/engine.h
@@ -72,6 +72,7 @@
 	byte base_life;
 	byte railtype:4;
 	byte climates:4;
+	uint32 refit_mask;
 } EngineInfo;
 
 typedef struct Engine {
@@ -174,8 +175,8 @@
 VARDEF const CargoID _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
 VARDEF const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE];
 VARDEF const CargoID _local_cargo_id_ctype[NUM_GLOBAL_CID];
+VARDEF const uint32 cargo_classes[16];
 
-VARDEF uint32 _engine_refit_masks[256];
 void SetWagonOverrideSprites(EngineID engine, struct SpriteGroup *group, byte *train_id, int trains);
 void SetCustomEngineSprites(EngineID engine, byte cargo, struct SpriteGroup *group);
 // loaded is in percents, overriding_engine 0xffff is none
--- a/newgrf.c
+++ b/newgrf.c
@@ -72,6 +72,8 @@
 	/* GSF_AIRCRAFT */ AIRCRAFT_ENGINES_INDEX,
 };
 
+static uint16 cargo_allowed[TOTAL_NUM_ENGINES];
+static uint16 cargo_disallowed[TOTAL_NUM_ENGINES];
 
 /* Debugging messages policy:
  *
@@ -352,7 +354,7 @@
 			FOR_EACH_OBJECT {
 				uint32 refit_mask = grf_load_dword(&buf);
 
-				_engine_refit_masks[engine + i] = refit_mask;
+				_engine_info[engine + i].refit_mask = refit_mask;
 			}
 		} break;
 		case 0x1E: { /* Callback */
@@ -395,6 +397,16 @@
 				}
 			}
 		} break;
+		case 0x28: { /* Cargo classes allowed */
+			FOR_EACH_OBJECT {
+				cargo_allowed[engine + i] = grf_load_word(&buf);
+			}
+		} break;
+		case 0x29: { /* Cargo classes disallowed */
+			FOR_EACH_OBJECT {
+				cargo_disallowed[engine + i] = grf_load_word(&buf);
+			}
+		} break;
 		/* TODO */
 		/* Fall-through for unimplemented one byte long properties. */
 		case 0x1A:	/* Sort order */
@@ -499,7 +511,17 @@
 			FOR_EACH_OBJECT {
 				uint32 refit_mask = grf_load_dword(&buf);
 
-				_engine_refit_masks[ROAD_ENGINES_INDEX + engine + i] = refit_mask;
+				_engine_info[ROAD_ENGINES_INDEX + engine + i].refit_mask = refit_mask;
+			}
+		} break;
+		case 0x1D: { /* Cargo classes allowed */
+			FOR_EACH_OBJECT {
+				cargo_allowed[ROAD_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			}
+		} break;
+		case 0x1E: { /* Cargo classes disallowed */
+			FOR_EACH_OBJECT {
+				cargo_disallowed[ROAD_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
 			}
 		} break;
 		case 0x17:      /* Callback */
@@ -507,6 +529,7 @@
 		case 0x19:      /* Air drag */
 		case 0x1A:      /* Refit cost */
 		case 0x1B:      /* Retire vehicle early */
+		case 0x1C:      /* Miscellaneous flags */
 			{
 			/* TODO */
 			FOR_EACH_OBJECT {
@@ -602,14 +625,25 @@
 			FOR_EACH_OBJECT {
 				uint32 refit_mask = grf_load_dword(&buf);
 
-				_engine_refit_masks[SHIP_ENGINES_INDEX + engine + i] = refit_mask;
+				_engine_info[SHIP_ENGINES_INDEX + engine + i].refit_mask = refit_mask;
 			}
 		}	break;
+		case 0x18: { /* Cargo classes allowed */
+			FOR_EACH_OBJECT {
+				cargo_allowed[SHIP_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			}
+		} break;
+		case 0x19: { /* Cargo classes disallowed */
+			FOR_EACH_OBJECT {
+				cargo_disallowed[SHIP_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			}
+		} break;
 		case 0x12: /* Callback */
 		case 0x13: /* Refit cost */
 		case 0x14: /* Ocean speed fraction */
 		case 0x15: /* Canal speed fraction */
 		case 0x16: /* Retire vehicle early */
+		case 0x17: /* Miscellaneous flags */
 		{
 			/* TODO */
 			FOR_EACH_OBJECT {
@@ -711,12 +745,23 @@
 			FOR_EACH_OBJECT {
 				uint32 refit_mask = grf_load_dword(&buf);
 
-				_engine_refit_masks[AIRCRAFT_ENGINES_INDEX + engine + i] = refit_mask;
+				_engine_info[AIRCRAFT_ENGINES_INDEX + engine + i].refit_mask = refit_mask;
 			}
 		}	break;
+		case 0x18: { /* Cargo classes allowed */
+			FOR_EACH_OBJECT {
+				cargo_allowed[AIRCRAFT_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			}
+		} break;
+		case 0x19: { /* Cargo classes disallowed */
+			FOR_EACH_OBJECT {
+				cargo_disallowed[AIRCRAFT_ENGINES_INDEX + engine + i] = grf_load_word(&buf);
+			}
+		} break;
 		case 0x14: /* Callback */
 		case 0x15: /* Refit cost */
 		case 0x16: /* Retire vehicle early */
+		case 0x17: /* Miscellaneous flags */
 		{
 			/* TODO */
 			FOR_EACH_OBJECT {
@@ -2375,6 +2420,10 @@
 	}
 	memcpy(&_bridge, &orig_bridge, sizeof(_bridge));
 
+	// Reset refit/cargo class data
+	memset(&cargo_allowed, 0, sizeof(cargo_allowed));
+	memset(&cargo_disallowed, 0, sizeof(cargo_disallowed));
+
 	// Unload sprite group data
 	UnloadWagonOverrides();
 	UnloadCustomEngineSprites();
@@ -2412,6 +2461,35 @@
 	}
 }
 
+/**
+ * Precalculate refit masks from cargo classes for all vehicles.
+ */
+static void CalculateRefitMasks(void)
+{
+	EngineID engine;
+
+	for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
+		uint32 mask = 0;
+		uint32 not_mask = 0;
+		uint32 xor_mask = _engine_info[engine].refit_mask;
+		byte i;
+
+		if (cargo_allowed[engine] != 0) {
+			// Build up the list of cargo types from the set cargo classes.
+			for (i = 0; i < lengthof(cargo_classes); i++) {
+				if (HASBIT(cargo_allowed[engine], i))
+					mask |= cargo_classes[i];
+				if (HASBIT(cargo_disallowed[engine], i))
+					not_mask |= cargo_classes[i];
+			}
+		} else {
+			// Don't apply default refit mask to wagons or engines with no capacity
+			if (xor_mask == 0 && !(GetEngine(engine)->type == VEH_Train && (RailVehInfo(engine)->capacity == 0 || RailVehInfo(engine)->flags & RVI_WAGON)))
+				xor_mask = _default_refitmasks[GetEngine(engine)->type - VEH_Train];
+		}
+		_engine_info[engine].refit_mask = ((mask & ~not_mask) ^ xor_mask) & _landscape_global_cargo_mask[_opt.landscape];
+	}
+}
 
 /* Here we perform initial decoding of some special sprites (as are they
  * described at http://www.ttdpatch.net/src/newgrf.txt, but this is only a very
@@ -2593,4 +2671,7 @@
 			DEBUG(spritecache, 2) ("Currently %i sprites are loaded", load_index);
 		}
 	}
+
+	// Pre-calculate all refit masks after loading GRF files
+	CalculateRefitMasks();
 }
--- a/table/engines.h
+++ b/table/engines.h
@@ -15,7 +15,7 @@
   * @param e Rail Type of the vehicle
   * @param f Bitmask of the climates
   */
-#define MK(a, b, c, d, e, f) { a, b, c, d, e, f }
+#define MK(a, b, c, d, e, f) { a, b, c, d, e, f, 0 }
 /** Writes the properties of a train carriage into the EngineInfo struct.
   * @see EngineInfo
   * @param a Introduction date
@@ -23,7 +23,7 @@
   * @param f Bitmask of the climates
   * @note the 0x80 in parameter b sets the "is carriage bit"
   */
-#define MW(a, b, c, d, e, f) { a, b | 0x80, c, d, e, f }
+#define MW(a, b, c, d, e, f) { a, b | 0x80, c, d, e, f, 0 }
 
 // Rail types
 // R = Conventional railway
--- a/train_gui.c
+++ b/train_gui.c
@@ -90,7 +90,7 @@
 void DrawTrainWagonPurchaseInfo(int x, int y, EngineID engine_number)
 {
 	const RailVehicleInfo *rvi = RailVehInfo(engine_number);
-	bool refittable = (_engine_refit_masks[engine_number] != 0);
+	bool refittable = (_engine_info[engine_number].refit_mask != 0);
 
 	/* Purchase cost */
 	SetDParam(0, (rvi->base_cost * _price.build_railwagon) >> 8);
@@ -915,7 +915,7 @@
 
 		/* See if any vehicle can be refitted */
 		for ( u = v; u != NULL; u = u->next) {
-			if (_engine_refit_masks[u->engine_type] != 0 ||
+			if (_engine_info[u->engine_type].refit_mask != 0 ||
 						 (!(RailVehInfo(v->engine_type)->flags & RVI_WAGON) && v->cargo_cap != 0)) {
 				CLRBIT(w->disabled_state, 12);
 				/* We have a refittable carriage, bail out */
--- a/vehicle.c
+++ b/vehicle.c
@@ -689,18 +689,7 @@
 bool CanRefitTo(const Vehicle *v, CargoID cid_to)
 {
 	CargoID cid = _global_cargo_id[_opt_ptr->landscape][cid_to];
-
-	if (cid == GC_INVALID) return false;
-
-	if (_engine_refit_masks[v->engine_type]) {
-		if (!HASBIT(_engine_refit_masks[v->engine_type], cid)) return false;
-	} else {
-		/* If we are talking about normal vehicles (no newgrf), you can only refit engines */
-		if (v->type == VEH_Train && (RailVehInfo(v->engine_type)->flags & RVI_WAGON)) return false;
-		if (!HASBIT(_default_refitmasks[v->type - VEH_Train], cid)) return false;
-	}
-
-	return true;
+	return HASBIT(_engine_info[v->engine_type].refit_mask, cid) != 0;
 }
 
 static void DoDrawVehicle(const Vehicle *v)
--- a/vehicle_gui.c
+++ b/vehicle_gui.c
@@ -226,18 +226,10 @@
 		cmask = 0;
 		u = v;
 		do {
-			if (_engine_refit_masks[u->engine_type] != 0) { // newgrf custom refit mask
-				cmask |= _engine_refit_masks[u->engine_type];
-			} else if (u->cargo_cap != 0) {
-				// rail wagons cant be refitted by default
-				if (v->type != VEH_Train || !(RailVehInfo(u->engine_type)->flags & RVI_WAGON))
-					cmask |= _default_refitmasks[v->type - VEH_Train];
-			}
+			cmask |= _engine_info[u->engine_type].refit_mask;
 			u = u->next;
 		} while (v->type == VEH_Train && u != NULL);
 
-		cmask &= _landscape_global_cargo_mask[_opt_ptr->landscape];
-
 		/* Check which cargo has been selected from the refit window and draw list */
 		for (cid = 0; cmask != 0; cmask >>= 1, cid++) {
 			if (HASBIT(cmask, 0)) // vehicle is refittable to this cargo