changeset 11990:db0e49f419d9 draft

(svn r16396) -Codechange: split NewGRF spritegroup into multiple subclasses instead of using a big union
author rubidium <rubidium@openttd.org>
date Sat, 23 May 2009 12:13:42 +0000
parents f70071553e5a
children a4d3838349e6
files src/newgrf.cpp src/newgrf_canal.cpp src/newgrf_cargo.cpp src/newgrf_engine.cpp src/newgrf_generic.cpp src/newgrf_house.cpp src/newgrf_industries.cpp src/newgrf_industrytiles.cpp src/newgrf_spritegroup.cpp src/newgrf_spritegroup.h src/newgrf_station.cpp
diffstat 11 files changed, 278 insertions(+), 277 deletions(-) [+]
line wrap: on
line diff
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -2588,42 +2588,6 @@
 	}
 }
 
-/**
- * Creates a spritegroup representing a callback result
- * @param value The value that was used to represent this callback result
- * @return A spritegroup representing that callback result
- */
-static const SpriteGroup *NewCallBackResultSpriteGroup(uint16 value)
-{
-	SpriteGroup *group = new SpriteGroup(SGT_CALLBACK);
-
-	/* Old style callback results have the highest byte 0xFF so signify it is a callback result
-	 * New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */
-	if ((value >> 8) == 0xFF) {
-		value &= ~0xFF00;
-	} else {
-		value &= ~0x8000;
-	}
-
-	group->g.callback.result = value;
-
-	return group;
-}
-
-/**
- * Creates a spritegroup representing a sprite number result.
- * @param sprite The sprite number.
- * @param num_sprites The number of sprites per set.
- * @return A spritegroup representing the sprite number result.
- */
-static const SpriteGroup *NewResultSpriteGroup(SpriteID sprite, byte num_sprites)
-{
-	SpriteGroup *group = new SpriteGroup(SGT_RESULT);
-	group->g.result.sprite = sprite;
-	group->g.result.num_sprites = num_sprites;
-	return group;
-}
-
 /* Action 0x01 */
 static void NewSpriteSet(byte *buf, size_t len)
 {
@@ -2678,7 +2642,7 @@
  * defined spritegroup. */
 static const SpriteGroup *GetGroupFromGroupID(byte setid, byte type, uint16 groupid)
 {
-	if (HasBit(groupid, 15)) return NewCallBackResultSpriteGroup(groupid);
+	if (HasBit(groupid, 15)) return new CallbackResultSpriteGroup(groupid);
 
 	if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) {
 		grfmsg(1, "GetGroupFromGroupID(0x%02X:0x%02X): Groupid 0x%04X does not exist, leaving empty", setid, type, groupid);
@@ -2691,7 +2655,7 @@
 /* Helper function to either create a callback or a result sprite group. */
 static const SpriteGroup *CreateGroupFromGroupID(byte feature, byte setid, byte type, uint16 spriteid, uint16 num_sprites)
 {
-	if (HasBit(spriteid, 15)) return NewCallBackResultSpriteGroup(spriteid);
+	if (HasBit(spriteid, 15)) return new CallbackResultSpriteGroup(spriteid);
 
 	if (spriteid >= _cur_grffile->spriteset_numsets) {
 		grfmsg(1, "CreateGroupFromGroupID(0x%02X:0x%02X): Sprite set %u invalid, max %u", setid, type, spriteid, _cur_grffile->spriteset_numsets);
@@ -2716,7 +2680,7 @@
 		return NULL;
 	}
 
-	return NewResultSpriteGroup(_cur_grffile->spriteset_start + spriteid * num_sprites, num_sprites);
+	return new ResultSpriteGroup(_cur_grffile->spriteset_start + spriteid * num_sprites, num_sprites);
 }
 
 /* Action 0x02 */
@@ -2732,7 +2696,7 @@
 	 *                 otherwise it specifies a number of entries, the exact
 	 *                 meaning depends on the feature
 	 * V feature-specific-data (huge mess, don't even look it up --pasky) */
-	SpriteGroup *group = NULL;
+	SpriteGroup *act_group = NULL;
 	byte *bufend = buf + len;
 
 	if (!check_length(len, 5, "NewSpriteGroup")) return;
@@ -2765,14 +2729,15 @@
 			/* Check we can load the var size parameter */
 			if (!check_length(bufend - buf, 1, "NewSpriteGroup (Deterministic) (1)")) return;
 
-			group = new SpriteGroup(SGT_DETERMINISTIC);
-			group->g.determ.var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
+			DeterministicSpriteGroup *group = new DeterministicSpriteGroup();
+			act_group = group;
+			group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
 
 			switch (GB(type, 2, 2)) {
 				default: NOT_REACHED();
-				case 0: group->g.determ.size = DSG_SIZE_BYTE;  varsize = 1; break;
-				case 1: group->g.determ.size = DSG_SIZE_WORD;  varsize = 2; break;
-				case 2: group->g.determ.size = DSG_SIZE_DWORD; varsize = 4; break;
+				case 0: group->size = DSG_SIZE_BYTE;  varsize = 1; break;
+				case 1: group->size = DSG_SIZE_WORD;  varsize = 2; break;
+				case 2: group->size = DSG_SIZE_DWORD; varsize = 4; break;
 			}
 
 			if (!check_length(bufend - buf, 5 + varsize, "NewSpriteGroup (Deterministic) (2)")) return;
@@ -2782,17 +2747,17 @@
 			do {
 				DeterministicSpriteGroupAdjust *adjust;
 
-				if (group->g.determ.num_adjusts > 0) {
+				if (group->num_adjusts > 0) {
 					if (!check_length(bufend - buf, 2 + varsize + 3, "NewSpriteGroup (Deterministic) (3)")) return;
 				}
 
-				group->g.determ.num_adjusts++;
-				group->g.determ.adjusts = ReallocT(group->g.determ.adjusts, group->g.determ.num_adjusts);
-
-				adjust = &group->g.determ.adjusts[group->g.determ.num_adjusts - 1];
+				group->num_adjusts++;
+				group->adjusts = ReallocT(group->adjusts, group->num_adjusts);
+
+				adjust = &group->adjusts[group->num_adjusts - 1];
 
 				/* The first var adjust doesn't have an operation specified, so we set it to add. */
-				adjust->operation = group->g.determ.num_adjusts == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)grf_load_byte(&buf);
+				adjust->operation = group->num_adjusts == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)grf_load_byte(&buf);
 				adjust->variable  = grf_load_byte(&buf);
 				if (adjust->variable == 0x7E) {
 					/* Link subroutine group */
@@ -2817,18 +2782,18 @@
 				/* Continue reading var adjusts while bit 5 is set. */
 			} while (HasBit(varadjust, 5));
 
-			group->g.determ.num_ranges = grf_load_byte(&buf);
-			if (group->g.determ.num_ranges > 0) group->g.determ.ranges = CallocT<DeterministicSpriteGroupRange>(group->g.determ.num_ranges);
-
-			if (!check_length(bufend - buf, 2 + (2 + 2 * varsize) * group->g.determ.num_ranges, "NewSpriteGroup (Deterministic)")) return;
-
-			for (uint i = 0; i < group->g.determ.num_ranges; i++) {
-				group->g.determ.ranges[i].group = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
-				group->g.determ.ranges[i].low   = grf_load_var(varsize, &buf);
-				group->g.determ.ranges[i].high  = grf_load_var(varsize, &buf);
+			group->num_ranges = grf_load_byte(&buf);
+			if (group->num_ranges > 0) group->ranges = CallocT<DeterministicSpriteGroupRange>(group->num_ranges);
+
+			if (!check_length(bufend - buf, 2 + (2 + 2 * varsize) * group->num_ranges, "NewSpriteGroup (Deterministic)")) return;
+
+			for (uint i = 0; i < group->num_ranges; i++) {
+				group->ranges[i].group = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
+				group->ranges[i].low   = grf_load_var(varsize, &buf);
+				group->ranges[i].high  = grf_load_var(varsize, &buf);
 			}
 
-			group->g.determ.default_group = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
+			group->default_group = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
 			break;
 		}
 
@@ -2839,25 +2804,26 @@
 		{
 			if (!check_length(bufend - buf, HasBit(type, 2) ? 8 : 7, "NewSpriteGroup (Randomized) (1)")) return;
 
-			group = new SpriteGroup(SGT_RANDOMIZED);
-			group->g.random.var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
+			RandomizedSpriteGroup *group = new RandomizedSpriteGroup();
+			act_group = group;
+			group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
 
 			if (HasBit(type, 2)) {
-				if (feature <= GSF_AIRCRAFT) group->g.random.var_scope = VSG_SCOPE_RELATIVE;
-				group->g.random.count = grf_load_byte(&buf);
+				if (feature <= GSF_AIRCRAFT) group->var_scope = VSG_SCOPE_RELATIVE;
+				group->count = grf_load_byte(&buf);
 			}
 
 			uint8 triggers = grf_load_byte(&buf);
-			group->g.random.triggers       = GB(triggers, 0, 7);
-			group->g.random.cmp_mode       = HasBit(triggers, 7) ? RSG_CMP_ALL : RSG_CMP_ANY;
-			group->g.random.lowest_randbit = grf_load_byte(&buf);
-			group->g.random.num_groups     = grf_load_byte(&buf);
-			group->g.random.groups = CallocT<const SpriteGroup*>(group->g.random.num_groups);
-
-			if (!check_length(bufend - buf, 2 * group->g.random.num_groups, "NewSpriteGroup (Randomized) (2)")) return;
-
-			for (uint i = 0; i < group->g.random.num_groups; i++) {
-				group->g.random.groups[i] = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
+			group->triggers       = GB(triggers, 0, 7);
+			group->cmp_mode       = HasBit(triggers, 7) ? RSG_CMP_ALL : RSG_CMP_ANY;
+			group->lowest_randbit = grf_load_byte(&buf);
+			group->num_groups     = grf_load_byte(&buf);
+			group->groups = CallocT<const SpriteGroup*>(group->num_groups);
+
+			if (!check_length(bufend - buf, 2 * group->num_groups, "NewSpriteGroup (Randomized) (2)")) return;
+
+			for (uint i = 0; i < group->num_groups; i++) {
+				group->groups[i] = GetGroupFromGroupID(setid, type, grf_load_word(&buf));
 			}
 
 			break;
@@ -2866,8 +2832,6 @@
 		/* Neither a variable or randomized sprite group... must be a real group */
 		default:
 		{
-
-
 			switch (feature) {
 				case GSF_TRAIN:
 				case GSF_ROAD:
@@ -2888,25 +2852,26 @@
 
 					if (!check_length(bufend - buf, 2 * num_loaded + 2 * num_loading, "NewSpriteGroup (Real) (1)")) return;
 
-					group = new SpriteGroup(SGT_REAL);
-
-					group->g.real.num_loaded  = num_loaded;
-					group->g.real.num_loading = num_loading;
-					if (num_loaded  > 0) group->g.real.loaded = CallocT<const SpriteGroup*>(num_loaded);
-					if (num_loading > 0) group->g.real.loading = CallocT<const SpriteGroup*>(num_loading);
+					RealSpriteGroup *group = new RealSpriteGroup();
+					act_group = group;
+
+					group->num_loaded  = num_loaded;
+					group->num_loading = num_loading;
+					if (num_loaded  > 0) group->loaded = CallocT<const SpriteGroup*>(num_loaded);
+					if (num_loading > 0) group->loading = CallocT<const SpriteGroup*>(num_loading);
 
 					grfmsg(6, "NewSpriteGroup: New SpriteGroup 0x%02X, %u views, %u loaded, %u loading",
 							setid, sprites, num_loaded, num_loading);
 
 					for (uint i = 0; i < num_loaded; i++) {
 						uint16 spriteid = grf_load_word(&buf);
-						group->g.real.loaded[i] = CreateGroupFromGroupID(feature, setid, type, spriteid, sprites);
+						group->loaded[i] = CreateGroupFromGroupID(feature, setid, type, spriteid, sprites);
 						grfmsg(8, "NewSpriteGroup: + rg->loaded[%i]  = subset %u", i, spriteid);
 					}
 
 					for (uint i = 0; i < num_loading; i++) {
 						uint16 spriteid = grf_load_word(&buf);
-						group->g.real.loading[i] = CreateGroupFromGroupID(feature, setid, type, spriteid, sprites);
+						group->loading[i] = CreateGroupFromGroupID(feature, setid, type, spriteid, sprites);
 						grfmsg(8, "NewSpriteGroup: + rg->loading[%i] = subset %u", i, spriteid);
 					}
 
@@ -2919,32 +2884,33 @@
 					byte num_sprites = max((uint8)1, type);
 					uint i;
 
-					group = new SpriteGroup(SGT_TILELAYOUT);
-					group->g.layout.num_sprites = sprites;
-					group->g.layout.dts = CallocT<DrawTileSprites>(1);
+					TileLayoutSpriteGroup *group = new TileLayoutSpriteGroup();
+					act_group = group;
+					group->num_sprites = sprites;
+					group->dts = CallocT<DrawTileSprites>(1);
 
 					/* Groundsprite */
-					group->g.layout.dts->ground.sprite = grf_load_word(&buf);
-					group->g.layout.dts->ground.pal    = grf_load_word(&buf);
+					group->dts->ground.sprite = grf_load_word(&buf);
+					group->dts->ground.pal    = grf_load_word(&buf);
 
 					/* Remap transparent/colour modifier bits */
-					MapSpriteMappingRecolour(&group->g.layout.dts->ground);
-
-					if (HasBit(group->g.layout.dts->ground.pal, 15)) {
+					MapSpriteMappingRecolour(&group->dts->ground);
+
+					if (HasBit(group->dts->ground.pal, 15)) {
 						/* Bit 31 set means this is a custom sprite, so rewrite it to the
 						 * last spriteset defined. */
-						SpriteID sprite = _cur_grffile->spriteset_start + GB(group->g.layout.dts->ground.sprite, 0, 14) * sprites;
-						SB(group->g.layout.dts->ground.sprite, 0, SPRITE_WIDTH, sprite);
-						ClrBit(group->g.layout.dts->ground.pal, 15);
+						SpriteID sprite = _cur_grffile->spriteset_start + GB(group->dts->ground.sprite, 0, 14) * sprites;
+						SB(group->dts->ground.sprite, 0, SPRITE_WIDTH, sprite);
+						ClrBit(group->dts->ground.pal, 15);
 					}
 
-					group->g.layout.dts->seq = CallocT<DrawTileSeqStruct>(num_sprites + 1);
+					group->dts->seq = CallocT<DrawTileSeqStruct>(num_sprites + 1);
 
 					for (i = 0; i < num_sprites; i++) {
-						DrawTileSeqStruct *seq = (DrawTileSeqStruct*)&group->g.layout.dts->seq[i];
+						DrawTileSeqStruct *seq = (DrawTileSeqStruct*)&group->dts->seq[i];
 
 						seq->image.sprite = grf_load_word(&buf);
-						seq->image.pal   = grf_load_word(&buf);
+						seq->image.pal    = grf_load_word(&buf);
 						seq->delta_x = grf_load_byte(&buf);
 						seq->delta_y = grf_load_byte(&buf);
 
@@ -2969,7 +2935,7 @@
 					}
 
 					/* Set the terminator value. */
-					((DrawTileSeqStruct*)group->g.layout.dts->seq)[i].delta_x = (int8)0x80;
+					((DrawTileSeqStruct*)group->dts->seq)[i].delta_x = (int8)0x80;
 
 					break;
 				}
@@ -2980,24 +2946,25 @@
 						break;
 					}
 
-					group = new SpriteGroup(SGT_INDUSTRY_PRODUCTION);
-					group->g.indprod.version = type;
+					IndustryProductionSpriteGroup *group = new IndustryProductionSpriteGroup();
+					act_group = group;
+					group->version = type;
 					if (type == 0) {
 						for (uint i = 0; i < 3; i++) {
-							group->g.indprod.substract_input[i] = grf_load_word(&buf);
+							group->substract_input[i] = grf_load_word(&buf);
 						}
 						for (uint i = 0; i < 2; i++) {
-							group->g.indprod.add_output[i] = grf_load_word(&buf);
+							group->add_output[i] = grf_load_word(&buf);
 						}
-						group->g.indprod.again = grf_load_byte(&buf);
+						group->again = grf_load_byte(&buf);
 					} else {
 						for (uint i = 0; i < 3; i++) {
-							group->g.indprod.substract_input[i] = grf_load_byte(&buf);
+							group->substract_input[i] = grf_load_byte(&buf);
 						}
 						for (uint i = 0; i < 2; i++) {
-							group->g.indprod.add_output[i] = grf_load_byte(&buf);
+							group->add_output[i] = grf_load_byte(&buf);
 						}
-						group->g.indprod.again = grf_load_byte(&buf);
+						group->again = grf_load_byte(&buf);
 					}
 					break;
 				}
@@ -3008,7 +2975,7 @@
 		}
 	}
 
-	_cur_grffile->spritegroups[setid] = group;
+	_cur_grffile->spritegroups[setid] = act_group;
 }
 
 static CargoID TranslateCargo(uint8 feature, uint8 ctype)
--- a/src/newgrf_canal.cpp
+++ b/src/newgrf_canal.cpp
@@ -60,11 +60,11 @@
 }
 
 
-static const SpriteGroup *CanalResolveReal(const ResolverObject *object, const SpriteGroup *group)
+static const SpriteGroup *CanalResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 {
-	if (group->g.real.num_loaded == 0) return NULL;
+	if (group->num_loaded == 0) return NULL;
 
-	return group->g.real.loaded[0];
+	return group->loaded[0];
 }
 
 
@@ -97,7 +97,7 @@
 	NewCanalResolver(&object, tile, _water_feature[feature].grffile);
 
 	group = Resolve(_water_feature[feature].group, &object);
-	if (group == NULL || group->type != SGT_RESULT) return 0;
+	if (group == NULL) return 0;
 
-	return group->g.result.sprite;
+	return group->GetResult();
 }
--- a/src/newgrf_cargo.cpp
+++ b/src/newgrf_cargo.cpp
@@ -35,12 +35,12 @@
 }
 
 
-static const SpriteGroup *CargoResolveReal(const ResolverObject *object, const SpriteGroup *group)
+static const SpriteGroup *CargoResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 {
 	/* Cargo action 2s should always have only 1 "loaded" state, but some
 	 * times things don't follow the spec... */
-	if (group->g.real.num_loaded > 0) return group->g.real.loaded[0];
-	if (group->g.real.num_loading > 0) return group->g.real.loading[0];
+	if (group->num_loaded > 0) return group->loaded[0];
+	if (group->num_loading > 0) return group->loading[0];
 
 	return NULL;
 }
@@ -75,9 +75,9 @@
 	NewCargoResolver(&object, cs);
 
 	group = Resolve(cs->group, &object);
-	if (group == NULL || group->type != SGT_RESULT) return 0;
+	if (group == NULL) return 0;
 
-	return group->g.result.sprite;
+	return group->GetResult();
 }
 
 
@@ -92,9 +92,9 @@
 	object.callback_param2 = param2;
 
 	group = Resolve(cs->group, &object);
-	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
+	if (group == NULL) return CALLBACK_FAILED;
 
-	return group->g.callback.result;
+	return group->GetCallbackResult();
 }
 
 
--- a/src/newgrf_engine.cpp
+++ b/src/newgrf_engine.cpp
@@ -815,24 +815,24 @@
 }
 
 
-static const SpriteGroup *VehicleResolveReal(const ResolverObject *object, const SpriteGroup *group)
+static const SpriteGroup *VehicleResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 {
 	const Vehicle *v = object->u.vehicle.self;
 
 	if (v == NULL) {
-		if (group->g.real.num_loading > 0) return group->g.real.loading[0];
-		if (group->g.real.num_loaded  > 0) return group->g.real.loaded[0];
+		if (group->num_loading > 0) return group->loading[0];
+		if (group->num_loaded  > 0) return group->loaded[0];
 		return NULL;
 	}
 
 	bool in_motion = !v->First()->current_order.IsType(OT_LOADING);
 
-	uint totalsets = in_motion ? group->g.real.num_loaded : group->g.real.num_loading;
+	uint totalsets = in_motion ? group->num_loaded : group->num_loading;
 
 	uint set = (v->cargo.Count() * totalsets) / max((uint16)1, v->cargo_cap);
 	set = min(set, totalsets - 1);
 
-	return in_motion ? group->g.real.loaded[set] : group->g.real.loading[set];
+	return in_motion ? group->loaded[set] : group->loading[set];
 }
 
 
@@ -913,9 +913,9 @@
 	NewVehicleResolver(&object, engine, v);
 
 	group = Resolve(GetVehicleSpriteGroup(engine, v), &object);
-	if (group == NULL || group->type != SGT_RESULT || group->g.result.num_sprites == 0) return 0;
+	if (group == NULL || group->GetNumResults() == 0) return 0;
 
-	return group->g.result.sprite + (direction % group->g.result.num_sprites);
+	return group->GetResult() + (direction % group->GetNumResults());
 }
 
 
@@ -936,11 +936,11 @@
 	const SpriteGroup *group = GetWagonOverrideSpriteSet(engine, CT_DEFAULT, engine);
 	group = Resolve(group, &object);
 
-	if (group == NULL || group->type != SGT_RESULT || group->g.result.num_sprites == 0) return 0;
+	if (group == NULL || group->GetNumResults() == 0) return 0;
 
-	if (v == NULL) return group->g.result.sprite;
+	if (v == NULL) return group->GetResult();
 
-	return group->g.result.sprite + (info_view ? 0 : (v->Next()->Next()->state % group->g.result.num_sprites));
+	return group->GetResult() + (info_view ? 0 : (v->Next()->Next()->state % group->GetNumResults()));
 }
 
 
@@ -976,9 +976,9 @@
 	object.callback_param2 = param2;
 
 	group = Resolve(GetVehicleSpriteGroup(engine, v, false), &object);
-	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
+	if (group == NULL) return CALLBACK_FAILED;
 
-	return group->g.callback.result;
+	return group->GetCallbackResult();
 }
 
 /**
@@ -1005,9 +1005,9 @@
 	object.u.vehicle.parent = parent;
 
 	group = Resolve(GetVehicleSpriteGroup(engine, v, false), &object);
-	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
+	if (group == NULL) return CALLBACK_FAILED;
 
-	return group->g.callback.result;
+	return group->GetCallbackResult();
 }
 
 
--- a/src/newgrf_generic.cpp
+++ b/src/newgrf_generic.cpp
@@ -98,11 +98,11 @@
 }
 
 
-static const SpriteGroup *GenericCallbackResolveReal(const ResolverObject *object, const SpriteGroup *group)
+static const SpriteGroup *GenericCallbackResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 {
-	if (group->g.real.num_loaded == 0) return NULL;
+	if (group->num_loaded == 0) return NULL;
 
-	return group->g.real.loaded[0];
+	return group->loaded[0];
 }
 
 
@@ -140,12 +140,12 @@
 	for (GenericCallbackList::const_iterator it = _gcl[feature].begin(); it != _gcl[feature].end(); ++it) {
 		const SpriteGroup *group = it->group;
 		group = Resolve(group, object);
-		if (group == NULL || group->type != SGT_CALLBACK) continue;
+		if (group == NULL) continue;
 
 		/* Return NewGRF file if necessary */
 		if (file != NULL) *file = it->file;
 
-		return group->g.callback.result;
+		return group->GetCallbackResult();
 	}
 
 	/* No callback returned a valid result, so we've failed. */
--- a/src/newgrf_house.cpp
+++ b/src/newgrf_house.cpp
@@ -309,7 +309,7 @@
 	return UINT_MAX;
 }
 
-static const SpriteGroup *HouseResolveReal(const ResolverObject *object, const SpriteGroup *group)
+static const SpriteGroup *HouseResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 {
 	/* Houses do not have 'real' groups */
 	return NULL;
@@ -355,14 +355,14 @@
 	object.callback_param2 = param2;
 
 	group = Resolve(GetHouseSpecs(house_id)->spritegroup, &object);
-	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
+	if (group == NULL) return CALLBACK_FAILED;
 
-	return group->g.callback.result;
+	return group->GetCallbackResult();
 }
 
-static void DrawTileLayout(const TileInfo *ti, const SpriteGroup *group, byte stage, HouseID house_id)
+static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte stage, HouseID house_id)
 {
-	const DrawTileSprites *dts = group->g.layout.dts;
+	const DrawTileSprites *dts = group->dts;
 	const DrawTileSeqStruct *dtss;
 
 	const HouseSpec *hs = GetHouseSpecs(house_id);
@@ -427,10 +427,11 @@
 		/* XXX: This is for debugging purposes really, and shouldn't stay. */
 		DrawGroundSprite(SPR_SHADOW_CELL, PAL_NONE);
 	} else {
+		const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group;
 		/* Limit the building stage to the number of stages supplied. */
 		byte stage = GetHouseBuildingStage(ti->tile);
-		stage = Clamp(stage - 4 + group->g.layout.num_sprites, 0, group->g.layout.num_sprites - 1);
-		DrawTileLayout(ti, group, stage, house_id);
+		stage = Clamp(stage - 4 + tlgroup->num_sprites, 0, tlgroup->num_sprites - 1);
+		DrawTileLayout(ti, tlgroup, stage, house_id);
 	}
 }
 
--- a/src/newgrf_industries.cpp
+++ b/src/newgrf_industries.cpp
@@ -329,7 +329,7 @@
 	return UINT_MAX;
 }
 
-static const SpriteGroup *IndustryResolveReal(const ResolverObject *object, const SpriteGroup *group)
+static const SpriteGroup *IndustryResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 {
 	/* IndustryTile do not have 'real' groups */
 	return NULL;
@@ -388,9 +388,9 @@
 	object.callback_param2 = param2;
 
 	group = Resolve(GetIndustrySpec(type)->grf_prop.spritegroup, &object);
-	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
+	if (group == NULL) return CALLBACK_FAILED;
 
-	return group->g.callback.result;
+	return group->GetCallbackResult();
 }
 
 uint32 IndustryLocationGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available)
@@ -465,18 +465,20 @@
 
 	/* Unlike the "normal" cases, not having a valid result means we allow
 	 * the building of the industry, as that's how it's done in TTDP. */
-	if (group == NULL || group->type != SGT_CALLBACK || group->g.callback.result == 0x400) return true;
+	if (group == NULL) return true;
+	uint16 result = group->GetCallbackResult();
+	if (result == 0x400 || result == CALLBACK_FAILED) return true;
 
 	/* Copy some parameters from the registers to the error message text ref. stack */
 	SwitchToErrorRefStack();
 	PrepareTextRefStackUsage(4);
 	SwitchToNormalRefStack();
 
-	switch (group->g.callback.result) {
+	switch (result) {
 		case 0x401: _error_message = STR_ERROR_SITE_UNSUITABLE; break;
 		case 0x402: _error_message = STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST; break;
 		case 0x403: _error_message = STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT; break;
-		default: _error_message = GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + group->g.callback.result); break;
+		default: _error_message = GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + result); break;
 	}
 
 	return false;
@@ -529,19 +531,20 @@
 		}
 
 		SB(object.callback_param2, 8, 16, loop);
-		const SpriteGroup *group = Resolve(spec->grf_prop.spritegroup, &object);
-		if (group == NULL || group->type != SGT_INDUSTRY_PRODUCTION) break;
+		const SpriteGroup *tgroup = Resolve(spec->grf_prop.spritegroup, &object);
+		if (tgroup == NULL || tgroup->type != SGT_INDUSTRY_PRODUCTION) break;
+		const IndustryProductionSpriteGroup *group = (const IndustryProductionSpriteGroup *)tgroup;
 
-		bool deref = (group->g.indprod.version == 1);
+		bool deref = (group->version == 1);
 
 		for (uint i = 0; i < 3; i++) {
-			ind->incoming_cargo_waiting[i] = Clamp(ind->incoming_cargo_waiting[i] - DerefIndProd(group->g.indprod.substract_input[i], deref) * multiplier, 0, 0xFFFF);
+			ind->incoming_cargo_waiting[i] = Clamp(ind->incoming_cargo_waiting[i] - DerefIndProd(group->substract_input[i], deref) * multiplier, 0, 0xFFFF);
 		}
 		for (uint i = 0; i < 2; i++) {
-			ind->produced_cargo_waiting[i] = Clamp(ind->produced_cargo_waiting[i] + max(DerefIndProd(group->g.indprod.add_output[i], deref), 0) * multiplier, 0, 0xFFFF);
+			ind->produced_cargo_waiting[i] = Clamp(ind->produced_cargo_waiting[i] + max(DerefIndProd(group->add_output[i], deref), 0) * multiplier, 0, 0xFFFF);
 		}
 
-		int32 again = DerefIndProd(group->g.indprod.again, deref);
+		int32 again = DerefIndProd(group->again, deref);
 		if (again == 0) break;
 
 		SB(object.callback_param2, 24, 8, again);
--- a/src/newgrf_industrytiles.cpp
+++ b/src/newgrf_industrytiles.cpp
@@ -105,7 +105,7 @@
 	return UINT_MAX;
 }
 
-static const SpriteGroup *IndustryTileResolveReal(const ResolverObject *object, const SpriteGroup *group)
+static const SpriteGroup *IndustryTileResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 {
 	/* IndustryTile do not have 'real' groups.  Or do they?? */
 	return NULL;
@@ -163,9 +163,9 @@
 	res->grffile         = (its != NULL ? its->grf_prop.grffile : NULL);
 }
 
-static void IndustryDrawTileLayout(const TileInfo *ti, const SpriteGroup *group, byte rnd_colour, byte stage, IndustryGfx gfx)
+static void IndustryDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte rnd_colour, byte stage, IndustryGfx gfx)
 {
-	const DrawTileSprites *dts = group->g.layout.dts;
+	const DrawTileSprites *dts = group->dts;
 	const DrawTileSeqStruct *dtss;
 
 	SpriteID image = dts->ground.sprite;
@@ -224,7 +224,7 @@
 	group = Resolve(GetIndustryTileSpec(gfx_id)->grf_prop.spritegroup, &object);
 	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
 
-	return group->g.callback.result;
+	return group->GetCallbackResult();
 }
 
 bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const IndustryTileSpec *inds)
@@ -249,10 +249,11 @@
 	if (group == NULL || group->type != SGT_TILELAYOUT) {
 		return false;
 	} else {
+		const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group;
 		/* Limit the building stage to the number of stages supplied. */
 		byte stage = GetIndustryConstructionStage(ti->tile);
-		stage = Clamp(stage - 4 + group->g.layout.num_sprites, 0, group->g.layout.num_sprites - 1);
-		IndustryDrawTileLayout(ti, group, i->random_colour, stage, gfx);
+		stage = Clamp(stage - 4 + tlgroup->num_sprites, 0, tlgroup->num_sprites - 1);
+		IndustryDrawTileLayout(ti, tlgroup, i->random_colour, stage, gfx);
 		return true;
 	}
 }
--- a/src/newgrf_spritegroup.cpp
+++ b/src/newgrf_spritegroup.cpp
@@ -11,32 +11,27 @@
 SpriteGroupPool _spritegroup_pool("SpriteGroup");
 INSTANTIATE_POOL_METHODS(SpriteGroup)
 
-SpriteGroup::~SpriteGroup()
+RealSpriteGroup::~RealSpriteGroup()
 {
-	/* Free dynamically allocated memory */
-	switch (this->type) {
-		case SGT_REAL:
-			free((SpriteGroup**)this->g.real.loaded);
-			free((SpriteGroup**)this->g.real.loading);
-			break;
+	free((SpriteGroup**)this->loaded);
+	free((SpriteGroup**)this->loading);
+}
 
-		case SGT_DETERMINISTIC:
-			free(this->g.determ.adjusts);
-			free(this->g.determ.ranges);
-			break;
-
-		case SGT_RANDOMIZED:
-			free((SpriteGroup**)this->g.random.groups);
-			break;
+DeterministicSpriteGroup::~DeterministicSpriteGroup()
+{
+	free(this->adjusts);
+	free(this->ranges);
+}
 
-		case SGT_TILELAYOUT:
-			free((void*)this->g.layout.dts->seq);
-			free(this->g.layout.dts);
-			break;
+RandomizedSpriteGroup::~RandomizedSpriteGroup()
+{
+	free((SpriteGroup**)this->groups);
+}
 
-		default:
-			break;
-	}
+TileLayoutSpriteGroup::~TileLayoutSpriteGroup()
+{
+	free((void*)this->dts->seq);
+	free(this->dts);
 }
 
 TemporaryStorageArray<uint32, 0x110> _temp_store;
@@ -126,17 +121,16 @@
 }
 
 
-static inline const SpriteGroup *ResolveVariable(const SpriteGroup *group, ResolverObject *object)
+static inline const SpriteGroup *ResolveVariable(const DeterministicSpriteGroup *group, ResolverObject *object)
 {
-	static SpriteGroup nvarzero;
 	uint32 last_value = 0;
 	uint32 value = 0;
 	uint i;
 
-	object->scope = group->g.determ.var_scope;
+	object->scope = group->var_scope;
 
-	for (i = 0; i < group->g.determ.num_adjusts; i++) {
-		DeterministicSpriteGroupAdjust *adjust = &group->g.determ.adjusts[i];
+	for (i = 0; i < group->num_adjusts; i++) {
+		DeterministicSpriteGroupAdjust *adjust = &group->adjusts[i];
 
 		/* Try to get the variable. We shall assume it is available, unless told otherwise. */
 		bool available = true;
@@ -144,10 +138,10 @@
 			ResolverObject subobject = *object;
 			subobject.procedure_call = true;
 			const SpriteGroup *subgroup = Resolve(adjust->subroutine, &subobject);
-			if (subgroup == NULL || subgroup->type != SGT_CALLBACK) {
+			if (subgroup == NULL) {
 				value = CALLBACK_FAILED;
 			} else {
-				value = subgroup->g.callback.result;
+				value = subgroup->GetCallbackResult();
 			}
 		} else {
 			value = GetVariable(object, adjust->variable, adjust->parameter, &available);
@@ -156,10 +150,10 @@
 		if (!available) {
 			/* Unsupported property: skip further processing and return either
 			 * the group from the first range or the default group. */
-			return Resolve(group->g.determ.num_ranges > 0 ? group->g.determ.ranges[0].group : group->g.determ.default_group, object);
+			return Resolve(group->num_ranges > 0 ? group->ranges[0].group : group->default_group, object);
 		}
 
-		switch (group->g.determ.size) {
+		switch (group->size) {
 			case DSG_SIZE_BYTE:  value = EvalAdjustT<uint8,  int8> (adjust, object, last_value, value); break;
 			case DSG_SIZE_WORD:  value = EvalAdjustT<uint16, int16>(adjust, object, last_value, value); break;
 			case DSG_SIZE_DWORD: value = EvalAdjustT<uint32, int32>(adjust, object, last_value, value); break;
@@ -170,45 +164,42 @@
 
 	object->last_value = last_value;
 
-	if (group->g.determ.num_ranges == 0) {
+	if (group->num_ranges == 0) {
 		/* nvar == 0 is a special case -- we turn our value into a callback result */
 		if (value != CALLBACK_FAILED) value = GB(value, 0, 15);
-		nvarzero.type = SGT_CALLBACK;
-		nvarzero.g.callback.result = value;
+		static CallbackResultSpriteGroup nvarzero(0);
+		nvarzero.result = value;
 		return &nvarzero;
 	}
 
-	for (i = 0; i < group->g.determ.num_ranges; i++) {
-		if (group->g.determ.ranges[i].low <= value && value <= group->g.determ.ranges[i].high) {
-			return Resolve(group->g.determ.ranges[i].group, object);
+	for (i = 0; i < group->num_ranges; i++) {
+		if (group->ranges[i].low <= value && value <= group->ranges[i].high) {
+			return Resolve(group->ranges[i].group, object);
 		}
 	}
 
-	return Resolve(group->g.determ.default_group, object);
+	return Resolve(group->default_group, object);
 }
 
 
-static inline const SpriteGroup *ResolveRandom(const SpriteGroup *group, ResolverObject *object)
+static inline const SpriteGroup *ResolveRandom(const RandomizedSpriteGroup *group, ResolverObject *object)
 {
 	uint32 mask;
 	byte index;
 
-	object->scope = group->g.random.var_scope;
-	object->count = group->g.random.count;
+	object->scope = group->var_scope;
+	object->count = group->count;
 
 	if (object->trigger != 0) {
 		/* Handle triggers */
 		/* Magic code that may or may not do the right things... */
 		byte waiting_triggers = object->GetTriggers(object);
-		byte match = group->g.random.triggers & (waiting_triggers | object->trigger);
-		bool res;
-
-		res = (group->g.random.cmp_mode == RSG_CMP_ANY) ?
-			(match != 0) : (match == group->g.random.triggers);
+		byte match = group->triggers & (waiting_triggers | object->trigger);
+		bool res = (group->cmp_mode == RSG_CMP_ANY) ? (match != 0) : (match == group->triggers);
 
 		if (res) {
 			waiting_triggers &= ~match;
-			object->reseed |= (group->g.random.num_groups - 1) << group->g.random.lowest_randbit;
+			object->reseed |= (group->num_groups - 1) << group->lowest_randbit;
 		} else {
 			waiting_triggers |= object->trigger;
 		}
@@ -216,10 +207,10 @@
 		object->SetTriggers(object, waiting_triggers);
 	}
 
-	mask  = (group->g.random.num_groups - 1) << group->g.random.lowest_randbit;
-	index = (object->GetRandomBits(object) & mask) >> group->g.random.lowest_randbit;
+	mask  = (group->num_groups - 1) << group->lowest_randbit;
+	index = (object->GetRandomBits(object) & mask) >> group->lowest_randbit;
 
-	return Resolve(group->g.random.groups[index], object);
+	return Resolve(group->groups[index], object);
 }
 
 
@@ -230,9 +221,9 @@
 	if (group == NULL) return NULL;
 
 	switch (group->type) {
-		case SGT_REAL:          return object->ResolveReal(object, group);
-		case SGT_DETERMINISTIC: return ResolveVariable(group, object);
-		case SGT_RANDOMIZED:    return ResolveRandom(group, object);
+		case SGT_REAL:          return object->ResolveReal(object, (RealSpriteGroup *)group);
+		case SGT_DETERMINISTIC: return ResolveVariable((DeterministicSpriteGroup *)group, object);
+		case SGT_RANDOMIZED:    return ResolveRandom((RandomizedSpriteGroup *)group, object);
 		default:                return group;
 	}
 }
--- a/src/newgrf_spritegroup.h
+++ b/src/newgrf_spritegroup.h
@@ -30,12 +30,44 @@
 	return _temp_store.Get(i);
 }
 
+/* List of different sprite group types */
+enum SpriteGroupType {
+	SGT_REAL,
+	SGT_DETERMINISTIC,
+	SGT_RANDOMIZED,
+	SGT_CALLBACK,
+	SGT_RESULT,
+	SGT_TILELAYOUT,
+	SGT_INDUSTRY_PRODUCTION,
+};
+
 struct SpriteGroup;
+typedef uint32 SpriteGroupID;
+typedef Pool<SpriteGroup, SpriteGroupID, 512, 64000> SpriteGroupPool;
+extern SpriteGroupPool _spritegroup_pool;
+
+/* Common wrapper for all the different sprite group types */
+struct SpriteGroup : SpriteGroupPool::PoolItem<&_spritegroup_pool> {
+protected:
+	SpriteGroup(SpriteGroupType type) : type(type) {}
+
+public:
+	virtual ~SpriteGroup() {}
+
+	SpriteGroupType type;
+
+	virtual SpriteID GetResult() const { return 0; }
+	virtual byte GetNumResults() const { return 0; }
+	virtual uint16 GetCallbackResult() const { return CALLBACK_FAILED; }
+};
 
 
 /* 'Real' sprite groups contain a list of other result or callback sprite
  * groups. */
-struct RealSpriteGroup {
+struct RealSpriteGroup : SpriteGroup {
+	RealSpriteGroup() : SpriteGroup(SGT_REAL) {}
+	~RealSpriteGroup();
+
 	/* Loaded = in motion, loading = not moving
 	 * Each group contains several spritesets, for various loading stages */
 
@@ -114,7 +146,10 @@
 };
 
 
-struct DeterministicSpriteGroup {
+struct DeterministicSpriteGroup : SpriteGroup {
+	DeterministicSpriteGroup() : SpriteGroup(SGT_DETERMINISTIC) {}
+	~DeterministicSpriteGroup();
+
 	VarSpriteGroupScope var_scope;
 	DeterministicSpriteGroupSize size;
 	byte num_adjusts;
@@ -131,7 +166,10 @@
 	RSG_CMP_ALL,
 };
 
-struct RandomizedSpriteGroup {
+struct RandomizedSpriteGroup : SpriteGroup {
+	RandomizedSpriteGroup() : SpriteGroup(SGT_RANDOMIZED) {}
+	~RandomizedSpriteGroup();
+
 	VarSpriteGroupScope var_scope;  ///< Take this object:
 
 	RandomizedSpriteGroupCompareMode cmp_mode; ///< Check for these triggers:
@@ -147,68 +185,68 @@
 
 /* This contains a callback result. A failed callback has a value of
  * CALLBACK_FAILED */
-struct CallbackResultSpriteGroup {
+struct CallbackResultSpriteGroup : SpriteGroup {
+	/**
+	 * Creates a spritegroup representing a callback result
+	 * @param result The value that was used to represent this callback result
+	 */
+	CallbackResultSpriteGroup(uint16 value) :
+		SpriteGroup(SGT_CALLBACK),
+		result(result)
+	{
+		/* Old style callback results have the highest byte 0xFF so signify it is a callback result
+		 * New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */
+		if ((this->result >> 8) == 0xFF) {
+			this->result &= ~0xFF00;
+		} else {
+			this->result &= ~0x8000;
+		}
+	}
+
 	uint16 result;
+	uint16 GetCallbackResult() const { return this->result; }
 };
 
 
 /* A result sprite group returns the first SpriteID and the number of
  * sprites in the set */
-struct ResultSpriteGroup {
+struct ResultSpriteGroup : SpriteGroup {
+	/**
+	 * Creates a spritegroup representing a sprite number result.
+	 * @param sprite The sprite number.
+	 * @param num_sprites The number of sprites per set.
+	 * @return A spritegroup representing the sprite number result.
+	 */
+	ResultSpriteGroup(SpriteID sprite, byte num_sprites) :
+		SpriteGroup(SGT_RESULT),
+		sprite(sprite),
+		num_sprites(num_sprites)
+	{
+	}
+
 	SpriteID sprite;
 	byte num_sprites;
+	SpriteID GetResult() const { return this->sprite; }
+	byte GetNumResults() const { return this->num_sprites; }
 };
 
-struct TileLayoutSpriteGroup {
+struct TileLayoutSpriteGroup : SpriteGroup {
+	TileLayoutSpriteGroup() : SpriteGroup(SGT_TILELAYOUT) {}
+	~TileLayoutSpriteGroup();
+
 	byte num_sprites; ///< Number of sprites in the spriteset, used for loading stages
 	struct DrawTileSprites *dts;
 };
 
-struct IndustryProductionSpriteGroup {
+struct IndustryProductionSpriteGroup : SpriteGroup {
+	IndustryProductionSpriteGroup() : SpriteGroup(SGT_INDUSTRY_PRODUCTION) {}
+
 	uint8 version;
 	uint16 substract_input[3];
 	uint16 add_output[2];
 	uint8 again;
 };
 
-/* List of different sprite group types */
-enum SpriteGroupType {
-	SGT_INVALID,
-	SGT_REAL,
-	SGT_DETERMINISTIC,
-	SGT_RANDOMIZED,
-	SGT_CALLBACK,
-	SGT_RESULT,
-	SGT_TILELAYOUT,
-	SGT_INDUSTRY_PRODUCTION,
-};
-
-typedef uint32 SpriteGroupID;
-typedef Pool<SpriteGroup, SpriteGroupID, 512, 64000> SpriteGroupPool;
-extern SpriteGroupPool _spritegroup_pool;
-
-/* Common wrapper for all the different sprite group types */
-struct SpriteGroup : SpriteGroupPool::PoolItem<&_spritegroup_pool> {
-	SpriteGroup(SpriteGroupType type = SGT_INVALID) :
-		type(type)
-	{
-	}
-
-	~SpriteGroup();
-
-	SpriteGroupType type;
-
-	union {
-		RealSpriteGroup real;
-		DeterministicSpriteGroup determ;
-		RandomizedSpriteGroup random;
-		CallbackResultSpriteGroup callback;
-		ResultSpriteGroup result;
-		TileLayoutSpriteGroup layout;
-		IndustryProductionSpriteGroup indprod;
-	} g;
-};
-
 
 struct ResolverObject {
 	CallbackID callback;
@@ -273,7 +311,7 @@
 	uint32 (*GetTriggers)(const struct ResolverObject*);
 	void (*SetTriggers)(const struct ResolverObject*, int);
 	uint32 (*GetVariable)(const struct ResolverObject*, byte, byte, bool*);
-	const SpriteGroup *(*ResolveReal)(const struct ResolverObject*, const SpriteGroup*);
+	const SpriteGroup *(*ResolveReal)(const struct ResolverObject*, const RealSpriteGroup*);
 
 	ResolverObject() : procedure_call(false) { }
 };
--- a/src/newgrf_station.cpp
+++ b/src/newgrf_station.cpp
@@ -527,7 +527,7 @@
 }
 
 
-static const SpriteGroup *StationResolveReal(const ResolverObject *object, const SpriteGroup *group)
+static const SpriteGroup *StationResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 {
 	const Station *st = object->u.station.st;
 	const StationSpec *statspec = object->u.station.statspec;
@@ -537,7 +537,7 @@
 	CargoID cargo_type = object->u.station.cargo_type;
 
 	if (st == NULL || statspec->sclass == STAT_CLASS_WAYP) {
-		return group->g.real.loading[0];
+		return group->loading[0];
 	}
 
 	switch (cargo_type) {
@@ -562,18 +562,18 @@
 	cargo = min(0xfff, cargo);
 
 	if (cargo > statspec->cargo_threshold) {
-		if (group->g.real.num_loading > 0) {
-			set = ((cargo - statspec->cargo_threshold) * group->g.real.num_loading) / (4096 - statspec->cargo_threshold);
-			return group->g.real.loading[set];
+		if (group->num_loading > 0) {
+			set = ((cargo - statspec->cargo_threshold) * group->num_loading) / (4096 - statspec->cargo_threshold);
+			return group->loading[set];
 		}
 	} else {
-		if (group->g.real.num_loaded > 0) {
-			set = (cargo * group->g.real.num_loaded) / (statspec->cargo_threshold + 1);
-			return group->g.real.loaded[set];
+		if (group->num_loaded > 0) {
+			set = (cargo * group->num_loaded) / (statspec->cargo_threshold + 1);
+			return group->loaded[set];
 		}
 	}
 
-	return group->g.real.loading[0];
+	return group->loading[0];
 }
 
 
@@ -645,7 +645,7 @@
 
 	group = ResolveStation(&object);
 	if (group == NULL || group->type != SGT_RESULT) return 0;
-	return group->g.result.sprite - 0x42D;
+	return group->GetResult() - 0x42D;
 }
 
 
@@ -661,7 +661,7 @@
 
 	group = ResolveStation(&object);
 	if (group == NULL || group->type != SGT_RESULT) return 0;
-	return group->g.result.sprite - 0x42D;
+	return group->GetResult() - 0x42D;
 }
 
 
@@ -677,8 +677,8 @@
 	object.callback_param2 = param2;
 
 	group = ResolveStation(&object);
-	if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED;
-	return group->g.callback.result;
+	if (group == NULL) return CALLBACK_FAILED;
+	return group->GetCallbackResult();
 }