From b883a72bb970d4b192e5c59925ce1847707e9370 Mon Sep 17 00:00:00 2001 From: kinther Date: Mon, 15 Dec 2025 19:16:38 -0800 Subject: [PATCH] Table update 2 --- src/act.informative.c | 8 +- src/act.movement.c | 516 +++++++++++++++++++++++++++++++++++------- 2 files changed, 446 insertions(+), 78 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index 10381b0..0949f5a 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -960,6 +960,7 @@ static void look_at_tables(struct char_data *ch) { struct obj_data *obj; int count = 0; + int allowed_positions = 0; if (!ch->desc) return; @@ -967,10 +968,13 @@ static void look_at_tables(struct char_data *ch) for (obj = world[IN_ROOM(ch)].contents; obj; obj = obj->next_content) { if (GET_OBJ_TYPE(obj) != ITEM_FURNITURE) continue; - if (GET_OBJ_VAL(obj, 0) <= 0) + if (GET_OBJ_VAL(obj, VAL_FURN_CAPACITY) <= 0) continue; if (!CAN_SEE_OBJ(ch, obj)) continue; + allowed_positions = GET_OBJ_VAL(obj, VAL_FURN_POSITIONS); + if (allowed_positions > 0 && !(allowed_positions & (1 << 1))) + continue; if (count == 0) send_to_char(ch, "You look around the room and see:\r\n\r\n"); @@ -985,6 +989,8 @@ static void look_at_tables(struct char_data *ch) if (!count) send_to_char(ch, "You don't see any tables here.\r\n"); + else + send_to_char(ch, "\r\nUse 'sit at ' to move to one of them.\r\n"); } ACMD(do_look) diff --git a/src/act.movement.c b/src/act.movement.c index 6f684c7..f228d51 100644 --- a/src/act.movement.c +++ b/src/act.movement.c @@ -33,6 +33,17 @@ static int find_door(struct char_data *ch, const char *type, char *dir, const ch static int has_key(struct char_data *ch, obj_vnum key); static void do_doorcmd(struct char_data *ch, struct obj_data *obj, int door, int scmd); static int ok_pick(struct char_data *ch, obj_vnum keynum, int pickproof, int scmd); +/* furniture helpers */ +static bool extract_furniture_token(struct char_data *ch, char *argument, char *out_token, + size_t out_size, const char *verb_cap); +static struct obj_data *get_numbered_furniture(struct char_data *ch, int number); +static struct obj_data *find_furniture_target(struct char_data *ch, char *token, + bool *used_number, int *ordinal); +static bool validate_furniture_use(struct char_data *ch, struct obj_data *furniture, + int position_bit, const char *verb_inf, + bool already_there); +static void attach_char_to_furniture(struct char_data *ch, struct obj_data *furniture); +static const char *position_gerund(int pos); /* simple function to determine if char can walk on water */ @@ -110,6 +121,148 @@ static int has_scuba(struct char_data *ch) return (0); } +static bool extract_furniture_token(struct char_data *ch, char *argument, char *out_token, + size_t out_size, const char *verb_cap) +{ + char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH]; + + if (!argument || !*argument) + return FALSE; + + two_arguments(argument, arg1, arg2); + + if (!*arg1) { + send_to_char(ch, "%s where?\r\n", verb_cap); + return FALSE; + } + + if (is_abbrev(arg1, "at")) { + if (!*arg2) { + send_to_char(ch, "%s at what?\r\n", verb_cap); + return FALSE; + } + strlcpy(out_token, arg2, out_size); + } else { + strlcpy(out_token, arg1, out_size); + } + + return TRUE; +} + +static struct obj_data *get_numbered_furniture(struct char_data *ch, int number) +{ + struct obj_data *obj; + int count = 0; + int allowed_positions = 0; + + if (number <= 0) + return NULL; + + for (obj = world[IN_ROOM(ch)].contents; obj; obj = obj->next_content) { + if (GET_OBJ_TYPE(obj) != ITEM_FURNITURE) + continue; + if (GET_OBJ_VAL(obj, VAL_FURN_CAPACITY) <= 0) + continue; + allowed_positions = GET_OBJ_VAL(obj, VAL_FURN_POSITIONS); + if (allowed_positions > 0 && !(allowed_positions & (1 << 1))) + continue; + if (!CAN_SEE_OBJ(ch, obj)) + continue; + count++; + if (count == number) + return obj; + } + return NULL; +} + +static struct obj_data *find_furniture_target(struct char_data *ch, char *token, + bool *used_number, int *ordinal) +{ + struct obj_data *furniture = NULL; + bool number_used = FALSE; + int ord = 0; + + if (token && *token && is_number(token)) { + int which = atoi(token); + furniture = get_numbered_furniture(ch, which); + number_used = TRUE; + ord = which; + } else { + furniture = get_obj_in_list_vis(ch, token, NULL, world[ch->in_room].contents); + } + + if (used_number) + *used_number = number_used; + if (ordinal) + *ordinal = ord; + + return furniture; +} + +static bool validate_furniture_use(struct char_data *ch, struct obj_data *furniture, + int position_bit, const char *verb_inf, + bool already_there) +{ + int allowed_positions; + + if (!furniture) + return FALSE; + + if (GET_OBJ_TYPE(furniture) != ITEM_FURNITURE) { + send_to_char(ch, "You can't %s on that!\r\n", verb_inf); + return FALSE; + } + + allowed_positions = GET_OBJ_VAL(furniture, VAL_FURN_POSITIONS); + if (allowed_positions > 0 && !(allowed_positions & position_bit)) { + act("$p doesn't look comfortable for that.", TRUE, ch, furniture, 0, TO_CHAR); + return FALSE; + } + + if (!already_there && + GET_OBJ_VAL(furniture, VAL_FURN_MAX_OCC) >= GET_OBJ_VAL(furniture, VAL_FURN_CAPACITY)) { + act("$p looks full.", TRUE, ch, furniture, 0, TO_CHAR); + return FALSE; + } + + return TRUE; +} + +static void attach_char_to_furniture(struct char_data *ch, struct obj_data *furniture) +{ + struct char_data *tempch; + + if (!furniture) + return; + + if (!OBJ_SAT_IN_BY(furniture)) + OBJ_SAT_IN_BY(furniture) = ch; + for (tempch = OBJ_SAT_IN_BY(furniture); tempch != ch; tempch = NEXT_SITTING(tempch)) { + if (NEXT_SITTING(tempch)) + continue; + NEXT_SITTING(tempch) = ch; + } + + SITTING(ch) = furniture; + NEXT_SITTING(ch) = NULL; + GET_OBJ_VAL(furniture, VAL_FURN_MAX_OCC) += 1; +} + +static const char *position_gerund(int pos) +{ + switch (pos) { + case POS_SLEEPING: + return "sleeping"; + case POS_RESTING: + return "resting"; + case POS_SITTING: + return "sitting"; + case POS_STANDING: + return "standing"; + default: + return "using"; + } +} /** Move a PC/NPC character from their current location to a new location. This * is the standard movement locomotion function that all normal walking * movement by characters should be sent through. This function also defines @@ -739,15 +892,84 @@ ACMD(do_leave) ACMD(do_stand) { + char token[MAX_INPUT_LENGTH]; + struct obj_data *furniture = NULL, *current_furniture = SITTING(ch); + bool has_target = FALSE, used_number = FALSE; + int ordinal = 0; + int orig_pos = GET_POS(ch); + + if (*argument) { + if (!extract_furniture_token(ch, argument, token, sizeof(token), "Stand")) + return; + has_target = TRUE; + furniture = find_furniture_target(ch, token, &used_number, &ordinal); + if (!furniture) { + if (used_number) + send_to_char(ch, "You don't see furniture #%d here.\r\n", ordinal); + else + send_to_char(ch, "You don't see that here.\r\n"); + return; + } + } + + if (has_target) { + bool already_there = (current_furniture && current_furniture == furniture); + + if (GET_POS(ch) == POS_SLEEPING) { + send_to_char(ch, "You have to wake up first!\r\n"); + return; + } else if (GET_POS(ch) == POS_FIGHTING) { + send_to_char(ch, "Do you not consider fighting as standing?\r\n"); + return; + } + + if (!validate_furniture_use(ch, furniture, (1 << 0), "stand", already_there)) + return; + + if (already_there && GET_POS(ch) == POS_STANDING) { + act("You are already standing at $p.", TRUE, ch, furniture, 0, TO_CHAR); + return; + } + + if (!already_there && current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) { + const char *leaving = position_gerund(GET_POS(ch)); + act("You stop $T on $p.", TRUE, ch, current_furniture, (char *)leaving, TO_CHAR); + act("$n stops $T on $p.", TRUE, ch, current_furniture, (char *)leaving, TO_ROOM); + char_from_furniture(ch); + } + + if (!already_there) + attach_char_to_furniture(ch, furniture); + + const char *self_msg = "You stand at $p."; + const char *room_msg = "$n stands at $p."; + + if (orig_pos == POS_SITTING) { + self_msg = "You stand up at $p."; + room_msg = "$n stands up at $p."; + } else if (orig_pos == POS_RESTING) { + self_msg = "You stop resting and stand at $p."; + room_msg = "$n stops resting and stands at $p."; + } else if (orig_pos < POS_SITTING) { + self_msg = "You struggle to your feet at $p."; + room_msg = "$n struggles to $s feet at $p."; + } + + act(self_msg, TRUE, ch, furniture, 0, TO_CHAR); + act(room_msg, TRUE, ch, furniture, 0, TO_ROOM); + GET_POS(ch) = FIGHTING(ch) ? POS_FIGHTING : POS_STANDING; + return; + } + switch (GET_POS(ch)) { case POS_STANDING: send_to_char(ch, "You are already standing.\r\n"); break; case POS_SITTING: - if (SITTING(ch) && GET_OBJ_TYPE(SITTING(ch)) == ITEM_FURNITURE) { - act("You stand up from $p.", TRUE, ch, SITTING(ch), 0, TO_CHAR); - act("$n stands up from $p.", TRUE, ch, SITTING(ch), 0, TO_ROOM); + if (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) { + act("You stand up from $p.", TRUE, ch, current_furniture, 0, TO_CHAR); + act("$n stands up from $p.", TRUE, ch, current_furniture, 0, TO_ROOM); } else { send_to_char(ch, "You stand up.\r\n"); act("$n clambers to $s feet.", TRUE, ch, 0, 0, TO_ROOM); @@ -759,9 +981,9 @@ ACMD(do_stand) break; case POS_RESTING: - if (SITTING(ch) && GET_OBJ_TYPE(SITTING(ch)) == ITEM_FURNITURE) { - act("You stop resting, and stand up from $p.", TRUE, ch, SITTING(ch), 0, TO_CHAR); - act("$n stops resting, and stands up from $p.", TRUE, ch, SITTING(ch), 0, TO_ROOM); + if (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) { + act("You stop resting, and stand up from $p.", TRUE, ch, current_furniture, 0, TO_CHAR); + act("$n stops resting, and stands up from $p.", TRUE, ch, current_furniture, 0, TO_ROOM); } else { send_to_char(ch, "You stop resting, and stand up.\r\n"); act("$n stops resting, and clambers on $s feet.", TRUE, ch, 0, 0, TO_ROOM); @@ -781,8 +1003,8 @@ ACMD(do_stand) default: send_to_char(ch, "You stop floating around, and put your feet on the ground.\r\n"); - if (SITTING(ch) && GET_OBJ_TYPE(SITTING(ch)) == ITEM_FURNITURE) - act("$n stops floating around, and stands up from $p.", TRUE, ch, SITTING(ch), 0, TO_ROOM); + if (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) + act("$n stops floating around, and stands up from $p.", TRUE, ch, current_furniture, 0, TO_ROOM); else act("$n stops floating around, and puts $s feet on the ground.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_STANDING; @@ -792,67 +1014,88 @@ ACMD(do_stand) ACMD(do_sit) { - char arg[MAX_STRING_LENGTH]; - struct obj_data *furniture; - struct char_data *tempch; - int found; + char token[MAX_INPUT_LENGTH]; + struct obj_data *furniture = NULL, *current_furniture = NULL; + bool has_target = FALSE, used_number = FALSE; + int ordinal = 0; + int orig_pos = GET_POS(ch); - one_argument(argument, arg); + if (*argument) { + if (!extract_furniture_token(ch, argument, token, sizeof(token), "Sit")) + return; + has_target = TRUE; + furniture = find_furniture_target(ch, token, &used_number, &ordinal); + if (!furniture) { + if (used_number) + send_to_char(ch, "You don't see furniture #%d here.\r\n", ordinal); + else + send_to_char(ch, "You don't see that here.\r\n"); + return; + } + } - if (!(furniture = get_obj_in_list_vis(ch, arg, NULL, world[ch->in_room].contents))) - found = 0; - else - found = 1; + current_furniture = SITTING(ch); + + if (has_target) { + bool already_there = (current_furniture && current_furniture == furniture); + + if (GET_POS(ch) == POS_SLEEPING) { + send_to_char(ch, "You have to wake up first.\r\n"); + return; + } + if (GET_POS(ch) == POS_FIGHTING) { + send_to_char(ch, "Sit down while fighting? Are you MAD?\r\n"); + return; + } + + if (!validate_furniture_use(ch, furniture, (1 << 1), "sit", already_there)) + return; + + if (already_there) { + if (GET_POS(ch) == POS_SITTING) { + act("You are already sitting on $p.", TRUE, ch, furniture, 0, TO_CHAR); + return; + } + } else if (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) { + const char *leaving = position_gerund(GET_POS(ch)); + act("You stop $T on $p.", TRUE, ch, current_furniture, (char *)leaving, TO_CHAR); + act("$n stops $T on $p.", TRUE, ch, current_furniture, (char *)leaving, TO_ROOM); + char_from_furniture(ch); + } + + if (!already_there) + attach_char_to_furniture(ch, furniture); + + const char *self_msg = "You sit on $p."; + const char *room_msg = "$n sits on $p."; + + if (orig_pos == POS_STANDING) { + self_msg = "You sit down on $p."; + room_msg = "$n sits down on $p."; + } else if (orig_pos == POS_RESTING) { + self_msg = "You stop resting and sit up on $p."; + room_msg = "$n stops resting and sits up on $p."; + } + + act(self_msg, TRUE, ch, furniture, 0, TO_CHAR); + act(room_msg, TRUE, ch, furniture, 0, TO_ROOM); + GET_POS(ch) = POS_SITTING; + return; + } switch (GET_POS(ch)) { case POS_STANDING: - if (found == 0) { - send_to_char(ch, "You sit down.\r\n"); - act("$n sits down.", FALSE, ch, 0, 0, TO_ROOM); - GET_POS(ch) = POS_SITTING; - } else { - if (GET_OBJ_TYPE(furniture) != ITEM_FURNITURE) { - send_to_char(ch, "You can't sit on that!\r\n"); - return; - } else if (GET_OBJ_VAL(furniture, 1) > GET_OBJ_VAL(furniture, 0)) { - /* Val 1 is current number sitting, 0 is max in sitting. */ - act("$p looks like it's all full.", TRUE, ch, furniture, 0, TO_CHAR); - log("SYSERR: Furniture %d holding too many people.", GET_OBJ_VNUM(furniture)); - return; - } else if (GET_OBJ_VAL(furniture, 1) == GET_OBJ_VAL(furniture, 0)) { - 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)) { - if (NEXT_SITTING(tempch)) - continue; - NEXT_SITTING(tempch) = ch; - } - act("You sit down on $p.", TRUE, ch, furniture, 0, TO_CHAR); - act("$n sits down on $p.", TRUE, ch, furniture, 0, TO_ROOM); - SITTING(ch) = furniture; - NEXT_SITTING(ch) = NULL; - GET_OBJ_VAL(furniture, 1) += 1; - GET_POS(ch) = POS_SITTING; - } - } + send_to_char(ch, "You sit down.\r\n"); + act("$n sits down.", FALSE, ch, 0, 0, TO_ROOM); + GET_POS(ch) = POS_SITTING; break; case POS_SITTING: send_to_char(ch, "You're sitting already.\r\n"); break; case POS_RESTING: send_to_char(ch, "You stop resting, and sit up.\r\n"); - if (SITTING(ch) && GET_OBJ_TYPE(SITTING(ch)) == ITEM_FURNITURE) - act("$n stops resting and sits up on $p.", TRUE, ch, SITTING(ch), 0, TO_ROOM); + if (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) + act("$n stops resting and sits up on $p.", TRUE, ch, current_furniture, 0, TO_ROOM); else act("$n stops resting and sits up.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SITTING; @@ -865,8 +1108,8 @@ ACMD(do_sit) break; default: send_to_char(ch, "You stop floating around, and sit down.\r\n"); - if (SITTING(ch) && GET_OBJ_TYPE(SITTING(ch)) == ITEM_FURNITURE) - act("$n stops floating around, and sits down on $p.", TRUE, ch, SITTING(ch), 0, TO_ROOM); + if (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) + act("$n stops floating around, and sits down on $p.", TRUE, ch, current_furniture, 0, TO_ROOM); else act("$n stops floating around, and sits down.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SITTING; @@ -876,11 +1119,80 @@ ACMD(do_sit) ACMD(do_rest) { + char token[MAX_INPUT_LENGTH]; + struct obj_data *furniture = NULL, *current_furniture = SITTING(ch); + bool has_target = FALSE, used_number = FALSE; + int ordinal = 0; + + if (*argument) { + if (!extract_furniture_token(ch, argument, token, sizeof(token), "Rest")) + return; + has_target = TRUE; + furniture = find_furniture_target(ch, token, &used_number, &ordinal); + if (!furniture) { + if (used_number) + send_to_char(ch, "You don't see furniture #%d here.\r\n", ordinal); + else + send_to_char(ch, "You don't see that here.\r\n"); + return; + } + } + + if (has_target) { + bool already_there = (current_furniture && current_furniture == furniture); + + if (GET_POS(ch) == POS_SLEEPING) { + send_to_char(ch, "You have to wake up first.\r\n"); + return; + } + if (GET_POS(ch) == POS_FIGHTING) { + send_to_char(ch, "Rest while fighting? Are you MAD?\r\n"); + return; + } + + if (!validate_furniture_use(ch, furniture, (1 << 2), "rest", already_there)) + return; + + if (already_there) { + if (GET_POS(ch) == POS_RESTING) { + act("You are already resting on $p.", TRUE, ch, furniture, 0, TO_CHAR); + return; + } + } else if (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) { + const char *leaving = position_gerund(GET_POS(ch)); + act("You stop $T on $p.", TRUE, ch, current_furniture, (char *)leaving, TO_CHAR); + act("$n stops $T on $p.", TRUE, ch, current_furniture, (char *)leaving, TO_ROOM); + char_from_furniture(ch); + } + + if (!already_there) + attach_char_to_furniture(ch, furniture); + + const char *self_msg = "You rest on $p."; + const char *room_msg = "$n rests on $p."; + + if (GET_POS(ch) == POS_STANDING) { + self_msg = "You sit down and rest on $p."; + room_msg = "$n sits down and rests on $p."; + } else if (GET_POS(ch) == POS_SITTING) { + self_msg = "You rest on $p."; + room_msg = "$n rests on $p."; + } else if (GET_POS(ch) == POS_RESTING && !already_there) { + self_msg = "You continue resting on $p."; + room_msg = "$n continues resting on $p."; + } + + act(self_msg, TRUE, ch, furniture, 0, TO_CHAR); + act(room_msg, TRUE, ch, furniture, 0, TO_ROOM); + GET_POS(ch) = POS_RESTING; + return; + } + switch (GET_POS(ch)) { case POS_STANDING: - if (SITTING(ch) && GET_OBJ_TYPE(SITTING(ch)) == ITEM_FURNITURE) { - act("You sit down and rest on $p.", TRUE, ch, SITTING(ch), 0, TO_CHAR); - act("$n sits down and rests on $p.", TRUE, ch, SITTING(ch), 0, TO_ROOM); + if (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) { + act("You sit down and rest on $p.", TRUE, ch, current_furniture, 0, TO_CHAR); + act("$n sits down and rests on $p.", TRUE, ch, current_furniture, 0, TO_ROOM); } else { send_to_char(ch, "You sit down and rest your tired bones.\r\n"); act("$n sits down and rests.", TRUE, ch, 0, 0, TO_ROOM); @@ -890,15 +1202,15 @@ ACMD(do_rest) 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 (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) { + int allowed_positions = GET_OBJ_VAL(current_furniture, VAL_FURN_POSITIONS); /* 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); + act("$p doesn't look comfortable for resting.", TRUE, ch, current_furniture, 0, TO_CHAR); return; } /* Valid furniture + resting */ - act("You rest on $p.", TRUE, ch, SITTING(ch), 0, TO_CHAR); - act("$n rests on $p.", TRUE, ch, SITTING(ch), 0, TO_ROOM); + act("You rest on $p.", TRUE, ch, current_furniture, 0, TO_CHAR); + act("$n rests on $p.", TRUE, ch, current_furniture, 0, TO_ROOM); } else { send_to_char(ch, "You rest your tired bones.\r\n"); act("$n rests.", TRUE, ch, 0, 0, TO_ROOM); @@ -920,8 +1232,8 @@ ACMD(do_rest) default: send_to_char(ch, "You stop floating around, and stop to rest your tired bones.\r\n"); - if (SITTING(ch) && GET_OBJ_TYPE(SITTING(ch)) == ITEM_FURNITURE) - act("$n stops floating around, and rests on $p.", FALSE, ch, SITTING(ch), 0, TO_ROOM); + if (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) + act("$n stops floating around, and rests on $p.", FALSE, ch, current_furniture, 0, TO_ROOM); else act("$n stops floating around, and rests.", FALSE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_RESTING; @@ -931,20 +1243,70 @@ ACMD(do_rest) ACMD(do_sleep) { + char token[MAX_INPUT_LENGTH]; + struct obj_data *furniture = NULL, *current_furniture = SITTING(ch); + bool has_target = FALSE, used_number = FALSE; + int ordinal = 0; + + if (*argument) { + if (!extract_furniture_token(ch, argument, token, sizeof(token), "Sleep")) + return; + has_target = TRUE; + furniture = find_furniture_target(ch, token, &used_number, &ordinal); + if (!furniture) { + if (used_number) + send_to_char(ch, "You don't see furniture #%d here.\r\n", ordinal); + else + send_to_char(ch, "You don't see that here.\r\n"); + return; + } + } + + if (has_target) { + bool already_there = (current_furniture && current_furniture == furniture); + + if (GET_POS(ch) == POS_SLEEPING) { + send_to_char(ch, "You are already sound asleep.\r\n"); + return; + } + if (GET_POS(ch) == POS_FIGHTING) { + send_to_char(ch, "Sleep while fighting? Are you MAD?\r\n"); + return; + } + + if (!validate_furniture_use(ch, furniture, (1 << 3), "sleep", already_there)) + return; + + if (!already_there && current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) { + const char *leaving = position_gerund(GET_POS(ch)); + act("You stop $T on $p.", TRUE, ch, current_furniture, (char *)leaving, TO_CHAR); + act("$n stops $T on $p.", TRUE, ch, current_furniture, (char *)leaving, TO_ROOM); + char_from_furniture(ch); + } + + if (!already_there) + attach_char_to_furniture(ch, furniture); + + act("You go to sleep on $p.", TRUE, ch, furniture, 0, TO_CHAR); + act("$n lies down and falls asleep on $p.", TRUE, ch, furniture, 0, TO_ROOM); + GET_POS(ch) = POS_SLEEPING; + return; + } + switch (GET_POS(ch)) { 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 (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) { + int allowed_positions = GET_OBJ_VAL(current_furniture, VAL_FURN_POSITIONS); /* 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); + act("$p doesn't look comfortable for sleeping.", TRUE, ch, current_furniture, 0, TO_CHAR); return; } /* Valid furniture + sleeping */ - act("You go to sleep on $p.", TRUE, ch, SITTING(ch), 0, TO_CHAR); - act("$n lies down and falls asleep on $p.", TRUE, ch, SITTING(ch), 0, TO_ROOM); + act("You go to sleep on $p.", TRUE, ch, current_furniture, 0, TO_CHAR); + act("$n lies down and falls asleep on $p.", TRUE, ch, current_furniture, 0, TO_ROOM); } else { send_to_char(ch, "You go to sleep.\r\n"); act("$n lies down and falls asleep.", TRUE, ch, 0, 0, TO_ROOM); @@ -962,8 +1324,8 @@ ACMD(do_sleep) default: send_to_char(ch, "You stop floating around, and lie down to sleep.\r\n"); - if (SITTING(ch) && GET_OBJ_TYPE(SITTING(ch)) == ITEM_FURNITURE) - act("$n stops floating around, and lies down to sleep on $p.", TRUE, ch, SITTING(ch), 0, TO_ROOM); + if (current_furniture && GET_OBJ_TYPE(current_furniture) == ITEM_FURNITURE) + act("$n stops floating around, and lies down to sleep on $p.", TRUE, ch, current_furniture, 0, TO_ROOM); else act("$n stops floating around, and lies down to sleep.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SLEEPING;