More oedit updates and new objects

This commit is contained in:
kinther 2025-08-25 15:27:42 -07:00
parent 9efab96518
commit 0815cd6a96
5 changed files with 331 additions and 122 deletions

View file

@ -6,4 +6,172 @@ Some padded armor has been discarded here.~
9 0 0 0 0 ad 0 0 0 0 0 0 0
1 1 0 0
10 4 0 0 0
#101
erdlu leather armor~
some erdlu leather armor~
An unfinished object is lying here.~
~
9 0 0 0 0 ad 0 0 0 0 0 0 0
1 1 0 0
5 5 0 0 0
#102
studded leather jacket~
a studded leather jacket~
A jacket made from studded leather lies here.~
~
9 0 0 0 0 ad 0 0 0 0 0 0 0
2 1 0 0
13 10 0 0 0
#103
bone chitin armor~
some bone and chitin armor~
A piece of armor made from bone and chitin lies here.~
~
9 0 0 0 0 ad 0 0 0 0 0 0 0
1 1 0 0
20 12 0 0 0
#104
pair padded sleeves~
a pair of padded sleeves~
A pair of padded cloth sleeves lie here abandoned.~
~
9 0 0 0 0 ai 0 0 0 0 0 0 0
1 1 0 0
5 10 0 0 0
#105
pair padded leggings~
a pair of padded leggings~
A pair of padded leggings lie here in the dust.~
~
9 0 0 0 0 af 0 0 0 0 0 0 0
1 1 0 0
5 10 0 0 0
#106
pair cloth gloves~
a pair of cloth gloves~
A pair of yellowed cloth gloves lie here.~
~
11 0 0 0 0 ah 0 0 0 0 0 0 0
0 0 0 0
2 10 0 0 0
#107
pair leather gloves~
a pair of leather gloves~
A pair of thick leather gloves have been left here.~
~
9 0 0 0 0 ah 0 0 0 0 0 0 0
1 1 0 0
6 10 0 0 0
#108
bone helmet~
a bone helmet~
A helmet made of bone has been discarded here.~
~
9 0 0 0 0 ae 0 0 0 0 0 0 0
1 1 0 0
12 18 0 0 0
#109
padded cloth helmet~
a padded cloth helmet~
A padded cloth helmet has been left here.~
~
9 0 0 0 0 ae 0 0 0 0 0 0 0
1 1 0 0
4 11 0 0 0
#110
braxat hide jacket~
a braxat hide jacket~
A thick jacket made of braxat hide has been abandoned here.~
~
9 0 0 0 0 ad 0 0 0 0 0 0 0
3 3 0 1
30 250 0 0 0
#111
pair thick leather sleeves~
a pair of thick leather sleeves~
Cured and stitched tight, a pair of thick leather sleeves are here.~
~
9 0 0 0 0 ai 0 0 0 0 0 0 0
1 1 0 0
14 30 0 0 0
#112
pair sandals~
a pair of sandals~
Some cheap looking sandals have been left in the dust here.~
~
11 0 0 0 0 ag 0 0 0 0 0 0 0
0 0 0 0
1 8 0 0 0
#113
loincloth~
a loincloth~
A scrap of cloth with a string attached has been left here.~
~
11 0 0 0 0 al 0 0 0 0 0 0 0
0 0 0 0
1 1 0 0 0
#114
erdlu scale shield~
an erdlu scale shield~
A shield made from erdlu scales lies here, collecting dust.~
~
9 0 0 0 0 aj 0 0 0 0 0 0 0
0 0 0 0
5 50 0 0 0
#115
pair thick leather leggings~
a pair of thick leather leggings~
A pair of leggings made from thick, dark leather are here.~
~
9 0 0 0 0 af 0 0 0 0 0 0 0
1 1 0 0
12 50 0 0 0
#116
hide wrist wrap wrist-wrap~
a hide wrist-wrap~
A simple hide wrist-wrap gathers dust and sand here.~
~
9 0 0 0 0 am 0 0 0 0 0 0 0
1 1 0 0
2 25 0 0 0
#117
studded hide wrist wrap wrist-wrap~
a studded hide wrist-wrap~
A hide wrist-wrap with studded bone bits has been left here.~
~
9 0 0 0 0 am 0 0 0 0 0 0 0
1 1 0 0
8 40 0 0 0
#118
padded neckguard~
a padded neckguard~
A padded neckguard made of cloth is here.~
~
9 0 0 0 0 ac 0 0 0 0 0 0 0
1 1 0 0
5 25 0 0 0
#119
pair padded shoes~
a pair of padded shoes~
An assuming pair of padded cloth shoes are here.~
~
9 0 0 0 0 ag 0 0 0 0 0 0 0
1 1 0 0
8 25 0 0 0
#120
black belt~
a black belt~
A belt made of black cloth lies here.~
~
15 0 0 0 0 al 0 0 0 0 0 0 0
10 0 0 0
1 25 0 0 0
#121
unfinished object~
a small bag~
An unfinished object is lying here.~
~
0 0 0 0 0 a 0 0 0 0 0 0 0
0 0 0 0
0 0 0 0 0
$~

View file

@ -984,8 +984,8 @@ static void do_stat_object(struct char_data *ch, struct obj_data *j)
struct char_data *tempch;
send_to_char(ch, "Name: '%s%s%s', Keywords: %s\r\n", CCYEL(ch, C_NRM),
j->short_description ? j->short_description : "<None>",
CCNRM(ch, C_NRM), j->name);
j->short_description ? j->short_description : "<None>",
CCNRM(ch, C_NRM), j->name);
vnum = GET_OBJ_VNUM(j);
sprinttype(GET_OBJ_TYPE(j), item_types, buf, sizeof(buf));
@ -994,12 +994,12 @@ static void do_stat_object(struct char_data *ch, struct obj_data *j)
GET_OBJ_SPEC(j) ? (get_spec_func_name(GET_OBJ_SPEC(j))) : "None");
send_to_char(ch, "L-Desc: '%s%s%s'\r\n", CCYEL(ch, C_NRM),
j->description ? j->description : "<None>",
CCNRM(ch, C_NRM));
j->description ? j->description : "<None>",
CCNRM(ch, C_NRM));
send_to_char(ch, "A-Desc: '%s%s%s'\r\n", CCYEL(ch, C_NRM),
j->action_description ? j->action_description : "<None>",
CCNRM(ch, C_NRM));
j->action_description ? j->action_description : "<None>",
CCNRM(ch, C_NRM));
if (j->ex_description) {
send_to_char(ch, "Extra descs:%s", CCCYN(ch, C_NRM));
@ -1021,7 +1021,7 @@ static void do_stat_object(struct char_data *ch, struct obj_data *j)
GET_OBJ_WEIGHT(j), GET_OBJ_COST(j), GET_OBJ_RENT(j), GET_OBJ_TIMER(j), GET_OBJ_LEVEL(j));
send_to_char(ch, "In room: %d (%s), ", GET_ROOM_VNUM(IN_ROOM(j)),
IN_ROOM(j) == NOWHERE ? "Nowhere" : world[IN_ROOM(j)].name);
IN_ROOM(j) == NOWHERE ? "Nowhere" : world[IN_ROOM(j)].name);
send_to_char(ch, "In object: %s, ", j->in_obj ? j->in_obj->short_description : "None");
send_to_char(ch, "Carried by: %s, ", j->carried_by ? GET_NAME(j->carried_by) : "Nobody");
@ -1034,81 +1034,109 @@ static void do_stat_object(struct char_data *ch, struct obj_data *j)
else
send_to_char(ch, "Hours left: [%d]\r\n", GET_OBJ_VAL(j, 2));
break;
case ITEM_SCROLL:
case ITEM_POTION:
send_to_char(ch, "Spells: (Level %d) %s, %s, %s\r\n", GET_OBJ_VAL(j, 0),
skill_name(GET_OBJ_VAL(j, 1)), skill_name(GET_OBJ_VAL(j, 2)),
skill_name(GET_OBJ_VAL(j, 3)));
skill_name(GET_OBJ_VAL(j, 1)), skill_name(GET_OBJ_VAL(j, 2)),
skill_name(GET_OBJ_VAL(j, 3)));
break;
case ITEM_WAND:
case ITEM_STAFF:
send_to_char(ch, "Spell: %s at level %d, %d (of %d) charges remaining\r\n",
skill_name(GET_OBJ_VAL(j, 3)), GET_OBJ_VAL(j, 0),
GET_OBJ_VAL(j, 2), GET_OBJ_VAL(j, 1));
skill_name(GET_OBJ_VAL(j, 3)), GET_OBJ_VAL(j, 0),
GET_OBJ_VAL(j, 2), GET_OBJ_VAL(j, 1));
break;
case ITEM_WEAPON:
send_to_char(ch, "Todam: %dd%d, Avg Damage: %.1f. Message type: %s\r\n",
GET_OBJ_VAL(j, 1), GET_OBJ_VAL(j, 2),
((GET_OBJ_VAL(j, 2) + 1) / 2.0) * GET_OBJ_VAL(j, 1),
attack_hit_text[GET_OBJ_VAL(j, 3)].singular);
GET_OBJ_VAL(j, 1), GET_OBJ_VAL(j, 2),
((GET_OBJ_VAL(j, 2) + 1) / 2.0) * GET_OBJ_VAL(j, 1),
attack_hit_text[GET_OBJ_VAL(j, 3)].singular);
break;
case ITEM_ARMOR:
send_to_char(ch, "AC-apply: [%d]\r\n", GET_OBJ_VAL(j, 0));
case ITEM_ARMOR: {
/* New: show armor-specific semantic fields */
int piece_ac = GET_OBJ_VAL(j, VAL_ARMOR_PIECE_AC);
int bulk = GET_OBJ_VAL(j, VAL_ARMOR_BULK);
int magic_bonus= GET_OBJ_VAL(j, VAL_ARMOR_MAGIC_BONUS);
int stealth = GET_OBJ_VAL(j, VAL_ARMOR_STEALTH_DISADV);
int durability = GET_OBJ_VAL(j, VAL_ARMOR_DURABILITY);
int str_req = GET_OBJ_VAL(j, VAL_ARMOR_STR_REQ);
send_to_char(ch,
"Armor:\r\n"
" piece_ac : %d\r\n"
" bulk : %d\r\n"
" magic_bonus : %d\r\n"
" stealth_disadv : %s\r\n"
" durability : %d\r\n"
" str_requirement: %d\r\n",
piece_ac, bulk, magic_bonus,
YESNO(stealth), durability, str_req);
break;
case ITEM_CONTAINER:
}
case ITEM_CONTAINER: {
sprintbit(GET_OBJ_VAL(j, 1), container_bits, buf, sizeof(buf));
send_to_char(ch, "Weight capacity: %d, Lock Type: %s, Key Num: %d, Corpse: %s\r\n",
GET_OBJ_VAL(j, 0), buf, GET_OBJ_VAL(j, 2),
YESNO(GET_OBJ_VAL(j, 3)));
GET_OBJ_VAL(j, 0), buf, GET_OBJ_VAL(j, 2),
YESNO(GET_OBJ_VAL(j, 3)));
break;
}
case ITEM_DRINKCON:
case ITEM_FOUNTAIN:
case ITEM_FOUNTAIN: {
sprinttype(GET_OBJ_VAL(j, 2), drinks, buf, sizeof(buf));
send_to_char(ch, "Capacity: %d, Contains: %d, Poisoned: %s, Liquid: %s\r\n",
GET_OBJ_VAL(j, 0), GET_OBJ_VAL(j, 1),
YESNO(GET_OBJ_VAL(j, 3)), buf);
GET_OBJ_VAL(j, 0), GET_OBJ_VAL(j, 1), YESNO(GET_OBJ_VAL(j, 3)), buf);
break;
}
case ITEM_NOTE:
send_to_char(ch, "Tongue: %d\r\n", GET_OBJ_VAL(j, 0));
break;
case ITEM_KEY: /* Nothing */
break;
case ITEM_FOOD:
send_to_char(ch, "Makes full: %d, Poisoned: %s\r\n",
GET_OBJ_VAL(j, 0), YESNO(GET_OBJ_VAL(j, 3)));
send_to_char(ch, "Makes full: %d, Poisoned: %s\r\n", GET_OBJ_VAL(j, 0), YESNO(GET_OBJ_VAL(j, 3)));
break;
case ITEM_MONEY:
send_to_char(ch, "Coins: %d\r\n", GET_OBJ_VAL(j, 0));
break;
case ITEM_FURNITURE:
send_to_char(ch, "Can hold: [%d] Num. of People in: [%d]\r\n",
GET_OBJ_VAL(j, 0), GET_OBJ_VAL(j, 1));
send_to_char(ch, "Can hold: [%d] Num. of People in: [%d]\r\n", GET_OBJ_VAL(j, 0), GET_OBJ_VAL(j, 1));
send_to_char(ch, "Holding : ");
for (tempch = OBJ_SAT_IN_BY(j); tempch; tempch = NEXT_SITTING(tempch))
send_to_char(ch, "%s ", GET_NAME(tempch));
send_to_char(ch, "\r\n");
break;
default: {
send_to_char(ch, "Values:");
for (i = 0; i < NUM_OBJ_VAL_POSITIONS; i++) {
send_to_char(ch, " [%d]", GET_OBJ_VAL(j, i));
}
send_to_char(ch, "\r\n");
default:
/* No special pretty-print */
break;
}
}
/* Always show raw values dynamically for debugging/visibility */
send_to_char(ch, "Values 0..%d:", NUM_OBJ_VAL_POSITIONS - 1);
for (i = 0; i < NUM_OBJ_VAL_POSITIONS; i++)
send_to_char(ch, " [%d]", GET_OBJ_VAL(j, i));
send_to_char(ch, "\r\n");
if (j->contains) {
int column;
send_to_char(ch, "\r\nContents:%s", CCGRN(ch, C_NRM));
column = 9;
for (found = 0, j2 = j->contains; j2; j2 = j2->next_content) {
column += send_to_char(ch, "%s %s", found++ ? "," : "", j2->short_description);
if (column >= 62) {
send_to_char(ch, "%s\r\n", j2->next_content ? "," : "");
found = FALSE;
send_to_char(ch, "%s\r\n", j2->next_content ? "," : "");
found = FALSE;
column = 0;
}
}
@ -1120,8 +1148,7 @@ static void do_stat_object(struct char_data *ch, struct obj_data *j)
for (i = 0; i < MAX_OBJ_AFFECT; i++)
if (j->affected[i].modifier) {
sprinttype(j->affected[i].location, apply_types, buf, sizeof(buf));
send_to_char(ch, "%s %+d to %s",
found++ ? "," : "", j->affected[i].modifier, buf);
send_to_char(ch, "%s %+d to %s", found++ ? "," : "", j->affected[i].modifier, buf);
}
if (!found)
send_to_char(ch, " None");
@ -5618,7 +5645,7 @@ ACMD(do_acaudit)
for (obj_rnum r = 0; r <= top_of_objt; r++) {
struct obj_data *obj = &obj_proto[r];
char namebuf[128] = {0};
int idx, vnum, piece_ac, bulk, magic, flags;
int idx, vnum, piece_ac, bulk, magic, stealth, strreq;
if (GET_OBJ_TYPE(obj) != ITEM_ARMOR)
continue;
@ -5632,7 +5659,8 @@ ACMD(do_acaudit)
piece_ac = GET_OBJ_VAL(obj, VAL_ARMOR_PIECE_AC);
bulk = GET_OBJ_VAL(obj, VAL_ARMOR_BULK);
magic = GET_OBJ_VAL(obj, VAL_ARMOR_MAGIC_BONUS);
flags = GET_OBJ_VAL(obj, VAL_ARMOR_FLAGS);
stealth = GET_OBJ_VAL(obj, VAL_ARMOR_STEALTH_DISADV); /* 1/0, yes or no */
strreq = GET_OBJ_VAL(obj, VAL_ARMOR_STR_REQ); /* 0 or 13/15/16 typically */
/* Display name (trim to keep line width < ~78 cols) */
if (obj->short_description)
@ -5656,14 +5684,14 @@ ACMD(do_acaudit)
found++;
/* Compact, non-wrapping row (~70 cols worst case) */
APPEND_FMT("\tc[#%5d]\tn %-24.24s sl=%-5.5s ac=%2d%s b=%d%s m=%+d%s f=%d%s\r\n",
APPEND_FMT("\tc[#%5d]\tn %-24.24s sl=%-5.5s ac=%2d%s b=%d%s m=%+d%s sd=%d str=%d\r\n",
vnum,
namebuf,
slot_name_from_index(idx),
piece_ac, over_ac ? " \tR!\tn" : (bad_ac ? " \tY?\tn" : ""),
bulk, bad_bulk ? " \tY?\tn" : "",
magic, over_magic ? " \tR!\tn" : (bad_magic? " \tY?\tn" : ""),
flags, (flags & ARMF_STEALTH_DISADV) ? " S" : "");
stealth, strreq);
if (over_ac || over_magic || bad_ac || bad_bulk || bad_magic)
warned++;

View file

@ -72,8 +72,8 @@ static const char *weapon_val_labels[NUM_OBJ_VAL_POSITIONS] = {
/* Armor */
static const char *armor_val_labels[NUM_OBJ_VAL_POSITIONS] = {
"piece_ac", "bulk", "magic_bonus", "flags",
"durability", "Value[5]", "Value[6]", "Value[7]"
"piece_ac", "bulk", "magic_bonus", "stealth_disadv",
"durability", "str_requirement", "Value[6]", "Value[7]"
};
/* Container */
@ -1041,51 +1041,80 @@ void oedit_parse(struct descriptor_data *d, char *arg)
break;
case OEDIT_VALUE_X:
{
int i = OLC_VAL(d);
int number = atoi(arg);
{
int i = OLC_VAL(d);
int number = atoi(arg);
if (GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_WEAPON && i == 2) {
if (number < 0 || number >= NUM_ATTACK_TYPES) {
oedit_disp_weapon_menu(d);
return;
/* --- Armor-specific semantics --- */
if (GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_ARMOR) {
if (i == VAL_ARMOR_STEALTH_DISADV /* 3 */) {
/* clamp to 0/1 */
GET_OBJ_VAL(OLC_OBJ(d), i) = (number != 0) ? 1 : 0;
oedit_disp_values_menu(d);
return;
}
if (i == VAL_ARMOR_STR_REQ /* 5 */) {
/* 0 disables the requirement; otherwise accept a sane STR range */
if (number < 0 || number > 25) {
write_to_output(d, "Enter STR requirement (0 disables, 3..25 typical): ");
return; /* stay in OEDIT_VALUE_X for a valid number */
}
GET_OBJ_VAL(OLC_OBJ(d), i) = number;
oedit_disp_values_menu(d);
return;
}
else if ((GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_SCROLL ||
GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_POTION ||
GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_WAND ||
GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_STAFF) &&
(i == 1 || i == 2 || i == 3)) {
if (number < 0 || number >= NUM_SPELLS) {
oedit_disp_spells_menu(d);
return;
}
GET_OBJ_VAL(OLC_OBJ(d), i) = number;
}
else if ((GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_DRINKCON ||
GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_FOUNTAIN) &&
i == 2) {
if (number < 0 || number >= NUM_LIQ_TYPES) {
oedit_liquid_type(d);
return;
}
GET_OBJ_VAL(OLC_OBJ(d), i) = number;
}
else if (GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_CONTAINER && i == 1) {
if (number < 0 || number >= NUM_CONTAINER_FLAGS) {
oedit_disp_container_flags_menu(d);
return;
}
TOGGLE_BIT(GET_OBJ_VAL(OLC_OBJ(d), i), 1 << number);
}
else {
GET_OBJ_VAL(OLC_OBJ(d), i) = number;
}
oedit_disp_values_menu(d);
}
/* --- Existing special cases (weapon/liquid/spells/container) remain here --- */
if (GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_WEAPON && i == 2) {
if (number < 0 || number >= NUM_ATTACK_TYPES) {
oedit_disp_weapon_menu(d);
return;
}
GET_OBJ_VAL(OLC_OBJ(d), i) = number;
oedit_disp_values_menu(d);
return;
}
else if ((GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_SCROLL ||
GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_POTION ||
GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_WAND ||
GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_STAFF) &&
(i == 1 || i == 2 || i == 3)) {
if (number < 0 || number >= NUM_SPELLS) {
oedit_disp_spells_menu(d);
return;
}
GET_OBJ_VAL(OLC_OBJ(d), i) = number;
oedit_disp_values_menu(d);
return;
}
else if ((GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_DRINKCON ||
GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_FOUNTAIN) &&
i == 2) {
if (number < 0 || number >= NUM_LIQ_TYPES) {
oedit_liquid_type(d);
return;
}
GET_OBJ_VAL(OLC_OBJ(d), i) = number;
oedit_disp_values_menu(d);
return;
}
else if (GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_CONTAINER && i == 1) {
extern const int NUM_CONTAINER_FLAGS;
if (number < 0 || number >= NUM_CONTAINER_FLAGS) {
oedit_disp_container_flags_menu(d);
return;
}
TOGGLE_BIT(GET_OBJ_VAL(OLC_OBJ(d), i), 1 << number);
oedit_disp_values_menu(d);
return;
}
/* --- Default assignment for other slots/types --- */
GET_OBJ_VAL(OLC_OBJ(d), i) = number;
oedit_disp_values_menu(d);
return;
}
/* === Apply editing === */
case OEDIT_PROMPT_APPLY:

View file

@ -1285,20 +1285,16 @@ struct recent_player
* value[0] = piece_ac (03)
* value[1] = bulk (03), determines allowed dex bonus
* value[2] = magic_bonus (03, most will be at most +1)
* value[3] = armor flags (bitvector, see ARMF_*)
* value[3] = if an armor piece imposes stealth disadvantage for some reason
* value[4] = durability, or how much damage an item can take before breaking (usually 100)
* value[5] = strength requirement to wear armor piece
*/
#define VAL_ARMOR_PIECE_AC 0
#define VAL_ARMOR_BULK 1
#define VAL_ARMOR_MAGIC_BONUS 2
#define VAL_ARMOR_FLAGS 3
#define VAL_ARMOR_DURABILITY 4
/* Armor-specific flags stored in obj->value[3] */
#define ARMF_STEALTH_DISADV (1 << 0) /* Disadvantage on Stealth checks */
#define ARMF_REQ_STR15 (1 << 1) /* Requires STR 15 to wear */
#define ARMF_RESERVED2 (1 << 2) /* Reserved for future use */
#define ARMF_RESERVED3 (1 << 3) /* Reserved */
#define VAL_ARMOR_PIECE_AC 0
#define VAL_ARMOR_BULK 1
#define VAL_ARMOR_MAGIC_BONUS 2
#define VAL_ARMOR_STEALTH_DISADV 3
#define VAL_ARMOR_DURABILITY 4
#define VAL_ARMOR_STR_REQ 5
/* Config structs */

View file

@ -1597,37 +1597,25 @@ static int dex_cap_from_bulk(int total_bulk) {
/* --- Stealth disadvantage detector ---
* Returns TRUE if:
* - Any worn armor piece has ARMF_STEALTH_DISADV, or
* - Total bulk category is Heavy (Dex cap == 0).
* - Any worn armor piece has VAL_ARMOR_STEALTH_DISADV set to 1
*/
bool has_stealth_disadv(struct char_data *ch) {
bool has_stealth_disadv(struct char_data *ch)
{
int i;
struct obj_data *obj;
if (!ch) return FALSE;
int total_bulk = 0;
bool piece_imposes = FALSE;
for (i = 0; i < NUM_WEARS; i++) {
obj = GET_EQ(ch, i);
if (!obj) continue;
if (GET_OBJ_TYPE(obj) != ITEM_ARMOR) continue;
for (int i = 0; i < NUM_ARMOR_SLOTS; i++) {
int wear_pos = ARMOR_WEAR_POSITIONS[i];
struct obj_data *obj = GET_EQ(ch, wear_pos);
if (!obj || GET_OBJ_TYPE(obj) != ITEM_ARMOR)
continue;
/* flags in value[3] */
int flags = GET_OBJ_VAL(obj, VAL_ARMOR_FLAGS);
if (flags & ARMF_STEALTH_DISADV)
piece_imposes = TRUE;
/* accumulate bulk */
int piece_bulk = GET_OBJ_VAL(obj, VAL_ARMOR_BULK);
if (piece_bulk < 0) piece_bulk = 0;
total_bulk += piece_bulk * armor_slots[i].bulk_weight;
/* new semantics: slot 3 is a 0/1 toggle */
if (GET_OBJ_VAL(obj, VAL_ARMOR_STEALTH_DISADV))
return TRUE;
}
/* Heavy armor bulk ⇒ Dex cap 0 ⇒ stealth disadvantage */
int cap = dex_cap_from_bulk(total_bulk); /* Light<=5:5 / <=10:2 / else:0 */
if (cap == 0) return TRUE;
return piece_imposes;
return FALSE;
}
/* Returns the 5e-style ability modifier for a given ability score. */