Update to furniture items

This commit is contained in:
kinther 2025-09-15 16:34:06 -07:00
parent c41e291770
commit ccf81bc3a4
7 changed files with 199 additions and 56 deletions

View file

@ -261,6 +261,6 @@ A long, wooden bar takes up most of the south side of the room.~
It's a long wooden bar!
~
6 0 0 0 0 0 0 0 0 0 0 0 0
100 8 0 0
8 0 0 0
200 0 0 0 0
$~

View file

@ -84,6 +84,7 @@ static void show_obj_to_char(struct obj_data *obj, struct char_data *ch, int mod
}
}
switch (mode) {
case SHOW_OBJ_LONG:
/* Hide objects starting with . from non-holylighted people. - Elaseth */
@ -121,6 +122,34 @@ static void show_obj_to_char(struct obj_data *obj, struct char_data *ch, int mod
if (GET_OBJ_MAIN(obj) && *GET_OBJ_MAIN(obj)) {
/* Use the pager so multi-line M-Descs display nicely. */
page_string(ch->desc, GET_OBJ_MAIN(obj), TRUE);
/* For furniture, also show items on it after the main description */
if (GET_OBJ_TYPE(obj) == ITEM_FURNITURE) {
/* Show seat availability */
if (GET_OBJ_VAL(obj, 0) > 0) {
int current_occupants = GET_OBJ_VAL(obj, 1);
int max_occupants = GET_OBJ_VAL(obj, 0);
int available_seats = max_occupants - current_occupants;
if (available_seats > 0) {
send_to_char(ch, "\r\n%s(%d seat%s available)%s",
CCYEL(ch, C_NRM), available_seats,
available_seats == 1 ? "" : "s",
CCNRM(ch, C_NRM));
} else {
send_to_char(ch, "\r\n%s(no seats available)%s",
CCRED(ch, C_NRM), CCNRM(ch, C_NRM));
}
}
/* Show items on furniture */
if (obj->contains) {
send_to_char(ch, "\r\nOn %s you see:\r\n", obj->short_description);
list_obj_to_char(obj->contains, ch, SHOW_OBJ_SHORT, TRUE);
} else {
send_to_char(ch, "\r\nYou see nothing on %s.", obj->short_description);
}
}
return;
}
@ -140,6 +169,33 @@ static void show_obj_to_char(struct obj_data *obj, struct char_data *ch, int mod
send_to_char(ch, "It looks like a drink container.");
break;
case ITEM_FURNITURE:
/* Show seat availability */
if (GET_OBJ_VAL(obj, 0) > 0) {
int current_occupants = GET_OBJ_VAL(obj, 1);
int max_occupants = GET_OBJ_VAL(obj, 0);
int available_seats = max_occupants - current_occupants;
if (available_seats > 0) {
send_to_char(ch, "%s(%d seat%s available)%s ",
CCYEL(ch, C_NRM), available_seats,
available_seats == 1 ? "" : "s",
CCNRM(ch, C_NRM));
} else {
send_to_char(ch, "%s(no seats available)%s ",
CCRED(ch, C_NRM), CCNRM(ch, C_NRM));
}
}
/* Show items on furniture */
if (obj->contains) {
send_to_char(ch, "On %s you see:\r\n", obj->short_description);
list_obj_to_char(obj->contains, ch, SHOW_OBJ_SHORT, TRUE);
} else {
send_to_char(ch, "You see nothing on %s.", obj->short_description);
}
break;
default:
/* Optional: friendlier fallback that names the item. */
if (obj->short_description && *obj->short_description)

View file

@ -81,12 +81,37 @@ static void perform_put(struct char_data *ch, struct obj_data *obj, struct obj_d
}
}
/* Put an item on furniture (like a table, bar, etc.) */
static void perform_put_on_furniture(struct char_data *ch, struct obj_data *obj, struct obj_data *furniture)
{
long object_id = obj_script_id(obj);
if (!drop_otrigger(obj, ch))
return;
if (!has_obj_by_uid_in_lookup_table(object_id)) /* object might be extracted by drop_otrigger */
return;
if (OBJ_FLAGGED(obj, ITEM_NODROP) && IN_ROOM(furniture) != NOWHERE)
act("You can't get $p out of your hand.", FALSE, ch, obj, NULL, TO_CHAR);
else {
obj_from_char(obj);
obj_to_obj(obj, furniture);
act("$n puts $p on $P.", TRUE, ch, obj, furniture, TO_ROOM);
act("You put $p on $P.", FALSE, ch, obj, furniture, TO_CHAR);
}
}
/* The following put modes are supported:
1) put <object> <container>
2) put all.<object> <container>
3) put all <container>
The <container> must be in inventory, worn/equipped, or on ground. All objects to be put
into container must be in inventory. */
4) put <object> on <furniture>
5) put all.<object> on <furniture>
6) put all on <furniture>
The <container> or <furniture> must be in inventory, worn/equipped, or on ground.
All objects to be put into container or on furniture must be in inventory. */
ACMD(do_put)
{
char arg1[MAX_INPUT_LENGTH];
@ -120,42 +145,74 @@ 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)
act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
else if (OBJVAL_FLAGGED(cont, CONT_CLOSED) && (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> */
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)
send_to_char(ch, "You attempt to fold it into itself, but fail.\r\n");
else {
while (obj && howmany) {
next_obj = obj->next_content;
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)))
send_to_char(ch, "You'd better open it first!\r\n");
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)
send_to_char(ch, "You attempt to fold it into itself, but fail.\r\n");
else {
while (obj && howmany) {
next_obj = obj->next_content;
if (obj != cont) {
howmany--;
perform_put(ch, obj, cont);
}
obj = get_obj_in_list_vis(ch, theobj, NULL, next_obj);
}
}
} else {
for (obj = ch->carrying; obj; obj = next_obj) {
next_obj = obj->next_content;
if (obj != cont && CAN_SEE_OBJ(ch, obj) &&
(obj_dotmode == FIND_ALL || isname(theobj, obj->name))) {
found = 1;
perform_put(ch, obj, cont);
}
}
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);
}
}
} else if (GET_OBJ_TYPE(cont) == ITEM_FURNITURE) {
/* Handle furniture logic - put items ON furniture */
if (obj_dotmode == FIND_INDIV) { /* put <obj> on <furniture> */
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)
send_to_char(ch, "You can't put something on itself.\r\n");
else {
while (obj && howmany) {
next_obj = obj->next_content;
if (obj != cont) {
howmany--;
perform_put(ch, obj, cont);
perform_put_on_furniture(ch, obj, cont);
}
obj = get_obj_in_list_vis(ch, theobj, NULL, next_obj);
}
}
obj = get_obj_in_list_vis(ch, theobj, NULL, next_obj);
}
}
} else {
for (obj = ch->carrying; obj; obj = next_obj) {
next_obj = obj->next_content;
if (obj != cont && CAN_SEE_OBJ(ch, obj) &&
(obj_dotmode == FIND_ALL || isname(theobj, obj->name))) {
found = 1;
perform_put(ch, obj, cont);
}
}
if (!found) {
if (obj_dotmode == FIND_ALL)
send_to_char(ch, "You don't seem to have anything to put in it.\r\n");
else
send_to_char(ch, "You don't seem to have any %ss.\r\n", theobj);
}
for (obj = ch->carrying; obj; obj = next_obj) {
next_obj = obj->next_content;
if (obj != cont && CAN_SEE_OBJ(ch, obj) &&
(obj_dotmode == FIND_ALL || isname(theobj, obj->name))) {
found = 1;
perform_put_on_furniture(ch, obj, cont);
}
}
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);
}
} else {
act("$p is not a container or furniture.", FALSE, ch, cont, 0, TO_CHAR);
}
}
}
@ -356,8 +413,8 @@ ACMD(do_get)
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)
act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
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);
else
get_from_container(ch, cont, arg1, mode, amount);
} else {
@ -367,12 +424,12 @@ 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) {
if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER || GET_OBJ_TYPE(cont) == ITEM_FURNITURE) {
found = 1;
get_from_container(ch, cont, arg1, FIND_OBJ_INV, amount);
} else if (cont_dotmode == FIND_ALLDOT) {
found = 1;
act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
act("$p is not a container or furniture.", FALSE, ch, cont, 0, TO_CHAR);
}
}
{
@ -385,12 +442,12 @@ ACMD(do_get)
if (CAN_SEE_OBJ(ch, eq) &&
(cont_dotmode == FIND_ALL || isname(arg2, eq->name))) {
if (GET_OBJ_TYPE(eq) == ITEM_CONTAINER) {
if (GET_OBJ_TYPE(eq) == ITEM_CONTAINER || GET_OBJ_TYPE(eq) == ITEM_FURNITURE) {
found = 1;
get_from_container(ch, eq, arg1, FIND_OBJ_EQUIP, amount);
} else if (cont_dotmode == FIND_ALLDOT) {
found = 1;
act("$p is not a container.", FALSE, ch, eq, 0, TO_CHAR);
act("$p is not a container or furniture.", FALSE, ch, eq, 0, TO_CHAR);
}
}
}
@ -398,17 +455,17 @@ 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) {
if (GET_OBJ_TYPE(cont) == ITEM_CONTAINER || GET_OBJ_TYPE(cont) == ITEM_FURNITURE) {
get_from_container(ch, cont, arg1, FIND_OBJ_ROOM, amount);
found = 1;
} else if (cont_dotmode == FIND_ALLDOT) {
act("$p is not a container.", FALSE, ch, cont, 0, TO_CHAR);
act("$p is not a container or furniture.", FALSE, ch, cont, 0, TO_CHAR);
found = 1;
}
}
if (!found) {
if (cont_dotmode == FIND_ALL)
send_to_char(ch, "You can't seem to find any containers.\r\n");
send_to_char(ch, "You can't seem to find any containers or furniture.\r\n");
else
send_to_char(ch, "You can't seem to find any %ss here.\r\n", arg2);
}

View file

@ -803,6 +803,13 @@ ACMD(do_sit)
act("There is no where left to sit upon $p.", TRUE, ch, furniture, 0, TO_CHAR);
return;
} else {
/* Check if furniture allows sitting position */
int allowed_positions = GET_OBJ_VAL(furniture, 2); /* VAL_FURN_POSITIONS */
if (allowed_positions > 0 && !(allowed_positions & (1 << 1))) { /* Check SIT bit (bit 1) */
act("$p doesn't look comfortable for sitting.", TRUE, ch, furniture, 0, TO_CHAR);
return;
}
if (OBJ_SAT_IN_BY(furniture) == NULL)
OBJ_SAT_IN_BY(furniture) = ch;
for (tempch = OBJ_SAT_IN_BY(furniture); tempch != ch ; tempch = NEXT_SITTING(tempch)) {
@ -850,6 +857,14 @@ ACMD(do_rest)
GET_POS(ch) = POS_RESTING;
break;
case POS_SITTING:
/* Check if sitting on furniture that allows resting */
if (SITTING(ch) && GET_OBJ_TYPE(SITTING(ch)) == ITEM_FURNITURE) {
int allowed_positions = GET_OBJ_VAL(SITTING(ch), 2); /* VAL_FURN_POSITIONS */
if (allowed_positions > 0 && !(allowed_positions & (1 << 2))) { /* Check REST bit (bit 2) */
act("$p doesn't look comfortable for resting.", TRUE, ch, SITTING(ch), 0, TO_CHAR);
return;
}
}
send_to_char(ch, "You rest your tired bones.\r\n");
act("$n rests.", TRUE, ch, 0, 0, TO_ROOM);
GET_POS(ch) = POS_RESTING;
@ -877,6 +892,14 @@ ACMD(do_sleep)
case POS_STANDING:
case POS_SITTING:
case POS_RESTING:
/* Check if sitting/resting on furniture that allows sleeping */
if (SITTING(ch) && GET_OBJ_TYPE(SITTING(ch)) == ITEM_FURNITURE) {
int allowed_positions = GET_OBJ_VAL(SITTING(ch), 2); /* VAL_FURN_POSITIONS */
if (allowed_positions > 0 && !(allowed_positions & (1 << 3))) { /* Check SLEEP bit (bit 3) */
act("$p doesn't look comfortable for sleeping.", TRUE, ch, SITTING(ch), 0, TO_CHAR);
return;
}
}
send_to_char(ch, "You go to sleep.\r\n");
act("$n lies down and falls asleep.", TRUE, ch, 0, 0, TO_ROOM);
GET_POS(ch) = POS_SLEEPING;

View file

@ -119,7 +119,6 @@ const char *furniture_position_bits[] = {
"SIT", /* can sit on it */
"REST", /* can rest on it */
"SLEEP", /* can sleep on it */
"KNEEL", /* can kneel at/on it */
"\n"
};

View file

@ -102,8 +102,8 @@ static const char *money_val_labels[NUM_OBJ_VAL_POSITIONS] = {
/* Furniture */
static const char *furniture_val_labels[NUM_OBJ_VAL_POSITIONS] = {
"capacity", "max_people", "allowed_pos", "furn_flags",
"comfy_bonus", "climb_dc", "script_hook", "reserved"
"max_seats", "current_occupants", "allowed_pos", "Value[3]",
"Value[4]", "Value[5]", "Value[6]", "Value[7]"
};
/* Generic fallback */
@ -525,8 +525,14 @@ static void oedit_disp_values_menu(struct descriptor_data *d)
write_to_output(d, "\r\n-- Object Values Menu --\r\n");
for (i = 0; i < NUM_OBJ_VAL_POSITIONS; i++) {
write_to_output(d, "%2d) %-12s : %d\r\n",
i+1, labels[i], GET_OBJ_VAL(obj, i));
/* Hide current_occupants field for furniture - it's managed by the game engine */
if (GET_OBJ_TYPE(obj) == ITEM_FURNITURE && i == 1) {
write_to_output(d, "%2d) %-12s : %d (managed by game engine)\r\n",
i+1, labels[i], GET_OBJ_VAL(obj, i));
} else {
write_to_output(d, "%2d) %-12s : %d\r\n",
i+1, labels[i], GET_OBJ_VAL(obj, i));
}
}
write_to_output(d, "Q) Quit to main menu\r\nEnter choice : ");
@ -1008,6 +1014,13 @@ void oedit_parse(struct descriptor_data *d, char *arg)
} else {
int i = atoi(arg) - 1;
if (i >= 0 && i < NUM_OBJ_VAL_POSITIONS) {
/* Prevent editing current_occupants for furniture - it's managed by the game engine */
if (GET_OBJ_TYPE(OLC_OBJ(d)) == ITEM_FURNITURE && i == 1) {
write_to_output(d, "The current_occupants field is managed by the game engine and cannot be edited manually.\r\n");
oedit_disp_values_menu(d);
return;
}
OLC_VAL_SLOT(d) = i;
const char **labels = get_val_labels(OLC_OBJ(d));

View file

@ -1336,14 +1336,9 @@ struct mob_loadout *loadout_deep_copy(const struct mob_loadout *src);
/* Furniture defines for object values */
/* Furniture object values (obj_flags.value[x]) */
#define VAL_FURN_CAPACITY 0 /* how much it can hold / support */
#define VAL_FURN_MAX_OCC 1 /* max occupants */
#define VAL_FURN_POSITIONS 2 /* allowed positions (bitvector) */
#define VAL_FURN_FLAGS 3 /* behavior flags (bitvector) */
#define VAL_FURN_COMFORT 4 /* comfort/healing bonus */
#define VAL_FURN_ENTRY_DC 5 /* difficulty to climb onto */
#define VAL_FURN_SCRIPT 6 /* script hook */
#define VAL_FURN_RESERVED 7 /* reserved */
#define VAL_FURN_CAPACITY 0 /* maximum number of people who can use furniture */
#define VAL_FURN_MAX_OCC 1 /* current number of people using furniture (runtime only, managed by game engine) */
#define VAL_FURN_POSITIONS 2 /* allowed positions bitvector: bit 0=STAND(1), bit 1=SIT(2), bit 2=REST(4), bit 3=SLEEP(8) */
/* Config structs */