While implementing the latest 3.3 features for my variant, one of my test runs crashed in which_pval() with an assertion failure.
Tracing back the error in debug mode, I found out that the game crashed while trying to generate a specific item (ego):
- item kind (from object.txt):
N:578:& Pair~ of Witan Boots
G:]:b
I:30:7
W:60:0:80:5000
A:10:60 to 100
P:10:1d1:0:0:5
F:IGNORE_ACID | IGNORE_COLD | IGNORE_FIRE | IGNORE_ELEC
L:-2:STEALTH
- ego kind (from ego_item.txt):
N:57f Stealth
X:16:0
W:0:6
T:30:0:99
F:HIDE_TYPE
L:d3:0:STEALTH
Looking at the object_type fields, it seems that the game generated an ego with +2 to stealth, leading to the following inconsistencies:
- o_ptr->num_pvals = 1
- o_ptr->pval[0] = 0;
- o_ptr->flags contains OF_STEALTH
This explains the crash: trying to access the pval for "stealth" when there is actually none...
First problem: o_ptr->flags contains OF_STEALTH
In ego_apply_magic(), ego flags are added to object flags AFTER applying pvals:
In object_add_pval(), if the resulting pval is zero, the flag is removed:
Fix: don't add flags that are removed from o_ptr->ego->flags to o_ptr->flags again
Second problem: o_ptr->num_pvals = 1
In object_dedup_pvals(), pvals are moved down and num_pvals is decremented when pval is zero:
Fix: apply the same code in object_add_pval() when pval = 0
Tracing back the error in debug mode, I found out that the game crashed while trying to generate a specific item (ego):
- item kind (from object.txt):
N:578:& Pair~ of Witan Boots
G:]:b
I:30:7
W:60:0:80:5000
A:10:60 to 100
P:10:1d1:0:0:5
F:IGNORE_ACID | IGNORE_COLD | IGNORE_FIRE | IGNORE_ELEC
L:-2:STEALTH
- ego kind (from ego_item.txt):
N:57f Stealth
X:16:0
W:0:6
T:30:0:99
F:HIDE_TYPE
L:d3:0:STEALTH
Looking at the object_type fields, it seems that the game generated an ego with +2 to stealth, leading to the following inconsistencies:
- o_ptr->num_pvals = 1
- o_ptr->pval[0] = 0;
- o_ptr->flags contains OF_STEALTH
This explains the crash: trying to access the pval for "stealth" when there is actually none...
First problem: o_ptr->flags contains OF_STEALTH
In ego_apply_magic(), ego flags are added to object flags AFTER applying pvals:
Code:
/* Apply pvals */ for (i = 0; i < o_ptr->ego->num_pvals; i++) { of_copy(flags, o_ptr->ego->pval_flags[i]); x = randcalc(o_ptr->ego->pval[i], level, RANDOMISE); for (flag = of_next(flags, FLAG_START); flag != FLAG_END; flag = of_next(flags, flag + 1)) object_add_pval(o_ptr, x, flag); } /* Apply flags */ of_union(o_ptr->flags, o_ptr->ego->flags);
Code:
if (o_ptr->pval[a] == 0) { /* Remove the flag */ of_off(o_ptr->flags, flag); of_off(o_ptr->pval_flags[a], flag); }
Second problem: o_ptr->num_pvals = 1
In object_dedup_pvals(), pvals are moved down and num_pvals is decremented when pval is zero:
Code:
/* Move any remaining pvals down one to fill the void */ for (k = j + 1; k < o_ptr->num_pvals; k++) { of_copy(o_ptr->pval_flags[k - 1], o_ptr->pval_flags[k]); of_wipe(o_ptr->pval_flags[k]); o_ptr->pval[k - 1] = o_ptr->pval[k]; o_ptr->pval[k] = 0; } /* We now have one fewer pval */ o_ptr->num_pvals--;
Comment