Fix stat reversion on boot

This commit is contained in:
kinther 2025-10-25 14:33:56 -07:00
parent ed8ee4aa5f
commit 89a1643c04
3 changed files with 63 additions and 81 deletions

View file

@ -12,8 +12,8 @@ call his stature bulky, as he has quite a bit of muscle.
1 3d20+40
8 8 1
Str: 16
Dex: 14
Con: 14
SaveStr: 3
Skill 134 60
E
L 3 118 1
L 5 131 1
@ -40,9 +40,6 @@ her nose.
2122 0 0 0 0 0 0 0 0 E
1 3d20+40
8 8 2
Str: 14
Dex: 18
Con: 14
E
L 17 127 1
L 16 117 1
@ -69,9 +66,6 @@ others.
10 0 0 0 0 0 0 0 0 E
1 3d12+60
8 8 1
Str: 18
Int: 12
Con: 18
E
L 14 113 1
L 9 112 1
@ -90,9 +84,5 @@ appear slightly bloodshot.
10 0 0 0 0 0 0 0 0 E
1 3d8+60
8 8 2
Str: 12
Dex: 14
Con: 14
Cha: 14
E
$

View file

@ -1596,6 +1596,28 @@ static void parse_simple_mob(FILE *mob_f, int i, int nr)
GET_SAVE(mob_proto + i, j) = 0;
}
static void parse_espec(char *buf, int i, int nr)
{
char *ptr;
/* Split on ':' if present (e.g., "Str: 16") */
if ((ptr = strchr(buf, ':')) != NULL) {
*(ptr++) = '\0';
while (isspace(*ptr))
ptr++;
} else {
/* No colon: treat the remainder as value start (may be NULL) */
ptr = NULL;
}
/* Trim leading spaces from keyword */
while (isspace(*buf))
buf++;
/* Always route to interpret_espec so we only write to real_abils there. */
interpret_espec(buf, ptr, i, nr);
}
/* interpret_espec is the function that takes espec keywords and values and
* assigns the correct value to the mob as appropriate. Adding new e-specs is
* straightforward: just add a new CASE() block. */
@ -1608,40 +1630,41 @@ static void interpret_espec(const char *keyword, const char *value, int i, int n
{
int num_arg = 0;
bool matched = FALSE;
bool touched_ability = FALSE;
/* Defensive check: if there's a value, convert to int */
if (value)
num_arg = atoi(value);
/* --- Ability Scores --- */
/* --- Ability Scores (write REAL, then sync AFF) --- */
CASE("Str") {
RANGE(3, 25);
mob_proto[i].real_abils.str = num_arg;
touched_ability = TRUE;
}
CASE("Dex") {
RANGE(3, 25);
mob_proto[i].real_abils.dex = num_arg;
touched_ability = TRUE;
}
CASE("Con") {
RANGE(3, 25);
mob_proto[i].real_abils.con = num_arg;
touched_ability = TRUE;
}
CASE("Int") {
RANGE(3, 25);
mob_proto[i].real_abils.intel = num_arg;
touched_ability = TRUE;
}
CASE("Wis") {
RANGE(3, 25);
mob_proto[i].real_abils.wis = num_arg;
touched_ability = TRUE;
}
CASE("Cha") {
RANGE(3, 25);
mob_proto[i].real_abils.cha = num_arg;
touched_ability = TRUE;
}
/* --- 5e-style Saving Throws --- */
@ -1649,32 +1672,31 @@ static void interpret_espec(const char *keyword, const char *value, int i, int n
RANGE(0, 100);
mob_proto[i].char_specials.saved.saving_throws[ABIL_STR] = num_arg;
}
CASE("SaveDex") {
RANGE(0, 100);
mob_proto[i].char_specials.saved.saving_throws[ABIL_DEX] = num_arg;
}
CASE("SaveCon") {
RANGE(0, 100);
mob_proto[i].char_specials.saved.saving_throws[ABIL_CON] = num_arg;
}
CASE("SaveInt") {
RANGE(0, 100);
mob_proto[i].char_specials.saved.saving_throws[ABIL_INT] = num_arg;
}
CASE("SaveWis") {
RANGE(0, 100);
mob_proto[i].char_specials.saved.saving_throws[ABIL_WIS] = num_arg;
}
CASE("SaveCha") {
RANGE(0, 100);
mob_proto[i].char_specials.saved.saving_throws[ABIL_CHA] = num_arg;
}
/* If we changed a base ability, keep aff_abils in sync for the prototype. */
if (touched_ability)
mob_proto[i].aff_abils = mob_proto[i].real_abils;
/* --- Debug + Fallback --- */
if (!matched) {
log("DEBUG: Unmatched espec line '%s' value '%s' in mob #%d",
@ -1684,58 +1706,10 @@ static void interpret_espec(const char *keyword, const char *value, int i, int n
}
}
/* Prevent macro bleed outside this functions scope */
/* Prevent macro bleed */
#undef CASE
#undef RANGE
static void parse_espec(char *buf, int i, int nr)
{
char *ptr;
int value;
/* Split on ':' if present (e.g., "Str: 16") */
if ((ptr = strchr(buf, ':')) != NULL) {
*(ptr++) = '\0';
while (isspace(*ptr))
ptr++;
}
/* Trim leading spaces from keyword */
while (isspace(*buf))
buf++;
/* --- Handle ability score lines --- */
if (!str_cmp(buf, "Str") && sscanf(ptr, "%d", &value) == 1)
GET_STR(mob_proto + i) = LIMIT(value, 3, 25);
else if (!str_cmp(buf, "Dex") && sscanf(ptr, "%d", &value) == 1)
GET_DEX(mob_proto + i) = LIMIT(value, 3, 25);
else if (!str_cmp(buf, "Int") && sscanf(ptr, "%d", &value) == 1)
GET_INT(mob_proto + i) = LIMIT(value, 3, 25);
else if (!str_cmp(buf, "Wis") && sscanf(ptr, "%d", &value) == 1)
GET_WIS(mob_proto + i) = LIMIT(value, 3, 25);
else if (!str_cmp(buf, "Con") && sscanf(ptr, "%d", &value) == 1)
GET_CON(mob_proto + i) = LIMIT(value, 3, 25);
else if (!str_cmp(buf, "Cha") && sscanf(ptr, "%d", &value) == 1)
GET_CHA(mob_proto + i) = LIMIT(value, 3, 25);
/* --- Optional saving throw support (if you use these in files) --- */
else if (!str_cmp(buf, "SaveStr") && sscanf(ptr, "%d", &value) == 1)
GET_SAVE(mob_proto + i, ABIL_STR) = value;
else if (!str_cmp(buf, "SaveDex") && sscanf(ptr, "%d", &value) == 1)
GET_SAVE(mob_proto + i, ABIL_DEX) = value;
else if (!str_cmp(buf, "SaveCon") && sscanf(ptr, "%d", &value) == 1)
GET_SAVE(mob_proto + i, ABIL_CON) = value;
else if (!str_cmp(buf, "SaveInt") && sscanf(ptr, "%d", &value) == 1)
GET_SAVE(mob_proto + i, ABIL_INT) = value;
else if (!str_cmp(buf, "SaveWis") && sscanf(ptr, "%d", &value) == 1)
GET_SAVE(mob_proto + i, ABIL_WIS) = value;
else if (!str_cmp(buf, "SaveCha") && sscanf(ptr, "%d", &value) == 1)
GET_SAVE(mob_proto + i, ABIL_CHA) = value;
/* --- Fallback: hand off anything else to the old interpreter --- */
else
interpret_espec(buf, ptr, i, nr);
}
static void parse_enhanced_mob(FILE *mob_f, int i, int nr)
{

View file

@ -230,8 +230,14 @@ static void init_mobile(struct char_data *mob)
GET_WEIGHT(mob) = 200;
GET_HEIGHT(mob) = 198;
mob->real_abils.str = mob->real_abils.intel = mob->real_abils.wis = 11;
mob->real_abils.dex = mob->real_abils.con = mob->real_abils.cha = 11;
/* Only assign defaults if the individual stat is unset (zero) */
if (!mob->real_abils.str) mob->real_abils.str = 11;
if (!mob->real_abils.intel) mob->real_abils.intel = 11;
if (!mob->real_abils.wis) mob->real_abils.wis = 11;
if (!mob->real_abils.dex) mob->real_abils.dex = 11;
if (!mob->real_abils.con) mob->real_abils.con = 11;
if (!mob->real_abils.cha) mob->real_abils.cha = 11;
mob->aff_abils = mob->real_abils;
for (i = 0; i < NUM_ABILITIES; i++)
@ -1061,27 +1067,39 @@ void medit_parse(struct descriptor_data *d, char *arg)
case MEDIT_SAVE_STR:
GET_SAVE(OLC_MOB(d), ABIL_STR) = LIMIT(atoi(arg), -20, 20);
break;
OLC_VAL(d) = TRUE;
medit_disp_stats_menu(d);
return;
case MEDIT_SAVE_DEX:
GET_SAVE(OLC_MOB(d), ABIL_DEX) = LIMIT(atoi(arg), -20, 20);
break;
OLC_VAL(d) = TRUE;
medit_disp_stats_menu(d);
return;
case MEDIT_SAVE_CON:
GET_SAVE(OLC_MOB(d), ABIL_CON) = LIMIT(atoi(arg), -20, 20);
break;
OLC_VAL(d) = TRUE;
medit_disp_stats_menu(d);
return;
case MEDIT_SAVE_INT:
GET_SAVE(OLC_MOB(d), ABIL_INT) = LIMIT(atoi(arg), -20, 20);
break;
OLC_VAL(d) = TRUE;
medit_disp_stats_menu(d);
return;
case MEDIT_SAVE_WIS:
GET_SAVE(OLC_MOB(d), ABIL_WIS) = LIMIT(atoi(arg), -20, 20);
break;
OLC_VAL(d) = TRUE;
medit_disp_stats_menu(d);
return;
case MEDIT_SAVE_CHA:
GET_SAVE(OLC_MOB(d), ABIL_CHA) = LIMIT(atoi(arg), -20, 20);
break;
OLC_VAL(d) = TRUE;
medit_disp_stats_menu(d);
return;
case MEDIT_POS:
GET_POS(OLC_MOB(d)) = LIMIT(i - 1, 0, NUM_POSITIONS - 1);