WORN items update

This commit is contained in:
kinther 2025-12-17 12:23:20 -08:00
parent 1430f6b7d3
commit 4ea7abca56
10 changed files with 344 additions and 41 deletions

View file

@ -175,7 +175,7 @@ A small bag made of cloth lies here.~
15 0 0 0
1 25 0 0 0
#122
large bag~
bag large~
a large bag~
A large bag made of cloth is lying here.~
~
@ -563,7 +563,7 @@ to form a receptacle that can hold water.
~
17 0 0 0 0 ap 0 0 0 0 0 0 0
4 4 0 0
1 40 0 0 0
9 40 0 0 0
#161
waterpouch pouch leather~
a leather waterpouch~
@ -574,5 +574,17 @@ prevent water spilling out.
~
17 0 0 0 0 ap 0 0 0 0 0 0 0
4 4 0 0
1 40 0 0 0
9 40 0 0 0
#162
cloak dark hooded~
a dark, hooded cloak~
A piece of dark fabric lays here in a heap.~
This piece of fabric is made of linen and has been dyed a dark, blackish-blue
color. It has a few small pockets sewn inside and a clasp near the neck to
close it. A large hood has been attached, allowing the wearer to partially
cover their face.
~
11 0 0 0 0 al 0 0 0 0 0 0 0
1 1 0 10
1 10 0 0 0
$~

View file

@ -144,6 +144,11 @@ ACMD(do_eat);
ACMD(do_pour);
#define SCMD_POUR 0
#define SCMD_FILL 1
/* do_raise_lower_hood */
ACMD(do_raise_lower_hood);
#define SCMD_RAISE_HOOD 0
#define SCMD_LOWER_HOOD 1
/* functions without subcommands */
ACMD(do_drink);
ACMD(do_get);
@ -154,7 +159,6 @@ ACMD(do_remove);
ACMD(do_wear);
ACMD(do_wield);
/*****************************************************************************
* Begin Functions and defines for act.movement.c
****************************************************************************/

View file

@ -803,12 +803,14 @@ static void look_in_obj(struct char_data *ch, char *arg)
FIND_OBJ_EQUIP, ch, &dummy, &obj))) {
send_to_char(ch, "There doesn't seem to be %s %s here.\r\n", AN(arg), arg);
} else if ((GET_OBJ_TYPE(obj) != ITEM_DRINKCON) &&
(GET_OBJ_TYPE(obj) != ITEM_FOUNTAIN) &&
(GET_OBJ_TYPE(obj) != ITEM_CONTAINER))
(GET_OBJ_TYPE(obj) != ITEM_FOUNTAIN) &&
!obj_is_storage(obj)) {
send_to_char(ch, "There's nothing inside that!\r\n");
else {
if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER) {
if (OBJVAL_FLAGGED(obj, CONT_CLOSED) && (GET_LEVEL(ch) < LVL_IMMORT || !PRF_FLAGGED(ch, PRF_NOHASSLE)))
} else {
/* Storage-like objects: containers + storage-capable worn items */
if (obj_is_storage(obj) && GET_OBJ_TYPE(obj) != ITEM_DRINKCON && GET_OBJ_TYPE(obj) != ITEM_FOUNTAIN) {
if (obj_storage_is_closed(obj) &&
(GET_LEVEL(ch) < LVL_IMMORT || !PRF_FLAGGED(ch, PRF_NOHASSLE)))
send_to_char(ch, "It is closed.\r\n");
else {
/* Choose a label for the container:
@ -817,11 +819,31 @@ static void look_in_obj(struct char_data *ch, char *arg)
* - Otherwise, fall back to the first keyword (fname(obj->name))
*/
const char *label;
const char *sd;
if (GET_OBJ_VAL(obj, 3) == 1 && obj->short_description && *obj->short_description)
/* Containers: keep corpse behavior exactly as-is */
if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER &&
GET_OBJ_VAL(obj, 3) == 1 &&
obj->short_description && *obj->short_description) {
label = obj->short_description;
else
}
/* WORN storage: use short_description, strip leading article */
else if (GET_OBJ_TYPE(obj) == ITEM_WORN &&
obj->short_description && *obj->short_description) {
sd = obj->short_description;
if (!strn_cmp(sd, "a ", 2))
label = sd + 2;
else if (!strn_cmp(sd, "an ", 3))
label = sd + 3;
else
label = sd;
}
/* Fallback */
else {
label = fname(obj->name);
}
send_to_char(ch, "%s", label);

View file

@ -50,6 +50,7 @@ static void wear_message(struct char_data *ch, struct obj_data *obj, int where);
static void perform_put(struct char_data *ch, struct obj_data *obj, struct obj_data *cont)
{
long object_id = obj_script_id(obj);
int cap = 0;
if (!drop_otrigger(obj, ch))
return;
@ -57,8 +58,26 @@ static void perform_put(struct char_data *ch, struct obj_data *obj, struct obj_d
if (!has_obj_by_uid_in_lookup_table(object_id)) /* object might be extracted by drop_otrigger */
return;
if ((GET_OBJ_VAL(cont, 0) > 0) &&
(GET_OBJ_WEIGHT(cont) + GET_OBJ_WEIGHT(obj) > GET_OBJ_VAL(cont, 0)))
/* --- Storage target validation (containers + storage WORN) --- */
if (!obj_is_storage(cont)) {
act("$P is not a container.", FALSE, ch, obj, cont, TO_CHAR);
return;
}
/* Prevent putting items into closed storage (matches container UX). */
if (obj_storage_is_closed(cont) &&
(GET_LEVEL(ch) < LVL_IMMORT || !PRF_FLAGGED(ch, PRF_NOHASSLE))) {
act("$P seems to be closed.", FALSE, ch, obj, cont, TO_CHAR);
return;
}
/* Capacity: containers use value[0]; worn storage uses WORN_CAPACITY. */
if (GET_OBJ_TYPE(cont) == ITEM_WORN)
cap = GET_OBJ_VAL(cont, WORN_CAPACITY);
else
cap = GET_OBJ_VAL(cont, 0);
if ((cap > 0) && (GET_OBJ_WEIGHT(cont) + GET_OBJ_WEIGHT(obj) > cap))
act("$p won't fit in $P.", FALSE, ch, obj, cont, TO_CHAR);
else if (OBJ_FLAGGED(obj, ITEM_NODROP) && IN_ROOM(cont) != NOWHERE)
act("You can't get $p out of your hand.", FALSE, ch, obj, NULL, TO_CHAR);
@ -142,12 +161,13 @@ ACMD(do_put)
generic_find(thecont, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &tmp_char, &cont);
if (!cont)
send_to_char(ch, "You don't see %s %s here.\r\n", AN(thecont), thecont);
else if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER) {
/* Handle container logic */
if (OBJVAL_FLAGGED(cont, CONT_CLOSED) && (GET_LEVEL(ch) < LVL_IMMORT || !PRF_FLAGGED(ch, PRF_NOHASSLE)))
else if (obj_is_storage(cont)) {
/* Handle container-like logic (containers + storage WORN) */
if (obj_storage_is_closed(cont) &&
(GET_LEVEL(ch) < LVL_IMMORT || !PRF_FLAGGED(ch, PRF_NOHASSLE))) {
send_to_char(ch, "You'd better open it first!\r\n");
else {
if (obj_dotmode == FIND_INDIV) { /* put <obj> <container> */
} else {
if (obj_dotmode == FIND_INDIV) { /* put <obj> <container> */
if (!(obj = get_obj_in_list_vis(ch, theobj, NULL, ch->carrying)))
send_to_char(ch, "You aren't carrying %s %s.\r\n", AN(theobj), theobj);
else if (obj == cont && howmany == 1)
@ -157,7 +177,7 @@ ACMD(do_put)
next_obj = obj->next_content;
if (obj != cont) {
howmany--;
perform_put(ch, obj, cont);
perform_put(ch, obj, cont); /* must be updated to accept storage WORN */
}
obj = get_obj_in_list_vis(ch, theobj, NULL, next_obj);
}
@ -168,13 +188,13 @@ ACMD(do_put)
if (obj != cont && CAN_SEE_OBJ(ch, obj) &&
(obj_dotmode == FIND_ALL || isname(theobj, obj->name))) {
found = 1;
perform_put(ch, obj, cont);
perform_put(ch, obj, cont); /* must be updated to accept storage WORN */
}
}
if (!found)
send_to_char(ch, "You don't seem to have %s %s.\r\n",
obj_dotmode == FIND_ALL ? "any" : "any",
obj_dotmode == FIND_ALL ? "items" : theobj);
send_to_char(ch, "You don't seem to have %s %s.\r\n",
obj_dotmode == FIND_ALL ? "any" : "any",
obj_dotmode == FIND_ALL ? "items" : theobj);
}
}
} else if (GET_OBJ_TYPE(cont) == ITEM_FURNITURE) {
@ -273,14 +293,21 @@ static void perform_get_from_container(struct char_data *ch, struct obj_data *ob
}
void get_from_container(struct char_data *ch, struct obj_data *cont,
char *arg, int mode, int howmany)
char *arg, int mode, int howmany)
{
struct obj_data *obj, *next_obj;
int obj_dotmode, found = 0;
obj_dotmode = find_all_dots(arg);
if (OBJVAL_FLAGGED(cont, CONT_CLOSED) && (GET_LEVEL(ch) < LVL_IMMORT || !PRF_FLAGGED(ch, PRF_NOHASSLE)))
/* Allow both ITEM_CONTAINER and storage-capable ITEM_WORN */
if (!obj_is_storage(cont)) {
act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
return;
}
if (obj_storage_is_closed(cont) &&
(GET_LEVEL(ch) < LVL_IMMORT || !PRF_FLAGGED(ch, PRF_NOHASSLE)))
act("$p is closed.", FALSE, ch, cont, 0, TO_CHAR);
else if (obj_dotmode == FIND_INDIV) {
if (!(obj = get_obj_in_list_vis(ch, arg, NULL, cont->contains))) {
@ -304,19 +331,19 @@ void get_from_container(struct char_data *ch, struct obj_data *cont,
for (obj = cont->contains; obj; obj = next_obj) {
next_obj = obj->next_content;
if (CAN_SEE_OBJ(ch, obj) &&
(obj_dotmode == FIND_ALL || isname(arg, obj->name))) {
found = 1;
perform_get_from_container(ch, obj, cont, mode);
(obj_dotmode == FIND_ALL || isname(arg, obj->name))) {
found = 1;
perform_get_from_container(ch, obj, cont, mode);
}
}
if (!found) {
if (obj_dotmode == FIND_ALL)
act("$p seems to be empty.", FALSE, ch, cont, 0, TO_CHAR);
act("$p seems to be empty.", FALSE, ch, cont, 0, TO_CHAR);
else {
char buf[MAX_STRING_LENGTH];
snprintf(buf, sizeof(buf), "You can't seem to find any %ss in $p.", arg);
act(buf, FALSE, ch, cont, 0, TO_CHAR);
snprintf(buf, sizeof(buf), "You can't seem to find any %ss in $p.", arg);
act(buf, FALSE, ch, cont, 0, TO_CHAR);
}
}
}
@ -409,11 +436,11 @@ ACMD(do_get)
if (cont_dotmode == FIND_INDIV) {
mode = generic_find(arg2, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &tmp_char, &cont);
if (!cont)
send_to_char(ch, "You don't have %s %s.\r\n", AN(arg2), arg2);
else if (GET_OBJ_TYPE(cont) != ITEM_CONTAINER && GET_OBJ_TYPE(cont) != ITEM_FURNITURE)
act("$p is not a container or furniture.", FALSE, ch, cont, 0, TO_CHAR);
send_to_char(ch, "You don't have %s %s.\r\n", AN(arg2), arg2);
else if (!obj_is_storage(cont) && GET_OBJ_TYPE(cont) != ITEM_FURNITURE)
act("$p is not a container or furniture.", FALSE, ch, cont, 0, TO_CHAR);
else
get_from_container(ch, cont, arg1, mode, amount);
get_from_container(ch, cont, arg1, mode, amount); /* must be updated */
} else {
if (cont_dotmode == FIND_ALLDOT && !*arg2) {
send_to_char(ch, "Get from all of what?\r\n");
@ -421,7 +448,7 @@ ACMD(do_get)
}
for (cont = ch->carrying; cont; cont = cont->next_content)
if (CAN_SEE_OBJ(ch, cont) && (cont_dotmode == FIND_ALL || isname(arg2, cont->name))) {
if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER || GET_OBJ_TYPE(cont) == ITEM_FURNITURE) {
if (obj_is_storage(cont) || GET_OBJ_TYPE(cont) == ITEM_FURNITURE) {
found = 1;
get_from_container(ch, cont, arg1, FIND_OBJ_INV, amount);
} else if (cont_dotmode == FIND_ALLDOT) {
@ -452,7 +479,7 @@ ACMD(do_get)
for (cont = world[IN_ROOM(ch)].contents; cont; cont = cont->next_content)
if (CAN_SEE_OBJ(ch, cont) &&
(cont_dotmode == FIND_ALL || isname(arg2, cont->name))) {
if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER || GET_OBJ_TYPE(cont) == ITEM_FURNITURE) {
if (obj_is_storage(cont) || GET_OBJ_TYPE(cont) == ITEM_FURNITURE) {
get_from_container(ch, cont, arg1, FIND_OBJ_ROOM, amount);
found = 1;
} else if (cont_dotmode == FIND_ALLDOT) {
@ -1814,3 +1841,89 @@ ACMD(do_remove)
perform_remove(ch, i);
}
}
ACMD(do_raise_lower_hood)
{
char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
struct obj_data *obj = NULL;
int j;
two_arguments(argument, arg1, arg2);
/* Must be exactly: "raise hood" or "lower hood" */
if (!*arg1 || str_cmp(arg1, "hood")) {
send_to_char(ch, "Usage: %s hood\r\n", (subcmd == SCMD_RAISE_HOOD) ? "raise" : "lower");
return;
}
/* Find a hooded worn item in equipment. Prefer:
- for lower: one that is currently up
- for raise: one that is currently down
*/
if (subcmd == SCMD_LOWER_HOOD) {
for (j = 0; j < NUM_WEARS; j++) {
obj = GET_EQ(ch, j);
if (!obj) continue;
if (GET_OBJ_TYPE(obj) != ITEM_WORN) continue;
if (GET_OBJ_VAL(obj, WORN_CAN_HOOD) != 1) continue;
if (IS_SET_AR(GET_OBJ_EXTRA(obj), ITEM_HOOD_UP))
break;
obj = NULL;
}
}
if (!obj && subcmd == SCMD_RAISE_HOOD) {
for (j = 0; j < NUM_WEARS; j++) {
obj = GET_EQ(ch, j);
if (!obj) continue;
if (GET_OBJ_TYPE(obj) != ITEM_WORN) continue;
if (GET_OBJ_VAL(obj, WORN_CAN_HOOD) != 1) continue;
if (!IS_SET_AR(GET_OBJ_EXTRA(obj), ITEM_HOOD_UP))
break;
obj = NULL;
}
}
/* If we didnt find an ideal target, fall back to any hooded worn item. */
if (!obj) {
for (j = 0; j < NUM_WEARS; j++) {
obj = GET_EQ(ch, j);
if (!obj) continue;
if (GET_OBJ_TYPE(obj) != ITEM_WORN) continue;
if (GET_OBJ_VAL(obj, WORN_CAN_HOOD) != 1) continue;
break;
}
if (j >= NUM_WEARS) obj = NULL;
}
if (!obj) {
send_to_char(ch, "You aren't wearing anything with a hood.\r\n");
return;
}
if (subcmd == SCMD_RAISE_HOOD) {
if (GET_OBJ_VAL(obj, WORN_HOOD_UP_STATE) == 1) {
send_to_char(ch, "Your hood is already up.\r\n");
return;
}
GET_OBJ_VAL(obj, WORN_HOOD_UP_STATE) = 1;
SET_BIT_AR(GET_OBJ_EXTRA(obj), ITEM_HOOD_UP); /* optional mirror */
send_to_char(ch, "You raise your hood.\r\n");
act("$n raises $s hood.", FALSE, ch, 0, 0, TO_ROOM);
return;
}
/* SCMD_LOWER_HOOD */
if (GET_OBJ_VAL(obj, WORN_HOOD_UP_STATE) == 0) {
send_to_char(ch, "Your hood is already down.\r\n");
return;
}
GET_OBJ_VAL(obj, WORN_HOOD_UP_STATE) = 0;
REMOVE_BIT_AR(GET_OBJ_EXTRA(obj), ITEM_HOOD_UP); /* optional mirror */
send_to_char(ch, "You lower your hood.\r\n");
act("$n lowers $s hood.", FALSE, ch, 0, 0, TO_ROOM);
}

View file

@ -785,6 +785,32 @@ static int ok_pick(struct char_data *ch, obj_vnum keynum, int pickproof, int scm
#define DOOR_KEY(ch, obj, door) ((obj) ? (GET_OBJ_VAL(obj, 2)) : \
(EXIT(ch, door)->key))
/* For worn items like backpacks, cloaks, etc */
static void do_worn_openclose(struct char_data *ch, struct obj_data *obj, int subcmd)
{
if (subcmd == SCMD_OPEN) {
if (GET_OBJ_VAL(obj, WORN_IS_CLOSED) == 0) {
send_to_char(ch, "But it's currently open!\r\n");
return;
}
GET_OBJ_VAL(obj, WORN_IS_CLOSED) = 0;
send_to_char(ch, "%s", CONFIG_OK);
act("$n opens $p.", FALSE, ch, obj, 0, TO_ROOM);
return;
}
if (subcmd == SCMD_CLOSE) {
if (GET_OBJ_VAL(obj, WORN_IS_CLOSED) == 1) {
send_to_char(ch, "But it's already closed!\r\n");
return;
}
GET_OBJ_VAL(obj, WORN_IS_CLOSED) = 1;
send_to_char(ch, "%s", CONFIG_OK);
act("$n closes $p.", FALSE, ch, obj, 0, TO_ROOM);
return;
}
}
ACMD(do_gen_door)
{
int door = -1;
@ -799,9 +825,23 @@ ACMD(do_gen_door)
return;
}
two_arguments(argument, type, dir);
if (!generic_find(type, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &victim, &obj))
if (!generic_find(type, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &victim, &obj))
door = find_door(ch, type, dir, cmd_door[subcmd]);
if (obj && GET_OBJ_TYPE(obj) == ITEM_WORN &&
GET_OBJ_VAL(obj, WORN_CAN_OPEN_CLOSE) == 1) {
if (subcmd == SCMD_OPEN || subcmd == SCMD_CLOSE) {
do_worn_openclose(ch, obj, subcmd);
return;
}
/* lock/unlock/pick on closable worn items: treat as not applicable */
/* fall through to door search by discarding obj */
obj = NULL;
door = find_door(ch, type, dir, cmd_door[subcmd]);
}
if ((obj) && (GET_OBJ_TYPE(obj) != ITEM_CONTAINER)) {
obj = NULL;
door = find_door(ch, type, dir, cmd_door[subcmd]);

View file

@ -187,6 +187,7 @@ cpp_extern const struct command_info cmd_info[] = {
{ "kick" , "ki" , POS_FIGHTING, do_kick , 1, 0 },
{ "look" , "l" , POS_RESTING , do_look , 0, SCMD_LOOK },
{ "lower" , "low" , POS_SITTING , do_raise_lower_hood, 0, SCMD_LOWER_HOOD },
{ "last" , "last" , POS_DEAD , do_last , LVL_GOD, 0 },
{ "leave" , "lea" , POS_STANDING, do_leave , 0, 0 },
{ "list" , "lis" , POS_STANDING, do_not_here , 0, 0 },
@ -246,6 +247,7 @@ cpp_extern const struct command_info cmd_info[] = {
{ "qui" , "qui" , POS_DEAD , do_quit , 0, 0 },
{ "quit" , "quit" , POS_DEAD , do_quit , 0, SCMD_QUIT },
{ "raise" , "rai" , POS_SITTING , do_raise_lower_hood, 0, SCMD_RAISE_HOOD },
{ "reply" , "r" , POS_SLEEPING, do_reply , LVL_IMMORT, 0 },
{ "rest" , "res" , POS_RESTING , do_rest , 0, 0 },
{ "read" , "rea" , POS_RESTING , do_look , 0, SCMD_READ },
@ -267,7 +269,7 @@ cpp_extern const struct command_info cmd_info[] = {
{ "say" , "s" , POS_RESTING , do_say , 0, 0 },
{ "score" , "sc" , POS_DEAD , do_score , 0, 0 },
{ "scan" , "sca" , POS_RESTING , do_scan , 0, 0 },
{ "scan" , "sca" , POS_RESTING , do_scan , 0, 0 },
{ "scopy" , "scopy" , POS_DEAD , do_oasis_copy, LVL_GOD, CON_SEDIT },
{ "sit" , "si" , POS_RESTING , do_sit , 0, 0 },
{ "'" , "'" , POS_RESTING , do_say , 0, 0 },

View file

@ -992,6 +992,40 @@ void oedit_parse(struct descriptor_data *d, char *arg)
}
}
/* --- Worn-specific semantics (clothing, rings, etc) --- */
if (GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_WORN) {
/* oval 1: closable (0/1) */
if (i == WORN_CAN_OPEN_CLOSE) {
if (number != 0 && number != 1) {
write_to_output(d, "Enter 0 or 1 to set closable: ");
return; /* stay in OEDIT_VALUE_X */
}
GET_OBJ_VAL(OLC_OBJ(d), i) = number;
OLC_DIRTY(d) = 1;
oedit_disp_values_menu(d);
return;
}
/* oval 2: hooded (0/1) */
if (i == WORN_CAN_HOOD) {
if (number != 0 && number != 1) {
write_to_output(d, "Enter 0 or 1 to set hooded: ");
return; /* stay in OEDIT_VALUE_X */
}
GET_OBJ_VAL(OLC_OBJ(d), i) = number;
/* If it can no longer have a hood, force hood state down. */
if (number == 0) {
REMOVE_BIT_AR(GET_OBJ_EXTRA(OLC_OBJ(d)), ITEM_HOOD_UP);
}
OLC_DIRTY(d) = 1;
oedit_disp_values_menu(d);
return;
}
}
/* --- 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) {

View file

@ -444,8 +444,9 @@
#define ITEM_ANTI_DRUID 19 /**< Not usable by druids */
#define ITEM_NOSELL 20 /**< Shopkeepers won't touch it */
#define ITEM_QUEST 21 /**< Item is a quest item */
#define ITEM_HOOD_UP 22 /**< WORN item hood is currently up */
/** Total number of item flags */
#define NUM_ITEM_FLAGS 22
#define NUM_ITEM_FLAGS 23
/* Modifier constants used with obj affects ('A' fields) */
#define APPLY_NONE 0 /**< No effect */
@ -475,7 +476,7 @@
#define APPLY_SAVE_CHA 24 /**< Apply to CHA saving throws */
/** Total number of applies */
#define NUM_APPLIES 25
#define NUM_APPLIES 25
/* Equals the total number of SAVING_* defines in spells.h */
#define NUM_OF_SAVING_THROWS 5
@ -486,6 +487,13 @@
#define CONT_CLOSED (1 << 2) /**< Container is closed */
#define CONT_LOCKED (1 << 3) /**< Container is locked */
/* ITEM_WORN value[] layout */
#define WORN_CAN_OPEN_CLOSE 0 /* 0/1: supports open/close */
#define WORN_CAN_HOOD 1 /* 0/1: supports hood up/down */
#define WORN_IS_CLOSED 2 /* runtime: 0/1 */
#define WORN_CAPACITY 3 /* max weight/units it can hold; 0 = cannot hold */
#define WORN_HOOD_UP_STATE 4 /* runtime 0/1, persisted */
/* Some different kind of liquids for use in values of drink containers */
#define LIQ_WATER 0 /**< Liquid type water */
#define LIQ_BEER 1 /**< Liquid type beer */

View file

@ -478,6 +478,11 @@ static const char *const furniture_val_labels[NUM_OBJ_VAL_POSITIONS] = {
"Value[4]", "Value[5]", "Value[6]", "Value[7]"
};
static const char *const worn_val_labels[NUM_OBJ_VAL_POSITIONS] = {
"closable", "hooded", "is_closed", "capacity",
"hood_raised", "Value[5]", "Value[6]", "Value[7]"
};
static const char *const generic_val_labels[NUM_OBJ_VAL_POSITIONS] = {
"Value[0]", "Value[1]", "Value[2]", "Value[3]",
"Value[4]", "Value[5]", "Value[6]", "Value[7]"
@ -494,6 +499,7 @@ const char *const *obj_value_labels(int item_type)
case ITEM_WEAPON: return weapon_val_labels;
case ITEM_ARMOR: return armor_val_labels;
case ITEM_CONTAINER: return container_val_labels;
case ITEM_WORN: return worn_val_labels;
case ITEM_DRINKCON:
case ITEM_FOUNTAIN: return drink_val_labels;
case ITEM_FOOD: return food_val_labels;
@ -1644,11 +1650,43 @@ void remove_from_string(char *string, const char *to_remove)
}
}
static struct obj_data *find_raised_hood_item(const struct char_data *ch)
{
int j;
if (!ch)
return NULL;
for (j = 0; j < NUM_WEARS; j++) {
struct obj_data *obj = GET_EQ((struct char_data *)ch, j); /* GET_EQ not const-safe */
if (!obj)
continue;
if (GET_OBJ_TYPE(obj) == ITEM_WORN &&
GET_OBJ_VAL(obj, WORN_CAN_HOOD) == 1 &&
GET_OBJ_VAL(obj, WORN_HOOD_UP_STATE) == 1) {
return obj;
}
}
return NULL;
}
const char *get_char_sdesc(const struct char_data *ch)
{
static char buf[MAX_STRING_LENGTH];
struct obj_data *hood;
if (!ch)
return "someone";
/* Hood override: temporary display only (does not mutate stored sdesc). */
hood = find_raised_hood_item(ch);
if (hood && hood->short_description && *hood->short_description) {
snprintf(buf, sizeof(buf), "the figure in %s", hood->short_description);
return buf;
}
if (GET_SHORT_DESC(ch) && *GET_SHORT_DESC(ch))
return GET_SHORT_DESC(ch);
@ -1953,3 +1991,31 @@ struct mob_loadout *loadout_deep_copy(const struct mob_loadout *src) {
}
return head;
}
/* Worn item helpers */
int obj_is_storage(const struct obj_data *obj)
{
if (!obj) return 0;
if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER)
return 1;
if (GET_OBJ_TYPE(obj) == ITEM_WORN && GET_OBJ_VAL(obj, WORN_CAPACITY) > 0)
return 1;
return 0;
}
int obj_storage_is_closed(const struct obj_data *obj)
{
if (!obj) return 0;
if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER)
return IS_SET(GET_OBJ_VAL(obj, 1), CONT_CLOSED);
if (GET_OBJ_TYPE(obj) == ITEM_WORN &&
GET_OBJ_VAL(obj, WORN_CAN_OPEN_CLOSE) == 1)
return (GET_OBJ_VAL(obj, WORN_IS_CLOSED) == 1);
return 0;
}

View file

@ -80,6 +80,8 @@ char *right_trim_whitespace(const char *string);
void remove_from_string(char *string, const char *to_remove);
const char *const *obj_value_labels(int item_type);
const char *get_char_sdesc(const struct char_data *ch);
int obj_is_storage(const struct obj_data *obj);
int obj_storage_is_closed(const struct obj_data *obj);
/* 5e system helpers */