diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 71cfdd10aa..530df31b6d 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -2588,42 +2588,6 @@ static void ReserveChangeInfo(byte *buf, size_t len) } } -/** - * 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 @@ static void SkipAct1(byte *buf, size_t len) * 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 @@ static const SpriteGroup *GetGroupFromGroupID(byte setid, byte type, uint16 grou /* 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 @@ static const SpriteGroup *CreateGroupFromGroupID(byte feature, byte setid, byte 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 @@ static void NewSpriteGroup(byte *buf, size_t len) * 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 @@ static void NewSpriteGroup(byte *buf, size_t len) /* 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 @@ static void NewSpriteGroup(byte *buf, size_t len) 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); + group->num_adjusts++; + group->adjusts = ReallocT(group->adjusts, group->num_adjusts); - adjust = &group->g.determ.adjusts[group->g.determ.num_adjusts - 1]; + 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 @@ static void NewSpriteGroup(byte *buf, size_t len) /* 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(group->g.determ.num_ranges); + group->num_ranges = grf_load_byte(&buf); + if (group->num_ranges > 0) group->ranges = CallocT(group->num_ranges); - if (!check_length(bufend - buf, 2 + (2 + 2 * varsize) * group->g.determ.num_ranges, "NewSpriteGroup (Deterministic)")) return; + if (!check_length(bufend - buf, 2 + (2 + 2 * varsize) * group->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); + 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 @@ static void NewSpriteGroup(byte *buf, size_t len) { 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(group->g.random.num_groups); + 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(group->num_groups); - if (!check_length(bufend - buf, 2 * group->g.random.num_groups, "NewSpriteGroup (Randomized) (2)")) return; + if (!check_length(bufend - buf, 2 * group->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)); + for (uint i = 0; i < group->num_groups; i++) { + group->groups[i] = GetGroupFromGroupID(setid, type, grf_load_word(&buf)); } break; @@ -2866,8 +2832,6 @@ static void NewSpriteGroup(byte *buf, size_t len) /* 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 @@ static void NewSpriteGroup(byte *buf, size_t len) if (!check_length(bufend - buf, 2 * num_loaded + 2 * num_loading, "NewSpriteGroup (Real) (1)")) return; - group = new SpriteGroup(SGT_REAL); + RealSpriteGroup *group = new RealSpriteGroup(); + act_group = group; - group->g.real.num_loaded = num_loaded; - group->g.real.num_loading = num_loading; - if (num_loaded > 0) group->g.real.loaded = CallocT(num_loaded); - if (num_loading > 0) group->g.real.loading = CallocT(num_loading); + group->num_loaded = num_loaded; + group->num_loading = num_loading; + if (num_loaded > 0) group->loaded = CallocT(num_loaded); + if (num_loading > 0) group->loading = CallocT(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 @@ static void NewSpriteGroup(byte *buf, size_t len) 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(1); + TileLayoutSpriteGroup *group = new TileLayoutSpriteGroup(); + act_group = group; + group->num_sprites = sprites; + group->dts = CallocT(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); + MapSpriteMappingRecolour(&group->dts->ground); - if (HasBit(group->g.layout.dts->ground.pal, 15)) { + 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(num_sprites + 1); + group->dts->seq = CallocT(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 @@ static void NewSpriteGroup(byte *buf, size_t len) } /* 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 @@ static void NewSpriteGroup(byte *buf, size_t len) 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 @@ static void NewSpriteGroup(byte *buf, size_t len) } } - _cur_grffile->spritegroups[setid] = group; + _cur_grffile->spritegroups[setid] = act_group; } static CargoID TranslateCargo(uint8 feature, uint8 ctype) diff --git a/src/newgrf_canal.cpp b/src/newgrf_canal.cpp index eab55e7f92..20355c899c 100644 --- a/src/newgrf_canal.cpp +++ b/src/newgrf_canal.cpp @@ -60,11 +60,11 @@ static uint32 CanalGetVariable(const ResolverObject *object, byte variable, byte } -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 @@ SpriteID GetCanalSprite(CanalFeature feature, TileIndex tile) 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(); } diff --git a/src/newgrf_cargo.cpp b/src/newgrf_cargo.cpp index b0f2620980..95f560edc5 100644 --- a/src/newgrf_cargo.cpp +++ b/src/newgrf_cargo.cpp @@ -35,12 +35,12 @@ static uint32 CargoGetVariable(const ResolverObject *object, byte variable, byte } -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 @@ SpriteID GetCustomCargoSprite(const CargoSpec *cs) 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 @@ uint16 GetCargoCallback(CallbackID callback, uint32 param1, uint32 param2, const 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(); } diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 550e032779..4643488b1b 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -815,24 +815,24 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by } -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 @@ SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction dire 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 @@ SpriteID GetRotorOverrideSprite(EngineID engine, const Aircraft *v, bool info_vi 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 @@ uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, Eng 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 @@ uint16 GetVehicleCallbackParent(CallbackID callback, uint32 param1, uint32 param 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(); } diff --git a/src/newgrf_generic.cpp b/src/newgrf_generic.cpp index 6ce92b7afc..0ca9fba771 100644 --- a/src/newgrf_generic.cpp +++ b/src/newgrf_generic.cpp @@ -98,11 +98,11 @@ static uint32 GenericCallbackGetVariable(const ResolverObject *object, byte vari } -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 @@ static uint16 GetGenericCallbackResult(uint8 feature, ResolverObject *object, co 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. */ diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index 15052c7b56..f49da4603f 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -309,7 +309,7 @@ static uint32 HouseGetVariable(const ResolverObject *object, byte variable, byte 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 @@ uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, House 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 @@ void DrawNewHouseTile(TileInfo *ti, HouseID house_id) /* 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); } } diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index 46cd2c1058..a17f004de7 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -329,7 +329,7 @@ uint32 IndustryGetVariable(const ResolverObject *object, byte variable, byte par 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 @@ uint16 GetIndustryCallback(CallbackID callback, uint32 param1, uint32 param2, In 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 @@ bool CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint itspe /* 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 @@ void IndustryProductionCallback(Industry *ind, int reason) } 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); diff --git a/src/newgrf_industrytiles.cpp b/src/newgrf_industrytiles.cpp index 34d41667cd..86a6a8222d 100644 --- a/src/newgrf_industrytiles.cpp +++ b/src/newgrf_industrytiles.cpp @@ -105,7 +105,7 @@ static uint32 IndustryTileGetVariable(const ResolverObject *object, byte variabl 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 @@ static void NewIndustryTileResolver(ResolverObject *res, IndustryGfx gfx, TileIn 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 @@ uint16 GetIndustryTileCallback(CallbackID callback, uint32 param1, uint32 param2 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 @@ bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const Indus 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; } } diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index d29c193e3c..03fa75f908 100644 --- 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; +DeterministicSpriteGroup::~DeterministicSpriteGroup() +{ + free(this->adjusts); + free(this->ranges); +} - case SGT_RANDOMIZED: - free((SpriteGroup**)this->g.random.groups); - break; +RandomizedSpriteGroup::~RandomizedSpriteGroup() +{ + free((SpriteGroup**)this->groups); +} - case SGT_TILELAYOUT: - free((void*)this->g.layout.dts->seq); - free(this->g.layout.dts); - break; - - default: - break; - } +TileLayoutSpriteGroup::~TileLayoutSpriteGroup() +{ + free((void*)this->dts->seq); + free(this->dts); } TemporaryStorageArray _temp_store; @@ -126,17 +121,16 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust *adjust, ResolverObjec } -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 @@ static inline const SpriteGroup *ResolveVariable(const SpriteGroup *group, Resol 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 @@ static inline const SpriteGroup *ResolveVariable(const SpriteGroup *group, Resol 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 (adjust, object, last_value, value); break; case DSG_SIZE_WORD: value = EvalAdjustT(adjust, object, last_value, value); break; case DSG_SIZE_DWORD: value = EvalAdjustT(adjust, object, last_value, value); break; @@ -170,45 +164,42 @@ static inline const SpriteGroup *ResolveVariable(const SpriteGroup *group, Resol 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 @@ static inline const SpriteGroup *ResolveRandom(const SpriteGroup *group, Resolve 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 @@ const SpriteGroup *Resolve(const SpriteGroup *group, ResolverObject *object) 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; } } diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index b8dd5f151d..3598d14093 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -30,12 +30,44 @@ static inline uint32 GetRegister(uint i) 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 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 DeterministicSpriteGroupRange { }; -struct DeterministicSpriteGroup { +struct DeterministicSpriteGroup : SpriteGroup { + DeterministicSpriteGroup() : SpriteGroup(SGT_DETERMINISTIC) {} + ~DeterministicSpriteGroup(); + VarSpriteGroupScope var_scope; DeterministicSpriteGroupSize size; byte num_adjusts; @@ -131,7 +166,10 @@ enum RandomizedSpriteGroupCompareMode { 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 @@ struct RandomizedSpriteGroup { /* 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 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 @@ struct ResolverObject { 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) { } }; diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index 57384b102b..81ce36c2e4 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -527,7 +527,7 @@ static uint32 StationGetVariable(const ResolverObject *object, byte variable, by } -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 @@ static const SpriteGroup *StationResolveReal(const ResolverObject *object, const 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 @@ static const SpriteGroup *StationResolveReal(const ResolverObject *object, const 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 @@ SpriteID GetCustomStationRelocation(const StationSpec *statspec, const Station * 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 @@ SpriteID GetCustomStationGroundRelocation(const StationSpec *statspec, const Sta 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 @@ uint16 GetStationCallback(CallbackID callback, uint32 param1, uint32 param2, con 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(); }