Mercurial > hg > openttd
changeset 3668:4b443d0d50e5 draft
(svn r4583) - NewGRF: Revamp sprite group loading to support advanced varadjusts and variable size. These are not yet processed, however.
author | peter1138 <peter1138@openttd.org> |
---|---|
date | Wed, 26 Apr 2006 20:44:28 +0000 |
parents | 813e5df222b7 |
children | 815e93e58a75 |
files | newgrf.c newgrf_engine.c newgrf_spritegroup.c newgrf_spritegroup.h newgrf_station.c sprite.c |
diffstat | 6 files changed, 254 insertions(+), 169 deletions(-) [+] |
line wrap: on
line diff
--- a/newgrf.c +++ b/newgrf.c @@ -176,6 +176,17 @@ return val; } +static uint32 grf_load_var(byte size, byte **buf) +{ + switch (size) { + case 1: return grf_load_byte(buf); + case 2: return grf_load_word(buf); + case 4: return grf_load_dword(buf); + default: + NOT_REACHED(); + return 0; + } +} static GRFFile *GetFileByGRFID(uint32 grfid) { @@ -1247,12 +1258,12 @@ * @param sprites The number of sprites per set. * @return A spritegroup representing the sprite number result. */ -static SpriteGroup* NewResultSpriteGroup(uint16 value, byte sprites) +static SpriteGroup* NewResultSpriteGroup(SpriteID sprite, byte num_sprites) { SpriteGroup *group = AllocateSpriteGroup(); group->type = SGT_RESULT; - group->g.result.result = value; - group->g.result.sprites = sprites; + group->g.result.sprite = sprite; + group->g.result.num_sprites = num_sprites; return group; } @@ -1384,42 +1395,78 @@ /* Deterministic Sprite Group */ case 0x81: // Self scope, byte case 0x82: // Parent scope, byte + case 0x85: // Self scope, word + case 0x86: // Parent scope, word + case 0x89: // Self scope, dword + case 0x8A: // Parent scope, dword { - DeterministicSpriteGroup *dg; - int i; - - check_length(bufend - buf, 6, "NewSpriteGroup 0x81/0x82"); + byte varadjust; + byte varsize; + uint i; + + /* Check we can load the var size parameter */ + check_length(bufend - buf, 1, "NewSpriteGroup (Deterministic) (1)"); group = AllocateSpriteGroup(); group->type = SGT_DETERMINISTIC; - dg = &group->g.determ; - - dg->var_scope = type == 0x82 ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; - dg->variable = grf_load_byte(&buf); - /* Variables 0x60 - 0x7F include an extra parameter */ - if (IS_BYTE_INSIDE(dg->variable, 0x60, 0x80)) - dg->parameter = grf_load_byte(&buf); - - dg->shift_num = grf_load_byte(&buf); - dg->and_mask = grf_load_byte(&buf); - dg->operation = dg->shift_num >> 6; /* w00t */ - dg->shift_num &= 0x3F; - if (dg->operation != DSG_OP_NONE) { - dg->add_val = grf_load_byte(&buf); - dg->divmod_val = grf_load_byte(&buf); + group->g.determ.var_scope = HASBIT(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; + + switch (GB(type, 2, 2)) { + 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; + default: NOT_REACHED(); break; } - /* (groupid & 0x8000) means this is callback result. */ - - dg->num_ranges = grf_load_byte(&buf); - dg->ranges = calloc(dg->num_ranges, sizeof(*dg->ranges)); - for (i = 0; i < dg->num_ranges; i++) { - dg->ranges[i].group = GetGroupFromGroupID(setid, type, grf_load_word(&buf)); - dg->ranges[i].low = grf_load_byte(&buf); - dg->ranges[i].high = grf_load_byte(&buf); + check_length(bufend - buf, 2 + (varsize * 3) + 2, "NewSpriteGroup (Deterministic) (2)"); + + /* Loop through the var adjusts. Unfortunately we don't know how many we have + * from the outset, so we shall have to keep reallocing. */ + do { + DeterministicSpriteGroupAdjust *adjust; + + if (group->g.determ.num_adjusts > 0) { + check_length(bufend - buf, 2 + (varsize * 3) + 3, "NewSpriteGroup (Deterministic) (3)"); + } + + group->g.determ.num_adjusts++; + group->g.determ.adjusts = realloc(group->g.determ.adjusts, group->g.determ.num_adjusts * sizeof(*group->g.determ.adjusts)); + + adjust = &group->g.determ.adjusts[group->g.determ.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 : grf_load_byte(&buf); + adjust->variable = grf_load_byte(&buf); + adjust->parameter = IS_BYTE_INSIDE(adjust->variable, 0x60, 0x80) ? grf_load_byte(&buf) : 0; + + varadjust = grf_load_byte(&buf); + adjust->shift_num = GB(varadjust, 0, 5); + adjust->type = GB(varadjust, 6, 2); + adjust->and_mask = grf_load_var(varsize, &buf); + + if (adjust->type != DSGA_TYPE_NONE) { + adjust->add_val = grf_load_var(varsize, &buf); + adjust->divmod_val = grf_load_var(varsize, &buf); + } else { + adjust->add_val = 0; + adjust->divmod_val = 0; + } + + /* Continue reading var adjusts while bit 5 is set. */ + } while (HASBIT(varadjust, 5)); + + group->g.determ.num_ranges = grf_load_byte(&buf); + group->g.determ.ranges = calloc(group->g.determ.num_ranges, sizeof(*group->g.determ.ranges)); + + check_length(bufend - buf, 2 + (2 + 2 * varsize) * group->g.determ.num_ranges, "NewSpriteGroup (Deterministic)"); + + for (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); } - dg->default_group = GetGroupFromGroupID(setid, type, grf_load_word(&buf)); + group->g.determ.default_group = GetGroupFromGroupID(setid, type, grf_load_word(&buf)); break; } @@ -1427,79 +1474,88 @@ case 0x80: // Self scope case 0x83: // Parent scope { - RandomizedSpriteGroup *rg; - int i; - - /* This stuff is getting actually evaluated in - * EvalRandomizedSpriteGroup(). */ - - check_length(bufend - buf, 6, "NewSpriteGroup 0x80/0x83"); + byte triggers; + uint i; + + check_length(bufend - buf, 7, "NewSpriteGroup (Randomized) (1)"); group = AllocateSpriteGroup(); group->type = SGT_RANDOMIZED; - rg = &group->g.random; - - rg->var_scope = type == 0x83 ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; - - rg->triggers = grf_load_byte(&buf); - rg->cmp_mode = rg->triggers & 0x80; - rg->triggers &= 0x7F; - - rg->lowest_randbit = grf_load_byte(&buf); - rg->num_groups = grf_load_byte(&buf); - - rg->groups = calloc(rg->num_groups, sizeof(*rg->groups)); - for (i = 0; i < rg->num_groups; i++) { - rg->groups[i] = GetGroupFromGroupID(setid, type, grf_load_word(&buf)); + group->g.random.var_scope = HASBIT(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; + + 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 = calloc(group->g.random.num_groups, sizeof(*group->g.random.groups)); + + check_length(bufend - buf, 2 * group->g.random.num_groups, "NewSpriteGroup (Randomized) (2)"); + + for (i = 0; i < group->g.random.num_groups; i++) { + group->g.random.groups[i] = GetGroupFromGroupID(setid, type, grf_load_word(&buf)); } break; } + /* Neither a variable or randomized sprite group... must be a real group */ default: { - RealSpriteGroup *rg; - byte num_loaded = type; - byte num_loading = grf_load_byte(&buf); - uint i; - - if (_cur_grffile->spriteset_start == 0) { - grfmsg(GMS_ERROR, "NewSpriteGroup: No sprite set to work on! Skipping."); - return; + switch (feature) { + case GSF_TRAIN: + case GSF_ROAD: + case GSF_SHIP: + case GSF_AIRCRAFT: + case GSF_STATION: + { + byte sprites = _cur_grffile->spriteset_numents; + byte num_loaded = type; + byte num_loading = grf_load_byte(&buf); + uint i; + + if (_cur_grffile->spriteset_start == 0) { + grfmsg(GMS_ERROR, "NewSpriteGroup: No sprite set to work on! Skipping."); + return; + } + + if (_cur_grffile->first_spriteset == 0) { + DEBUG(grf, 6) ("NewSpriteGroup: Setting 0x%X as first Sprite ID", _cur_grffile->spriteset_start); + _cur_grffile->first_spriteset = _cur_grffile->spriteset_start; + } + + check_length(bufend - buf, 2 * num_loaded + 2 * num_loading, "NewSpriteGroup (Real) (1)"); + + group = AllocateSpriteGroup(); + group->type = SGT_REAL; + + group->g.real.num_loaded = num_loaded; + group->g.real.num_loading = num_loading; + if (num_loaded > 0) group->g.real.loaded = calloc(num_loaded, sizeof(*group->g.real.loaded)); + if (num_loading > 0) group->g.real.loading = calloc(num_loading, sizeof(*group->g.real.loading)); + + DEBUG(grf, 6) ("NewSpriteGroup: New SpriteGroup 0x%02X, %u views, %u loaded, %u loading", + setid, sprites, num_loaded, num_loading); + + for (i = 0; i < num_loaded; i++) { + uint16 spriteid = grf_load_word(&buf); + group->g.real.loaded[i] = CreateGroupFromGroupID(setid, type, spriteid, sprites); + DEBUG(grf, 8) ("NewSpriteGroup: + rg->loaded[%i] = subset %u", i, spriteid); + } + + for (i = 0; i < num_loading; i++) { + uint16 spriteid = grf_load_word(&buf); + group->g.real.loading[i] = CreateGroupFromGroupID(setid, type, spriteid, sprites); + DEBUG(grf, 8) ("NewSpriteGroup: + rg->loading[%i] = subset %u", i, spriteid); + } + + break; + } + + /* Loading of Tile Layout and Production Callback groups would happen here */ + default: + grfmsg(GMS_WARN, "NewSpriteGroup: Unsupported feature %d, skipping.", feature); } - - if (_cur_grffile->first_spriteset == 0) - _cur_grffile->first_spriteset = _cur_grffile->spriteset_start; - - group = AllocateSpriteGroup(); - group->type = SGT_REAL; - rg = &group->g.real; - - rg->sprites_per_set = _cur_grffile->spriteset_numents; - rg->loaded_count = num_loaded; - rg->loading_count = num_loading; - - rg->loaded = calloc(rg->loaded_count, sizeof(*rg->loaded)); - rg->loading = calloc(rg->loading_count, sizeof(*rg->loading)); - - DEBUG(grf, 6) ("NewSpriteGroup: New SpriteGroup 0x%02hhx, %u views, %u loaded, %u loading, sprites %u - %u", - setid, rg->sprites_per_set, rg->loaded_count, rg->loading_count, - _cur_grffile->spriteset_start - _cur_grffile->sprite_offset, - _cur_grffile->spriteset_start + (_cur_grffile->spriteset_numents * (num_loaded + num_loading)) - _cur_grffile->sprite_offset); - - for (i = 0; i < num_loaded; i++) { - uint16 spriteset_id = grf_load_word(&buf); - rg->loaded[i] = CreateGroupFromGroupID(setid, type, spriteset_id, rg->sprites_per_set); - DEBUG(grf, 8) ("NewSpriteGroup: + rg->loaded[%i] = %u (subset %u)", i, rg->loaded[i]->g.result.result, spriteset_id); - } - - for (i = 0; i < num_loading; i++) { - uint16 spriteset_id = grf_load_word(&buf); - rg->loading[i] = CreateGroupFromGroupID(setid, type, spriteset_id, rg->sprites_per_set); - DEBUG(grf, 8) ("NewSpriteGroup: + rg->loading[%i] = %u (subset %u)", i, rg->loading[i]->g.result.result, spriteset_id); - } - - break; } }
--- a/newgrf_engine.c +++ b/newgrf_engine.c @@ -208,16 +208,18 @@ const DeterministicSpriteGroup *dsg = &spritegroup->g.determ; const SpriteGroup *target; int value = -1; + // XXX Temporary support + byte variable = dsg->adjusts[0].variable; - //debug("[%p] Having fun resolving variable %x", veh, dsg->variable); - if (dsg->variable == 0x0C) { + //debug("[%p] Having fun resolving variable %x", veh, variable); + if (variable == 0x0C) { /* Callback ID */ value = callback_info & 0xFF; - } else if (dsg->variable == 0x10) { + } else if (variable == 0x10) { value = (callback_info >> 8) & 0xFF; - } else if ((dsg->variable >> 6) == 0) { + } else if ((variable >> 6) == 0) { /* General property */ - value = GetDeterministicSpriteValue(dsg->variable); + value = GetDeterministicSpriteValue(variable); } else { /* Vehicle-specific property. */ @@ -240,18 +242,18 @@ veh = GetFirstVehicleInChain(veh); } - if (dsg->variable == 0x40 || dsg->variable == 0x41) { + if (variable == 0x40 || variable == 0x41) { if (veh->type == VEH_Train) { const Vehicle *u = GetFirstVehicleInChain(veh); byte chain_before = 0, chain_after = 0; while (u != veh) { chain_before++; - if (dsg->variable == 0x41 && u->engine_type != veh->engine_type) + if (variable == 0x41 && u->engine_type != veh->engine_type) chain_before = 0; u = u->next; } - while (u->next != NULL && (dsg->variable == 0x40 || u->next->engine_type == veh->engine_type)) { + while (u->next != NULL && (variable == 0x40 || u->next->engine_type == veh->engine_type)) { chain_after++; u = u->next; }; @@ -265,7 +267,7 @@ } else { // TTDPatch runs on little-endian arch; // Variable is 0x80 + offset in TTD's vehicle structure - switch (dsg->variable - 0x80) { + switch (variable - 0x80) { #define veh_prop(id_, value_) case (id_): value = (value_); break veh_prop(0x00, veh->type); veh_prop(0x01, MapOldSubType(veh)); @@ -347,7 +349,7 @@ #undef veh_prop // Handle vehicle specific properties. - default: value = VehicleSpecificProperty(veh, dsg->variable - 0x80); break; + default: value = VehicleSpecificProperty(veh, variable - 0x80); break; } } } @@ -411,7 +413,6 @@ byte loaded = 0; bool in_motion = 0; int totalsets, spriteset; - int r; if (v != NULL) { int capacity = v->cargo_cap; @@ -444,16 +445,11 @@ assert(group->type == SGT_REAL); rsg = &group->g.real; - if (!rsg->sprites_per_set) { - // This group is empty. This function users should therefore - // look up the sprite number in _engine_original_sprites. - return 0; - } + // This group is empty. This function users should therefore + // look up the sprite number in _engine_original_sprites. + if (rsg->num_loaded == 0 || rsg->num_loading == 0) return 0; - assert(rsg->sprites_per_set <= 8); - direction %= rsg->sprites_per_set; - - totalsets = in_motion ? rsg->loaded_count : rsg->loading_count; + totalsets = in_motion ? rsg->num_loaded : rsg->num_loading; // My aim here is to make it possible to visually determine absolutely // empty and totally full vehicles. --pasky @@ -470,8 +466,10 @@ spriteset--; } - r = (in_motion ? rsg->loaded[spriteset]->g.result.result : rsg->loading[spriteset]->g.result.result) + direction; - return r; + group = in_motion ? rsg->loaded[spriteset] : rsg->loading[spriteset]; + if (group->type != SGT_RESULT) return 0; + + return group->g.result.sprite + (direction % group->g.result.num_sprites); } /**
--- a/newgrf_spritegroup.c +++ b/newgrf_spritegroup.c @@ -29,6 +29,7 @@ break; case SGT_DETERMINISTIC: + free(group->g.determ.adjusts); free(group->g.determ.ranges); break;
--- a/newgrf_spritegroup.h +++ b/newgrf_spritegroup.h @@ -6,9 +6,10 @@ typedef struct SpriteGroup SpriteGroup; + +/* 'Real' sprite groups contain a list of other result or callback sprite + * groups. */ typedef struct RealSpriteGroup { - byte sprites_per_set; // means number of directions - 4 or 8 - // Loaded = in motion, loading = not moving // Each group contains several spritesets, for various loading stages @@ -16,53 +17,81 @@ // with small amount of cargo whilst loading is for stations with a lot // of da stuff. - byte loaded_count; ///< Number of loaded groups + byte num_loaded; ///< Number of loaded groups + byte num_loading; ///< Number of loading groups SpriteGroup **loaded; ///< List of loaded groups (can be SpriteIDs or Callback results) - byte loading_count; ///< Number of loading groups SpriteGroup **loading; ///< List of loading groups (can be SpriteIDs or Callback results) } RealSpriteGroup; /* Shared by deterministic and random groups. */ -typedef enum VarSpriteGroupScope { +typedef enum VarSpriteGroupScopes { VSG_SCOPE_SELF, // Engine of consists for vehicles, city for stations. VSG_SCOPE_PARENT, } VarSpriteGroupScope; -typedef struct DeterministicSpriteGroupRanges DeterministicSpriteGroupRanges; +typedef enum DeterministicSpriteGroupSizes { + DSG_SIZE_BYTE, + DSG_SIZE_WORD, + DSG_SIZE_DWORD, +} DeterministicSpriteGroupSize; + +typedef enum DeterministicSpriteGroupAdjustTypes { + DSGA_TYPE_NONE, + DSGA_TYPE_DIV, + DSGA_TYPE_MOD, +} DeterministicSpriteGroupAdjustType; -typedef enum DeterministicSpriteGroupOperation { - DSG_OP_NONE, - DSG_OP_DIV, - DSG_OP_MOD, -} DeterministicSpriteGroupOperation; +typedef enum DeterministicSpriteGroupAdjustOperations { + DSGA_OP_ADD, // a + b + DSGA_OP_SUB, // a - b + DSGA_OP_SMIN, // (signed) min(a, b) + DSGA_OP_SMAX, // (signed) max(a, b) + DSGA_OP_UMIN, // (unsigned) min(a, b) + DSGA_OP_UMAX, // (unsigned) max(a, b) + DSGA_OP_SDIV, // (signed) a / b + DSGA_OP_SMOD, // (signed) a % b + DSGA_OP_UDIV, // (unsigned) a / b + DSGA_OP_UMOD, // (unsigned) a & b + DSGA_OP_MUL, // a * b + DSGA_OP_AND, // a & b + DSGA_OP_OR, // a | b + DSGA_OP_XOR, // a ^ b +} DeterministicSpriteGroupAdjustOperation; + -typedef struct DeterministicSpriteGroupRange DeterministicSpriteGroupRange; +typedef struct DeterministicSpriteGroupAdjust { + DeterministicSpriteGroupAdjustOperation operation; + DeterministicSpriteGroupAdjustType type; + byte variable; + byte parameter; ///< Used for variables between 0x60 and 0x7F inclusive. + byte shift_num; + uint32 and_mask; + uint32 add_val; + uint32 divmod_val; +} DeterministicSpriteGroupAdjust; + + +typedef struct DeterministicSpriteGroupRange { + SpriteGroup *group; + uint32 low; + uint32 high; +} DeterministicSpriteGroupRange; + typedef struct DeterministicSpriteGroup { - // Take this variable: VarSpriteGroupScope var_scope; - byte variable; - byte parameter; ///< Used for variables between 0x60 and 0x7F inclusive. - - // Do this with it: - byte shift_num; - byte and_mask; - - // Then do this with it: - DeterministicSpriteGroupOperation operation; - byte add_val; - byte divmod_val; - - // And apply it to this: + DeterministicSpriteGroupSize size; + byte num_adjusts; byte num_ranges; + DeterministicSpriteGroupAdjust *adjusts; DeterministicSpriteGroupRange *ranges; // Dynamically allocated // Dynamically allocated, this is the sole owner SpriteGroup *default_group; } DeterministicSpriteGroup; -typedef enum RandomizedSpriteGroupCompareMode { +typedef enum RandomizedSpriteGroupCompareModes { RSG_CMP_ANY, RSG_CMP_ALL, } RandomizedSpriteGroupCompareMode; @@ -83,15 +112,22 @@ SpriteGroup **groups; } RandomizedSpriteGroup; + +/* This contains a callback result. A failed callback has a value of + * CALLBACK_FAILED */ typedef struct CallbackResultSpriteGroup { uint16 result; } CallbackResultSpriteGroup; + +/* A result sprite group returns the first SpriteID and the number of + * sprites in the set */ typedef struct ResultSpriteGroup { - uint16 result; - byte sprites; + SpriteID sprite; + byte num_sprites; } ResultSpriteGroup; +/* List of different sprite group types */ typedef enum SpriteGroupType { SGT_INVALID, SGT_REAL, @@ -101,6 +137,7 @@ SGT_RESULT, } SpriteGroupType; +/* Common wrapper for all the different sprite group types */ struct SpriteGroup { SpriteGroupType type; @@ -113,12 +150,6 @@ } g; }; -struct DeterministicSpriteGroupRange { - SpriteGroup *group; - byte low; - byte high; -}; - SpriteGroup *AllocateSpriteGroup(void); void InitializeSpriteGroupPool(void);
--- a/newgrf_station.c +++ b/newgrf_station.c @@ -169,10 +169,11 @@ const DeterministicSpriteGroup *dsg = &spg->g.determ; SpriteGroup *target; int value = -1; + byte variable = dsg->adjusts[0].variable; - if ((dsg->variable >> 6) == 0) { + if ((variable >> 6) == 0) { /* General property */ - value = GetDeterministicSpriteValue(dsg->variable); + value = GetDeterministicSpriteValue(variable); } else { if (st == NULL) { /* We are in a build dialog of something, @@ -192,7 +193,7 @@ /* TODO: Town structure. */ } else /* VSG_SELF */ { - if (dsg->variable == 0x40 || dsg->variable == 0x41) { + if (variable == 0x40 || variable == 0x41) { /* FIXME: This is ad hoc only * for waypoints. */ value = 0x01010000; @@ -200,7 +201,7 @@ /* TODO: Only small fraction done. */ // TTDPatch runs on little-endian arch; // Variable is 0x70 + offset in the TTD's station structure - switch (dsg->variable - 0x70) { + switch (variable - 0x70) { case 0x80: value = st->facilities; break; case 0x81: value = st->airport_type; break; case 0x82: value = st->truck_stops->status; break; @@ -229,10 +230,8 @@ const RealSpriteGroup *rsg = ResolveStationSpriteGroup(spec->spritegroup[ctype], st); if (rsg == NULL) return 0; - if (rsg->sprites_per_set != 0) { - if (rsg->loading_count != 0) return rsg->loading[0]->g.result.result; - if (rsg->loaded_count != 0) return rsg->loaded[0]->g.result.result; - } + if (rsg->num_loading != 0) return rsg->loading[0]->g.result.sprite; + if (rsg->num_loaded != 0) return rsg->loaded[0]->g.result.sprite; DEBUG(grf, 6)("Custom station 0x%08x::0x%02x has no sprites associated.", spec->grfid, spec->localidx);
--- a/sprite.c +++ b/sprite.c @@ -11,27 +11,27 @@ { int i; - value >>= dsg->shift_num; // This should bring us to the byte range. - value &= dsg->and_mask; + value >>= dsg->adjusts[0].shift_num; // This should bring us to the byte range. + value &= dsg->adjusts[0].and_mask; - if (dsg->operation != DSG_OP_NONE) - value += (signed char) dsg->add_val; + if (dsg->adjusts[0].operation != DSGA_TYPE_NONE) + value += (signed char) dsg->adjusts[0].add_val; - switch (dsg->operation) { - case DSG_OP_DIV: - value /= (signed char) dsg->divmod_val; + switch (dsg->adjusts[0].type) { + case DSGA_TYPE_DIV: + value /= (signed char) dsg->adjusts[0].divmod_val; break; - case DSG_OP_MOD: - value %= (signed char) dsg->divmod_val; + case DSGA_TYPE_MOD: + value %= (signed char) dsg->adjusts[0].divmod_val; break; - case DSG_OP_NONE: + case DSGA_TYPE_NONE: break; } for (i = 0; i < dsg->num_ranges; i++) { DeterministicSpriteGroupRange *range = &dsg->ranges[i]; - if (range->low <= value && value <= range->high) + if (range->low <= (uint32)value && (uint32)value <= range->high) return range->group; }