/** * @file act_move.c * @ingroup common * * Movement commands, door handling, and sleep/rest/etc state * * @author Part of CircleMUD * * @par Copyright: * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University<br> * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * * @par * All rights reserved. See license.doc for complete information. * * @package cs * @version 1.0 */ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "utils.h" #include "character.h" #include "comm.h" #include "command.h" #include "interpreter.h" #include "handler.h" #include "db.h" #include "spells.h" #include "house.h" #include "constants.h" #include "log.h" #include "base.h" #include "zone.h" #include "room.h" #include "item.h" /* external variables */ extern int tunnel_size; /* external functions */ int special(charData_t *ch, const commandData_t *cmd, char *arg); void death_cry(charData_t *ch); int find_eq_pos(charData_t *ch, itemData_t *obj, char *arg); /* local functions */ int has_boat(charData_t *ch); int find_door(charData_t *ch, const char *type, char *dir, const char *cmdname); int has_key(charData_t *ch, itemData_t *key); void do_doorcmd(charData_t *ch, itemData_t *obj, int door, const commandData_t *cmd); int ok_pick(charData_t *ch, itemData_t *key, int pickproof, const commandData_t *cmd); /** * Simple function to determine if char can walk on water * @param ch Character to check * @returns TRUE or FALSE * @todo Update to bool instead of int */ int has_boat(charData_t *ch) { itemData_t *obj; int i; /* if (ROOM_IDENTITY(IN_ROOM(ch)) == DEAD_SEA) return (1); */ if (GET_AUTH(ch) >= AUTH_WIZARD) return (1); if (AFF_FLAGGED(ch, AFF_WATERWALK)) return (1); /* non-wearable boats in inventory will do it */ for (obj = ch->carrying; obj; obj = obj->nextContent) if (GET_ITEM_TYPE(obj) == ITEM_BOAT && (find_eq_pos(ch, obj, NULL) < 0)) return (1); /* and any boat you're wearing will do it too */ for (i = 0; i < NUM_WEARS; i++) if (GET_EQ(ch, i) && GET_ITEM_TYPE(GET_EQ(ch, i)) == ITEM_BOAT) return (1); return (0); } /** * Move a character in a given direction * * do_simple_move assumes * 1. That there is no master and no followers. * 2. That the direction exists. * * @param ch Character to move * @param dir Direction to move * @param need_specials_check Should a spec_proc() check be run after the move * @returns TRUE or FALSE * @todo Update to bool instead of int */ int do_simple_move(charData_t *ch, int dir, int need_specials_check) { char throwaway[MAX_INPUT_LENGTH] = ""; /* Functions assume writable. */ roomData_t *was_in; int need_movement; const commandData_t *cmd = find_command(dirs[dir]); /* * Check for special routines (North is 1 in command list, but 0 here) Note * -- only check if following; this avoids 'double spec-proc' bug */ if (need_specials_check && special(ch, cmd, throwaway)) return (0); /* charmed? */ if (AFF_FLAGGED(ch, AFF_CHARM) && ch->master && IN_ROOM(ch) == IN_ROOM(ch->master)) { send_to_char(ch, "The thought of leaving your master makes you weep.\r\n"); act("$n bursts into tears.", FALSE, ch, 0, 0, TO_ROOM); return (0); } /* if this room or the one we're going to needs a boat, check for one */ if ((SECT(IN_ROOM(ch)) == SECT_WATER_NOSWIM) || (SECT(EXIT(ch, dir)->toRoom) == SECT_WATER_NOSWIM)) { if (!has_boat(ch)) { send_to_char(ch, "You need a boat to go there.\r\n"); return (0); } } /* move points needed is avg. move loss for src and destination sect type */ need_movement = (movement_loss[SECT(IN_ROOM(ch))] + movement_loss[SECT(EXIT(ch, dir)->toRoom)]) / 2; if (GET_MOVE(ch) < need_movement && !IS_NPC(ch)) { if (need_specials_check && ch->master) send_to_char(ch, "You are too exhausted to follow.\r\n"); else send_to_char(ch, "You are too exhausted.\r\n"); return (0); } if (ROOM_FLAGGED(IN_ROOM(ch), ROOM_ATRIUM)) { if (!House_can_enter(ch, EXIT(ch, dir)->toRoom)) { send_to_char(ch, "That's private property -- no trespassing!\r\n"); return (0); } } if (ROOM_FLAGGED(EXIT(ch, dir)->toRoom, ROOM_TUNNEL) && num_pc_in_room(EXIT(ch, dir)->toRoom) >= tunnel_size) { if (tunnel_size > 1) send_to_char(ch, "There isn't enough room for you to go there!\r\n"); else send_to_char(ch, "There isn't enough room there for more than one person!\r\n"); return (0); } /* Mortals cannot enter wizard rooms. */ if (ROOM_FLAGGED(EXIT(ch, dir)->toRoom, ROOM_WIZROOM) && GET_AUTH(ch) < AUTH_WIZARD) { send_to_char(ch, "You aren't godly enough to use that room!\r\n"); return (0); } /* Now we know we're allow to go into the room. */ if (GET_AUTH(ch) < AUTH_WIZARD && !IS_NPC(ch)) GET_MOVE(ch) -= need_movement; if (!AFF_FLAGGED(ch, AFF_SNEAK)) { char buf2[MAX_STRING_LENGTH]; snprintf(buf2, sizeof(buf2), "$n leaves %s.", dirs[dir]); act(buf2, TRUE, ch, 0, 0, TO_ROOM); } was_in = IN_ROOM(ch); char_fromRoom(ch); char_toRoom(ch, was_in->dir[dir]->toRoom); if (!AFF_FLAGGED(ch, AFF_SNEAK)) act("$n has arrived.", TRUE, ch, 0, 0, TO_ROOM); if (ch->desc != NULL) look_at_room(ch, 0); if (ROOM_FLAGGED(IN_ROOM(ch), ROOM_DEATH) && GET_AUTH(ch) < AUTH_WIZARD) { log_death_trap(ch); death_cry(ch); char_extract(ch); return (0); } return (1); } /** * Higher level character movement command * * This function will check to see if a direction exists and any door which * might be there is open, and if so passes character to do_simple_move * * @param ch Character to move * @param dir Direction to move * @param need_specials_check Should a spec_proc() check be run after the move * @returns TRUE or FALSE * @todo Update to bool instead of int */ int perform_move(charData_t *ch, int dir, int need_specials_check) { roomData_t *was_in = NULL; followData_t *k, *next; if (ch == NULL || dir < 0 || dir >= NUM_OF_DIRS || FIGHTING(ch)) return (0); else if (!EXIT(ch, dir) || EXIT(ch, dir)->toRoom == NULL) send_to_char(ch, "Alas, you cannot go that way...\r\n"); else if (EXIT_FLAGGED(EXIT(ch, dir), EX_CLOSED)) { if (EXIT(ch, dir)->keyword) send_to_char(ch, "The %s seems to be closed.\r\n", fname(EXIT(ch, dir)->keyword)); else send_to_char(ch, "It seems to be closed.\r\n"); } else { if (!ch->followers) return (do_simple_move(ch, dir, need_specials_check)); was_in = IN_ROOM(ch); if (!do_simple_move(ch, dir, need_specials_check)) return (0); for (k = ch->followers; k; k = next) { next = k->next; if ((IN_ROOM(k->follower) == was_in) && (GET_POS(k->follower) >= POS_STANDING)) { act("You follow $N.\r\n", FALSE, k->follower, 0, ch, TO_CHAR); perform_move(k->follower, dir, 1); } } return (1); } return (0); } /** * MOVE command * * This command lets a user move in a stated direction * * @param ch the character performing the command * @param argument the additional text passed after the command * @param cmd the command object that was performed * @returns none * @sa perform_move */ ACMD(do_move) { if (CMD_IS("north")) perform_move(ch, 0, 0); else if (CMD_IS("east")) perform_move(ch, 1, 0); else if (CMD_IS("south")) perform_move(ch, 2, 0); else if (CMD_IS("west")) perform_move(ch, 3, 0); else if (CMD_IS("up")) perform_move(ch, 4, 0); else if (CMD_IS("down")) perform_move(ch, 5, 0); } /** * Find a door by specified keyword/name * * @param ch Character looking for a door * @param type Specified keyword for the door to find * @param dir A specific direction or NULL * @param cmdname Text value of the command "open", "unlock", "close", etc * @returns Numeric value of door if found, or -1 */ int find_door(charData_t *ch, const char *type, char *dir, const char *cmdname) { int door; if (*dir) { /* a direction was specified */ if ((door = search_block(dir, dirs, FALSE)) == -1) { /* Partial Match */ send_to_char(ch, "That's not a direction.\r\n"); return (-1); } if (EXIT(ch, door)) { /* Braces added according to indent. -gg */ if (EXIT(ch, door)->keyword) { if (isname(type, EXIT(ch, door)->keyword)) return (door); else { send_to_char(ch, "I see no %s there.\r\n", type); return (-1); } } else return (door); } else { send_to_char(ch, "I really don't see how you can %s anything there.\r\n", cmdname); return (-1); } } else { /* try to locate the keyword */ if (!*type) { send_to_char(ch, "What is it you want to %s?\r\n", cmdname); return (-1); } for (door = 0; door < NUM_OF_DIRS; door++) if (EXIT(ch, door)) if (EXIT(ch, door)->keyword) if (isname(type, EXIT(ch, door)->keyword)) return (door); send_to_char(ch, "There doesn't seem to be %s %s here.\r\n", AN(type), type); return (-1); } } /** * Check to see if a character has a key object * * This function takes a key object in and checks to see if the characater * has that object in their inventory or equipped. It does /not/ recurse * through containers. * * The key objects are set on exits during boot, pointing to the prototype * entry for that string vnum (ex: "midgaard:3000") * * @param ch Character to check * @param key Pointer to the key object (prototype) * @returns TRUE or FALSE * @todo Update to bool instead of int */ int has_key(charData_t *ch, itemData_t *key) { itemData_t *o; for (o = ch->carrying; o; o = o->nextContent) if (o->prototype == key) return (1); if (GET_EQ(ch, WEAR_HOLD)) if (GET_EQ(ch, WEAR_HOLD)->prototype == key) return (1); return (0); } #define NEED_OPEN BIT_00 /**< Open bit */ #define NEED_CLOSED BIT_01 /**< Closed bit */ #define NEED_UNLOCKED BIT_02 /**< Unlocked bit */ #define NEED_LOCKED BIT_03 /**< Locked bit */ const char *cmd_door[] = { "open", "close", "unlock", "lock", "pick" }; const int flags_door[] = { NEED_CLOSED | NEED_UNLOCKED, NEED_OPEN, NEED_CLOSED | NEED_LOCKED, NEED_CLOSED | NEED_UNLOCKED, NEED_CLOSED | NEED_LOCKED }; /** * Macro to find an exit by number in a room by RNum */ #define EXITN(room, door) (room->dir[door]) /** * Set door open */ #define OPEN_DOOR(room, obj, door) ((obj) ?\ (REMOVE_BIT(GET_ITEM_VAL(obj, 1), CONT_CLOSED)) :\ (REMOVE_BIT(EXITN(room, door)->exitInfo, EX_CLOSED))) /** * Set door closed */ #define CLOSE_DOOR(room, obj, door) ((obj) ?\ (SET_BIT(GET_ITEM_VAL(obj, 1), CONT_CLOSED)) :\ (SET_BIT(EXITN(room, door)->exitInfo, EX_CLOSED))) /** * Set door locked */ #define LOCK_DOOR(room, obj, door) ((obj) ?\ (SET_BIT(GET_ITEM_VAL(obj, 1), CONT_LOCKED)) :\ (SET_BIT(EXITN(room, door)->exitInfo, EX_LOCKED))) /** * Set door unlocked */ #define UNLOCK_DOOR(room, obj, door) ((obj) ?\ (REMOVE_BIT(GET_ITEM_VAL(obj, 1), CONT_LOCKED)) :\ (REMOVE_BIT(EXITN(room, door)->exitInfo, EX_LOCKED))) /** * Toggle the locked/unlock status of a door */ #define TOGGLE_LOCK(room, obj, door) ((obj) ?\ (TOGGLE_BIT(GET_ITEM_VAL(obj, 1), CONT_LOCKED)) :\ (TOGGLE_BIT(EXITN(room, door)->exitInfo, EX_LOCKED))) /** * Perform an action on a door. "open", "close", "lock", etc * * @param ch Character performing action * @param obj Item being used in the action or NULL * @param door Exit number of the door * @param cmd Numeric value of the command "open", "unlock", "close", etc * @returns none */ void do_doorcmd(charData_t *ch, itemData_t *obj, int door, const commandData_t *cmd) { char buf[MAX_STRING_LENGTH]; size_t len; roomData_t *other_room = NULL; roomExitData_t *back = NULL; int dcmd = 0; if (CMD_IS("open")) dcmd = 0; else if (CMD_IS("close")) dcmd = 1; else if (CMD_IS("unlock")) dcmd = 2; else if (CMD_IS("lock")) dcmd = 3; else if (CMD_IS("pick")) dcmd = 4; len = snprintf(buf, sizeof(buf), "$n %ss ", cmd_door[dcmd]); if (!obj && ((other_room = EXIT(ch, door)->toRoom) != NULL)) if ((back = other_room->dir[rev_dir[door]]) != NULL) if (back->toRoom != IN_ROOM(ch)) back = NULL; if (CMD_IS("open")) { OPEN_DOOR(IN_ROOM(ch), obj, door); if (back) OPEN_DOOR(other_room, obj, rev_dir[door]); send_to_char(ch, "%s", OK); } else if (CMD_IS("close")) { CLOSE_DOOR(IN_ROOM(ch), obj, door); if (back) CLOSE_DOOR(other_room, obj, rev_dir[door]); send_to_char(ch, "%s", OK); } else if (CMD_IS("lock")) { LOCK_DOOR(IN_ROOM(ch), obj, door); if (back) LOCK_DOOR(other_room, obj, rev_dir[door]); send_to_char(ch, "*Click*\r\n"); } else if (CMD_IS("unlock")) { UNLOCK_DOOR(IN_ROOM(ch), obj, door); if (back) UNLOCK_DOOR(other_room, obj, rev_dir[door]); send_to_char(ch, "*Click*\r\n"); } else if (CMD_IS("pick")) { TOGGLE_LOCK(IN_ROOM(ch), obj, door); if (back) TOGGLE_LOCK(other_room, obj, rev_dir[door]); send_to_char(ch, "The lock quickly yields to your skills.\r\n"); len = strlcpy(buf, "$n skillfully picks the lock on ", sizeof(buf)); } /* Notify the room. */ if (len < sizeof(buf)) snprintf(buf + len, sizeof(buf) - len, "%s%s.", obj ? "" : "the ", obj ? "$p" : EXIT(ch, door)->keyword ? "$F" : "door"); if (!obj || IN_ROOM(obj) != NULL) act(buf, FALSE, ch, obj, obj ? 0 : EXIT(ch, door)->keyword, TO_ROOM); /* Notify the other room */ if (back && (CMD_IS("open") || CMD_IS("close"))) send_to_room(EXIT(ch, door)->toRoom, "The %s is %s%s from the other side.", back->keyword ? fname(back->keyword) : "door", cmd_door[dcmd], CMD_IS("close") ? "d" : "ed"); } /** * Attempt to pick a lock on a door * @param ch Character attempting to pick the lock * @param key Pointer to key prototype or NULL * @param pickproof Value if the lock is un-pickable. TRUE or FALSE. * @param cmd Command value, "pick" to run * @returns TRUE or FALSE * @todo Update to bool instead of int */ int ok_pick(charData_t *ch, itemData_t *key, int pickproof, const commandData_t *cmd) { int percent, skill_lvl; if (!CMD_IS("pick")) return (1); percent = rand_number(1, 101); skill_lvl = GET_SKILL(ch, SKILL_PICK_LOCK) + dex_app_skill[GET_DEX(ch)].p_locks; if (key == NULL) send_to_char(ch, "Odd - you can't seem to find a keyhole.\r\n"); else if (pickproof) send_to_char(ch, "It resists your attempts to pick it.\r\n"); else if (percent > skill_lvl) send_to_char(ch, "You failed to pick the lock.\r\n"); else return (1); return (0); } /** * Check if door can be opened */ #define DOOR_IS_OPENABLE(ch, obj, door) ((obj) ? \ ((GET_ITEM_TYPE(obj) == ITEM_CONTAINER) && \ ITEMVAL_FLAGGED(obj, CONT_CLOSEABLE)) :\ (EXIT_FLAGGED(EXIT(ch, door), EX_ISDOOR))) /** * Check if a door is open */ #define DOOR_IS_OPEN(ch, obj, door) ((obj) ? \ (!ITEMVAL_FLAGGED(obj, CONT_CLOSED)) :\ (!EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED))) /** * Check if a door is unlocked */ #define DOOR_IS_UNLOCKED(ch, obj, door) ((obj) ? \ (!ITEMVAL_FLAGGED(obj, CONT_LOCKED)) :\ (!EXIT_FLAGGED(EXIT(ch, door), EX_LOCKED))) /** * Check if a door's lock can be picked */ #define DOOR_IS_PICKPROOF(ch, obj, door) ((obj) ? \ (ITEMVAL_FLAGGED(obj, CONT_PICKPROOF)) : \ (EXIT_FLAGGED(EXIT(ch, door), EX_PICKPROOF))) /** * Check if a door is closed */ #define DOOR_IS_CLOSED(ch, obj, door) (!(DOOR_IS_OPEN(ch, obj, door))) /** * Check if a door is locked */ #define DOOR_IS_LOCKED(ch, obj, door) (!(DOOR_IS_UNLOCKED(ch, obj, door))) #define DOOR_KEY(ch, obj, door) ((obj) ? (obj)->key ? (obj)->key : NULL : (EXIT(ch, door)->key)) /** * OPEN, CLOSE, UNLOCK, LOCK, PICK commands * * These commands allow a user to interact with doors * * @param ch the character performing the command * @param argument the additional text passed after the command * @param cmd the command object that was performed * @returns none */ ACMD(do_gen_door) { int door = -1; char type[MAX_INPUT_LENGTH], dir[MAX_INPUT_LENGTH]; itemData_t *obj = NULL; charData_t *victim = NULL; itemData_t *key = NULL; int doorcmd = 0; if (CMD_IS("open")) doorcmd = 0; else if (CMD_IS("close")) doorcmd = 1; else if (CMD_IS("unlock")) doorcmd = 2; else if (CMD_IS("lock")) doorcmd = 3; else if (CMD_IS("pick")) doorcmd = 4; skip_spaces(&argument); if (!*argument) { send_to_char(ch, "%c%s what?\r\n", UPPER(*cmd_door[doorcmd]), cmd_door[doorcmd] + 1); return; } two_arguments(argument, type, dir); if (!generic_find(type, FIND_ITEM_INV | FIND_ITEM_ROOM, ch, &victim, &obj)) door = find_door(ch, type, dir, cmd_door[doorcmd]); if ((obj) || (door >= 0)) { key = DOOR_KEY(ch, obj, door); if (!(DOOR_IS_OPENABLE(ch, obj, door))) act("You can't $F that!", FALSE, ch, 0, cmd_door[doorcmd], TO_CHAR); else if (!DOOR_IS_OPEN(ch, obj, door) && IS_SET(flags_door[doorcmd], NEED_OPEN)) send_to_char(ch, "But it's already closed!\r\n"); else if (!DOOR_IS_CLOSED(ch, obj, door) && IS_SET(flags_door[doorcmd], NEED_CLOSED)) send_to_char(ch, "But it's currently open!\r\n"); else if (!(DOOR_IS_LOCKED(ch, obj, door)) && IS_SET(flags_door[doorcmd], NEED_LOCKED)) send_to_char(ch, "Oh.. it wasn't locked, after all..\r\n"); else if (!(DOOR_IS_UNLOCKED(ch, obj, door)) && IS_SET(flags_door[doorcmd], NEED_UNLOCKED)) send_to_char(ch, "It seems to be locked.\r\n"); else if (!has_key(ch, key) && GET_AUTH(ch) < AUTH_WIZARD && ((CMD_IS("lock")) || (CMD_IS("unlock")))) send_to_char(ch, "You don't seem to have the proper key.\r\n"); else if (ok_pick(ch, key, DOOR_IS_PICKPROOF(ch, obj, door), cmd)) do_doorcmd(ch, obj, door, cmd); } return; } /** * ENTER command * * This command lets a user enter through a door * * @param ch the character performing the command * @param argument the additional text passed after the command * @param cmd the command object that was performed * @returns none */ ACMD(do_enter) { char buf[MAX_INPUT_LENGTH]; int door; one_argument(argument, buf); if (*buf) { /* an argument was supplied, search for door * keyword */ for (door = 0; door < NUM_OF_DIRS; door++) if (EXIT(ch, door)) if (EXIT(ch, door)->keyword) if (!str_cmp(EXIT(ch, door)->keyword, buf)) { perform_move(ch, door, 1); return; } send_to_char(ch, "There is no %s here.\r\n", buf); } else if (ROOM_FLAGGED(IN_ROOM(ch), ROOM_INDOORS)) send_to_char(ch, "You are already indoors.\r\n"); else { /* try to locate an entrance */ for (door = 0; door < NUM_OF_DIRS; door++) if (EXIT(ch, door)) if (EXIT(ch, door)->toRoom != NULL) if (!EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED) && ROOM_FLAGGED(EXIT(ch, door)->toRoom, ROOM_INDOORS)) { perform_move(ch, door, 1); return; } send_to_char(ch, "You can't seem to find anything to enter.\r\n"); } } /** * LEAVE command * * This command lets a user leave through a door * * @param ch the character performing the command * @param argument the additional text passed after the command * @param cmd the command object that was performed * @returns none */ ACMD(do_leave) { int door; if (OUTSIDE(ch)) send_to_char(ch, "You are outside.. where do you want to go?\r\n"); else { for (door = 0; door < NUM_OF_DIRS; door++) if (EXIT(ch, door)) if (EXIT(ch, door)->toRoom != NULL) if (!EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED) && !ROOM_FLAGGED(EXIT(ch, door)->toRoom, ROOM_INDOORS)) { perform_move(ch, door, 1); return; } send_to_char(ch, "I see no obvious exits to the outside.\r\n"); } } /** * STAND command * * This command lets a user stand up * * @param ch the character performing the command * @param argument the additional text passed after the command * @param cmd the command object that was performed * @returns none */ ACMD(do_stand) { switch (GET_POS(ch)) { case POS_STANDING: send_to_char(ch, "You are already standing.\r\n"); break; case POS_SITTING: send_to_char(ch, "You stand up.\r\n"); act("$n clambers to $s feet.", TRUE, ch, 0, 0, TO_ROOM); /* Will be sitting after a successful bash and may still be fighting. */ GET_POS(ch) = FIGHTING(ch) ? POS_FIGHTING : POS_STANDING; break; case POS_RESTING: 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); GET_POS(ch) = POS_STANDING; break; case POS_SLEEPING: send_to_char(ch, "You have to wake up first!\r\n"); break; case POS_FIGHTING: send_to_char(ch, "Do you not consider fighting as standing?\r\n"); break; default: send_to_char(ch, "You stop floating around, and put your feet on the ground.\r\n"); act("$n stops floating around, and puts $s feet on the ground.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_STANDING; break; } } /** * SIT command * * This command lets a user sit down * * @param ch the character performing the command * @param argument the additional text passed after the command * @param cmd the command object that was performed * @returns none */ ACMD(do_sit) { switch (GET_POS(ch)) { case POS_STANDING: 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"); act("$n stops resting.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SITTING; break; case POS_SLEEPING: send_to_char(ch, "You have to wake up first.\r\n"); break; case POS_FIGHTING: send_to_char(ch, "Sit down while fighting? Are you MAD?\r\n"); break; default: send_to_char(ch, "You stop floating around, and sit down.\r\n"); act("$n stops floating around, and sits down.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SITTING; break; } } /** * REST command * * This command lets a user rest * * @param ch the character performing the command * @param argument the additional text passed after the command * @param cmd the command object that was performed * @returns none */ ACMD(do_rest) { switch (GET_POS(ch)) { case POS_STANDING: 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); GET_POS(ch) = POS_RESTING; break; case POS_SITTING: 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; break; case POS_RESTING: send_to_char(ch, "You are already resting.\r\n"); break; case POS_SLEEPING: send_to_char(ch, "You have to wake up first.\r\n"); break; case POS_FIGHTING: send_to_char(ch, "Rest while fighting? Are you MAD?\r\n"); break; default: send_to_char(ch, "You stop floating around, and stop to rest your tired bones.\r\n"); act("$n stops floating around, and rests.", FALSE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SITTING; break; } } /** * SLEEP command * * This command lets a user sleep * * @param ch the character performing the command * @param argument the additional text passed after the command * @param cmd the command object that was performed * @returns none */ ACMD(do_sleep) { switch (GET_POS(ch)) { case POS_STANDING: case POS_SITTING: case POS_RESTING: 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; break; case POS_SLEEPING: send_to_char(ch, "You are already sound asleep.\r\n"); break; case POS_FIGHTING: send_to_char(ch, "Sleep while fighting? Are you MAD?\r\n"); break; default: send_to_char(ch, "You stop floating around, and lie down to sleep.\r\n"); act("$n stops floating around, and lie down to sleep.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SLEEPING; break; } } /** * WAKE command * * This command lets a user wake up * * @param ch the character performing the command * @param argument the additional text passed after the command * @param cmd the command object that was performed * @returns none */ ACMD(do_wake) { char arg[MAX_INPUT_LENGTH]; charData_t *vict; int self = 0; one_argument(argument, arg); if (*arg) { if (GET_POS(ch) == POS_SLEEPING) send_to_char(ch, "Maybe you should wake yourself up first.\r\n"); else if ((vict = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM)) == NULL) send_to_char(ch, "%s", NOPERSON); else if (vict == ch) self = 1; else if (AWAKE(vict)) act("$E is already awake.", FALSE, ch, 0, vict, TO_CHAR); else if (AFF_FLAGGED(vict, AFF_SLEEP)) act("You can't wake $M up!", FALSE, ch, 0, vict, TO_CHAR); else if (GET_POS(vict) < POS_SLEEPING) act("$E's in pretty bad shape!", FALSE, ch, 0, vict, TO_CHAR); else { act("You wake $M up.", FALSE, ch, 0, vict, TO_CHAR); act("You are awakened by $n.", FALSE, ch, 0, vict, TO_VICT | TO_SLEEP); GET_POS(vict) = POS_SITTING; } if (!self) return; } if (AFF_FLAGGED(ch, AFF_SLEEP)) send_to_char(ch, "You can't wake up!\r\n"); else if (GET_POS(ch) > POS_SLEEPING) send_to_char(ch, "You are already awake...\r\n"); else { send_to_char(ch, "You awaken, and sit up.\r\n"); act("$n awakens.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SITTING; } } /** * FOLLOW command * * This command lets a user follow another character * * @param ch the character performing the command * @param argument the additional text passed after the command * @param cmd the command object that was performed * @returns none */ ACMD(do_follow) { char buf[MAX_INPUT_LENGTH]; charData_t *leader; one_argument(argument, buf); if (*buf) { if (!(leader = get_char_vis(ch, buf, NULL, FIND_CHAR_ROOM))) { send_to_char(ch, "%s", NOPERSON); return; } } else { send_to_char(ch, "Whom do you wish to follow?\r\n"); return; } if (ch->master == leader) { act("You are already following $M.", FALSE, ch, 0, leader, TO_CHAR); return; } if (AFF_FLAGGED(ch, AFF_CHARM) && (ch->master)) { act("But you only feel like following $N!", FALSE, ch, 0, ch->master, TO_CHAR); } else { /* Not Charmed follow person */ if (leader == ch) { if (!ch->master) { send_to_char(ch, "You are already following yourself.\r\n"); return; } stop_follower(ch); } else { if (circle_follow(ch, leader)) { send_to_char(ch, "Sorry, but following in loops is not allowed.\r\n"); return; } if (ch->master) stop_follower(ch); REMOVE_BIT(AFF_FLAGS(ch), AFF_GROUP); add_follower(ch, leader); } } }