/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// * * -----------------------------------------------------------| (0...0) * * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( * * -----------------------------------------------------------| {o o} * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~* * Tricops and Fireblade | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Player movement module * ****************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <time.h> #include "mud.h" const sh_int movement_loss [SECT_MAX] = { 1, 2, 2, 3, 4, 6, 4, 6, 6, 10, 6, 3, 7, 4 }; char * const dir_name [] = { "north", "east", "south", "west", "up", "down", "northeast", "northwest", "southeast", "southwest", "somewhere" }; char * const rev_dir_name [] = { "south", "west", "north", "east", "down", "up", "southwest", "southeast", "northwest", "northeast", "somewhere" }; const int trap_door [] = { TRAP_N, TRAP_E, TRAP_S, TRAP_W, TRAP_U, TRAP_D, TRAP_NE, TRAP_NW, TRAP_SE, TRAP_SW }; const sh_int rev_dir [] = { 2, 3, 0, 1, 5, 4, 9, 8, 7, 6, 10 }; ROOM_INDEX_DATA * vroom_hash [64]; /* * Local functions. */ OBJ_DATA *has_key args( ( CHAR_DATA *ch, int key ) ); void drop_dream_items(CHAR_DATA *ch, OBJ_DATA *obj); /* from talent.c */ void travel_teleport(CHAR_DATA *ch); /* from handler.c */ extern void learn_noncombat(CHAR_DATA *ch, int i); char * const sect_names[SECT_MAX][2] = { { "In a room","inside" }, { "In a city", "cities" }, { "In a field","fields" }, { "In a forest","forests" }, { "hill", "hills" }, { "On a mountain","mountains" }, { "In the water","waters" }, { "In rough water","waters" }, { "Underwater", "underwaters" }, { "In the air", "air" }, { "In a desert","deserts" }, { "Somewhere", "unknown" }, { "ocean floor", "ocean floor" }, { "underground", "underground" } }; const int sent_total[SECT_MAX] = { 3, 5, 4, 4, 1, 1, 1, 1, 1, 2, 2, 25, 1, 1 }; char * const room_sents[SECT_MAX][25] = { { "rough hewn walls of granite with the occasional spider crawling around", "signs of a recent battle from the bloodstains on the floor", "a damp musty odour not unlike rotting vegetation" }, { "the occasional stray digging through some garbage", "merchants trying to lure customers to their tents", "some street people putting on an interesting display of talent", "an argument between a customer and a merchant about the price of an item", "several shady figures talking down a dark alleyway" }, { "sparce patches of brush and shrubs", "a small cluster of trees far off in the distance", "grassy fields as far as the eye can see", "a wide variety of weeds and wildflowers" }, { "tall, dark evergreens prevent you from seeing very far", "many huge oak trees that look several hundred years old", "a solitary lonely weeping willow", "a patch of bright white birch trees slender and tall" }, { "rolling hills lightly speckled with violet wildflowers" }, { "the rocky mountain pass offers many hiding places" }, { "the water is smooth as glass" }, { "rough waves splash about angrily" }, { "a small school of fish" }, { "the land far below", "a misty haze of clouds" }, { "sand as far as the eye can see", "an oasis far in the distance" }, { "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", "nothing unusual", }, { "rocks and coral which litter the ocean floor." }, { "a lengthy tunnel of rock." } }; char *grab_word( char *argument, char *arg_first ) { char cEnd; sh_int count; count = 0; while ( isspace(*argument) ) argument++; cEnd = ' '; if ( *argument == '\'' || *argument == '"' ) cEnd = *argument++; while ( *argument != '\0' || ++count >= 255 ) { if ( *argument == cEnd ) { argument++; break; } *arg_first++ = *argument++; } *arg_first = '\0'; while ( isspace(*argument) ) argument++; return argument; } char *wordwrap( char *txt, sh_int wrap ) { static char buf[MAX_STRING_LENGTH]; char *bufp; buf[0] = '\0'; bufp = buf; if ( txt != NULL ) { char line[MAX_STRING_LENGTH]; char temp[MAX_STRING_LENGTH]; char *ptr, *p; int ln, x; ++bufp; line[0] = '\0'; ptr = txt; while ( *ptr ) { ptr = grab_word( ptr, temp ); ln = strlen( line ); x = strlen( temp ); if ( (ln + x + 1) < wrap ) { if ( ln>0 && line[ln-1] == '.' ) strcat( line, " " ); else strcat( line, " " ); strcat( line, temp ); p = strchr( line, '\n' ); if ( !p ) p = strchr( line, '\r' ); if ( p ) { strcat( buf, line ); line[0] = '\0'; } } else { strcat( line, "\r\n" ); strcat( buf, line ); strcpy( line, temp ); } } if ( line[0] != '\0' ) strcat( buf, line ); } return bufp; } void decorate_room( ROOM_INDEX_DATA *room ) { char buf[MAX_STRING_LENGTH]; char buf2[MAX_STRING_LENGTH]; int nRand; int iRand, len; int previous[8]; int sector = room->sector_type; char *pre = "You notice ", *post = "."; if ( room->name ) STRFREE( room->name ); if ( room->description ) STRFREE( room->description ); room->name = STRALLOC( "In a virtual room" ); room->description = STRALLOC( "You're on a pathway.\n\r" ); return; /* Return with above till I can figure out what is * wrong with it. --Shaddai */ room->name = STRALLOC( sect_names[sector][0] ); buf[0] = '\0'; nRand = number_range( 1, UMIN(8,sent_total[sector]) ); for ( iRand = 0; iRand < nRand; iRand++ ) previous[iRand] = -1; for ( iRand = 0; iRand < nRand; iRand++ ) { while ( previous[iRand] == -1 ) { int x, z; x = number_range( 0, sent_total[sector]-1 ); for ( z = 0; z < iRand; z++ ) if ( previous[z] == x ) break; if ( z < iRand ) continue; previous[iRand] = x; len = strlen(buf); if ( len == 0 ) { switch( number_range(1, 2 * (iRand == nRand -1) ? 1 : 2) ) { case 1: pre = "You notice "; post = "."; break; case 2: pre = "You see "; post = "."; break; case 3: pre = "You see "; post = ", and "; break; case 4: pre = "You notice "; post = ", and "; break; } sprintf( buf2, "%s%s%s", pre, room_sents[sector][x], post ); } else if ( iRand != nRand -1 ) { if ( buf[len-1] == '.' ) switch( number_range(0, 3) ) { case 0: pre = "you notice "; post = "."; break; case 1: pre = "you see "; post = ", and "; break; case 2: pre = "you see "; post = "."; break; case 3: pre = "over yonder "; post = ", and "; break; } else switch( number_range(0, 3) ) { case 0: pre = ""; post = "."; break; case 1: pre = ""; post = " not too far away."; break; case 2: pre = ""; post = ", and "; break; case 3: pre = ""; post = " nearby."; break; } sprintf( buf2, "%s%s%s", pre, room_sents[sector][x], post ); } else sprintf( buf2, "%s.", room_sents[sector][x] ); if ( len > 5 && buf[len-1] == '.' ) { strcat( buf, " " ); buf2[0] = UPPER(buf2[0] ); } else if ( len == 0 ) buf2[0] = UPPER(buf2[0] ); strcat( buf, buf2 ); } } /* Below is the line that causes the uninitialized memory read --Shaddai */ sprintf( buf2, "%s\n\r", wordwrap(buf, 78) ); room->description = STRALLOC( buf2 ); } /* * Remove any unused virtual rooms -Thoric */ void clear_vrooms( ) { int hash; ROOM_INDEX_DATA *room, *room_next, *prev; for ( hash = 0; hash < 64; hash++ ) { while ( vroom_hash[hash] && !vroom_hash[hash]->first_person && !vroom_hash[hash]->first_content ) { room = vroom_hash[hash]; vroom_hash[hash] = room->next; clean_room( room ); DISPOSE( room ); --top_vroom; } prev = NULL; for ( room = vroom_hash[hash]; room; room = room_next ) { room_next = room->next; if ( !room->first_person && !room->first_content ) { if ( prev ) prev->next = room_next; clean_room( room ); DISPOSE( room ); --top_vroom; } if ( room ) prev = room; } } } char *rev_exit( sh_int vdir ) { switch( vdir ) { default: return "somewhere"; case 0: return "the south"; case 1: return "the west"; case 2: return "the north"; case 3: return "the east"; case 4: return "below"; case 5: return "above"; case 6: return "the southwest"; case 7: return "the southeast"; case 8: return "the northwest"; case 9: return "the northeast"; } return "<?>"; } /* * Function to get the equivelant exit of DIR 0-MAXDIR out of linked list. * Made to allow old-style diku-merc exit functions to work. -Thoric */ EXIT_DATA *get_exit( ROOM_INDEX_DATA *room, sh_int dir ) { EXIT_DATA *xit; if ( !room ) { bug( "Get_exit: NULL room", 0 ); return NULL; } for (xit = room->first_exit; xit; xit = xit->next ) if ( xit->vdir == dir ) return xit; return NULL; } /* * Function to get an exit, leading the the specified room */ EXIT_DATA *get_exit_to( ROOM_INDEX_DATA *room, sh_int dir, int vnum ) { EXIT_DATA *xit; if ( !room ) { bug( "Get_exit: NULL room", 0 ); return NULL; } for (xit = room->first_exit; xit; xit = xit->next ) if ( xit->vdir == dir && xit->vnum == vnum ) return xit; return NULL; } /* * Function to get the nth exit of a room -Thoric */ EXIT_DATA *get_exit_num( ROOM_INDEX_DATA *room, sh_int count ) { EXIT_DATA *xit; int cnt; if ( !room ) { bug( "Get_exit: NULL room", 0 ); return NULL; } for (cnt = 0, xit = room->first_exit; xit; xit = xit->next ) if ( ++cnt == count ) return xit; return NULL; } /* exploration exp */ void explore_room(CHAR_DATA *ch, ROOM_INDEX_DATA *room) { EXPLORED_AREA *xarea; if (IS_NPC(ch)) return; if (ch->in_room->vnum - ch->in_room->area->low_r_vnum > 125) return; xarea = ch->pcdata->first_explored; while (xarea) { if (xarea->index == ch->in_room->area->low_soft_range) { if (xIS_SET(xarea->rooms, ch->in_room->vnum - ch->in_room->area->low_r_vnum)) return; xSET_BIT(xarea->rooms, ch->in_room->vnum - ch->in_room->area->low_r_vnum); ch->exp += 100000; return; } xarea = xarea->next; } CREATE(xarea, EXPLORED_AREA, 1); xarea->index = ch->in_room->area->low_soft_range; xCLEAR_BITS(xarea->rooms); LINK(xarea, ch->pcdata->first_explored, ch->pcdata->last_explored, next, prev); xSET_BIT(xarea->rooms, ch->in_room->vnum - ch->in_room->area->low_r_vnum); ch->exp += 250000; } /* * Modify movement due to encumbrance -Thoric */ sh_int encumbrance( CHAR_DATA *ch, sh_int move ) { int cur, max; max = can_carry_w(ch); cur = ch->carry_weight; if ( cur >= max ) return move * 4; else if ( cur >= max * 0.95 ) return move * 3.5; else if ( cur >= max * 0.90 ) return move * 3; else if ( cur >= max * 0.85 ) return move * 2.5; else if ( cur >= max * 0.80 ) return move * 2; else if ( cur >= max * 0.75 ) return move * 1.5; else return move; } /* * Check to see if a character can fall down, checks for looping -Thoric */ bool will_fall( CHAR_DATA *ch, int fall ) { if (!ch) return FALSE; if (char_died(ch)) return FALSE; if (IS_AFFECTED(ch, AFF_FLYING) && (IS_NPC(ch) || xIS_SET(ch->pcdata->perm_aff, AFF_FLYING)) && ch->curr_talent[TAL_WIND] < 30 && ch->curr_talent[TAL_MOTION] < 60 && (!can_use_bodypart(ch, BP_RWING) || !can_use_bodypart(ch, BP_LWING))) { act(AT_PLAIN, "You plummet like a rock.", ch, NULL, NULL, TO_CHAR); act(AT_PLAIN, "$n plummets like a rock.", ch, NULL, NULL, TO_ROOM); if (IS_NPC(ch)) xREMOVE_BIT(ch->affected_by, AFF_FLYING); else xREMOVE_BIT(ch->pcdata->perm_aff, AFF_FLYING); } if (ch->in_obj && IS_OBJ_STAT(ch->in_obj, ITEM_HOVER)) return FALSE; if ( IS_SET( ch->in_room->room_flags, ROOM_NOFLOOR ) && CAN_GO(ch, DIR_DOWN)) { /* check for swimming -keo */ if (IS_UNDERWATER(ch)) { if (ch->in_obj && IS_SET(ch->in_obj->value[2], VEHICLE_UNDERWATER)) return FALSE; if ( !can_use_bodypart(ch, BP_RFIN) && !can_use_bodypart(ch, BP_LFIN) && !can_use_bodypart(ch, BP_DFIN) && (( number_percent( ) >= (IS_NPC(ch) ? 100 : LEARNED(ch, gsn_swim ) + (15-encumbrance(ch, 10)) + ch->curr_talent[TAL_WATER] ) ))) { learn_from_failure(ch, gsn_swim); set_char_color( AT_FALLING, ch ); send_to_char( "You're sinking down...\n\r", ch ); move_char( ch, get_exit(ch->in_room, DIR_DOWN), ++fall ); if (ch->in_obj) { obj_from_room(ch->in_obj); obj_to_room(ch->in_obj, ch->in_room); } return TRUE; } else { learn_from_success(ch, gsn_swim); return FALSE; } } else { if ( ch->in_obj || (!IS_AFFECTED( ch, AFF_FLYING ) && ( !ch->mount || !IS_AFFECTED( ch->mount, AFF_FLYING )))) { if ( fall > 80 ) { bug( "Falling (in a loop?) more than 80 rooms: vnum %d", ch->in_room->vnum ); char_from_room( ch ); char_to_room( ch, get_room_index( ROOM_VNUM_NEXUS ) ); fall = 0; return TRUE; } set_char_color( AT_FALLING, ch ); send_to_char( "You're falling down...\n\r", ch ); move_char( ch, get_exit(ch->in_room, DIR_DOWN), ++fall ); if (ch->in_obj) { obj_from_room(ch->in_obj); obj_to_room(ch->in_obj, ch->in_room); } return TRUE; } } } return FALSE; } /* * create a 'virtual' room -Thoric */ ROOM_INDEX_DATA *generate_exit( ROOM_INDEX_DATA *in_room, EXIT_DATA **pexit ) { /* the billion vnum patch really screwed this up, the author didnt understand virtual rooms - shogar */ /* >> and << dont work with long long so fake it out with a small rewrite*/ EXIT_DATA *xit, *bxit; EXIT_DATA *orig_exit = (EXIT_DATA *) *pexit; ROOM_INDEX_DATA *room, *backroom; int brvnum; int serial; int virtual=in_room->virtual; int roomnum; int distance = -1; int vdir = orig_exit->vdir; int hash; bool found = FALSE; if ( virtual ) /* room is virtual */ { serial = in_room->vnum; roomnum = in_room->tele_vnum; if ( (serial) == orig_exit->vnum ) { brvnum = virtual; --roomnum; distance = roomnum; } else { brvnum = virtual; ++roomnum; distance = orig_exit->distance - 1; } backroom = get_room_index( brvnum ); } else { int r1 = in_room->vnum; int r2 = orig_exit->vnum; brvnum = r1; backroom = in_room; /* serial = ((long long) UMAX( r1, r2 ) << 32L) | (long long) UMIN( r1, r2 ); */ serial=r1 + 1048576000; virtual=r1; distance = orig_exit->distance - 1; roomnum = r1 < r2 ? 1 : distance; } hash = serial % 64; for ( room = vroom_hash[hash]; room; room = room->next ) if ( room->vnum == serial && room->tele_vnum == roomnum ) { found = TRUE; break; } if ( !found ) { CREATE( room, ROOM_INDEX_DATA, 1 ); room->area = in_room->area; room->vnum = serial; room->virtual = virtual; room->tele_vnum = roomnum; room->sector_type = in_room->sector_type; room->room_flags = in_room->room_flags; decorate_room( room ); room->next = vroom_hash[hash]; vroom_hash[hash] = room; ++top_vroom; } if ( !found || (xit=get_exit(room, vdir))==NULL ) { xit = make_exit(room, orig_exit->to_room, vdir); xit->keyword = STRALLOC( "" ); xit->description = STRALLOC( "" ); xit->key = -1; xit->distance = distance; } if ( !found ) { bxit = make_exit(room, backroom, rev_dir[vdir]); bxit->keyword = STRALLOC( "" ); bxit->description = STRALLOC( "" ); bxit->key = -1; if ( (serial ) != orig_exit->vnum ) bxit->distance = roomnum; else { EXIT_DATA *tmp = get_exit( backroom, vdir ); int fulldist = tmp->distance; bxit->distance = fulldist - distance; } } (EXIT_DATA *) pexit = xit; return room; } ch_ret move_char( CHAR_DATA *ch, EXIT_DATA *pexit, int fall ) { ROOM_INDEX_DATA *in_room; ROOM_INDEX_DATA *to_room; ROOM_INDEX_DATA *from_room; TRAIL_DATA *trail; TRAIL_DATA *new_trail; CHAR_DATA *gch; char buf[MAX_STRING_LENGTH]; char *txt; char *dtxt; ch_ret retcode; sh_int door, distance; bool drunk = FALSE; bool brief = FALSE; bool was_underwater = FALSE; if ( !IS_NPC( ch ) ) { if (IS_FIGHTING(ch)) { if (IS_AFFECTED(ch, AFF_BERSERK)) { send_to_char("Your bloodlust is too great!", ch); return rNONE; } } if ( IS_DRUNK( ch, 2 ) && ( ch->position != POS_SHOVE ) && ( ch->position != POS_DRAG ) ) drunk = TRUE; } if ( (drunk) && !fall ) { door = number_door(); pexit = get_exit( ch->in_room, door ); } #ifdef DEBUG if ( pexit ) { sprintf( buf, "move_char: %s to door %d", ch->name, pexit->vdir ); log_string( buf ); } #endif retcode = rNONE; txt = NULL; if ( IS_NPC(ch) && xIS_SET(ch->affected_by, AFF_MOUNTED) ) return retcode; in_room = ch->in_room; from_room = in_room; if ( !pexit || (to_room = pexit->to_room) == NULL ) { if ( drunk && ch->position != POS_MOUNTED && ch->in_room->sector_type != SECT_WATER_SWIM && ch->in_room->sector_type != SECT_WATER_NOSWIM && ch->in_room->sector_type != SECT_UNDERWATER && ch->in_room->sector_type != SECT_OCEANFLOOR ) { switch ( number_bits( 4 ) ) { default: act( AT_ACTION, "You drunkenly stumble into some obstacle.", ch, NULL, NULL, TO_CHAR ); act( AT_ACTION, "$n drunkenly stumbles into a nearby obstacle.", ch, NULL, NULL, TO_ROOM ); break; case 3: act( AT_ACTION, "In your drunken stupor you trip over your own feet and tumble to the ground.", ch, NULL, NULL, TO_CHAR ); act( AT_ACTION, "$n stumbles drunkenly, trips and tumbles to the ground.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_RESTING; break; case 4: act( AT_SOCIAL, "You utter a string of slurred obscenities.", ch, NULL, NULL, TO_CHAR) ; act( AT_ACTION, "Something blurry and immovable has intercepted you as you stagger along.", ch, NULL, NULL, TO_CHAR ); act( AT_HURT, "Oh geez... THAT really hurt. Everything slowly goes dark and numb...", ch, NULL, NULL, TO_CHAR ); act( AT_ACTION, "$n drunkenly staggers into something.", ch, NULL, NULL, TO_ROOM ); act( AT_SOCIAL, "$n utters a string of slurred obscenities: @@*&^%@@*&!", ch, NULL, NULL, TO_ROOM ); act( AT_ACTION, "$n topples to the ground with a thud.", ch, NULL, NULL, TO_ROOM ); lose_ep(ch, ch->move + 25); break; } } else if ( drunk ) act( AT_ACTION, "You stare around trying to make sense of things through your drunken stupor.", ch, NULL, NULL, TO_CHAR ); else send_to_char( "Alas, you cannot go that way.\n\r", ch ); return rNONE; } door = pexit->vdir; distance = pexit->distance; /* * Exit is only a "window", there is no way to travel in that direction * unless it's a door with a window in it -Thoric */ if ( IS_SET( pexit->exit_info, EX_WINDOW ) && !IS_SET( pexit->exit_info, EX_ISDOOR ) ) { send_to_char( "Alas, you cannot go that way.\n\r", ch ); return rNONE; } if ( IS_SET(pexit->exit_info, EX_PORTAL) && IS_NPC(ch) ) { act( AT_PLAIN, "Mobs can't use portals.", ch, NULL, NULL, TO_CHAR ); return rNONE; } if ( IS_SET(pexit->exit_info, EX_NOMOB) && IS_NPC(ch) ) { act( AT_PLAIN, "Mobs can't enter there.", ch, NULL, NULL, TO_CHAR ); return rNONE; } if ( IS_NPC(ch) && (IS_SET(pexit->to_room->room_flags, ROOM_NO_MOB) || IS_SET(pexit->to_room->runes, RUNE_DISTRACT) ) ) { act( AT_PLAIN, "Mobs can't go in there.", ch, NULL, NULL, TO_CHAR ); return rNONE; } if (IS_SET(pexit->to_room->room_flags, ROOM_NO_DREAM) && IS_AFFECTED(ch, AFF_DREAMWORLD) && ch->curr_talent[TAL_DREAM] < 100 ) { act( AT_MAGIC, "A mysterious shield prevents you from entering there.", ch, NULL, NULL, TO_CHAR); return rNONE; } if ( IS_SET(pexit->exit_info, EX_CLOSED) && (!IS_AFFECTED(ch, AFF_PASS_DOOR) || IS_SET(pexit->exit_info, EX_NOPASSDOOR)) ) { if ( !IS_SET( pexit->exit_info, EX_SECRET ) && !IS_SET( pexit->exit_info, EX_DIG ) ) { if ( drunk ) { act( AT_PLAIN, "$n runs into the $d in $s drunken state.", ch, NULL, pexit->keyword, TO_ROOM ); act( AT_PLAIN, "You run into the $d in your drunken state.", ch, NULL, pexit->keyword, TO_CHAR ); } else act( AT_PLAIN, "The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR ); } else { if ( drunk ) send_to_char( "You stagger around in your drunken state.\n\r", ch ); else send_to_char( "Alas, you cannot go that way.\n\r", ch ); } return rNONE; } if ( !fall && IS_AFFECTED(ch, AFF_CHARM) && ch->master && in_room == ch->master->in_room ) { send_to_char( "What? And leave your beloved master?\n\r", ch ); return rNONE; } if ( room_is_private( to_room ) && ( IS_NPC(ch) || !IS_SET(ch->pcdata->permissions, PERMIT_BUILD)) ) { send_to_char( "That room is private right now.\n\r", ch ); return rNONE; } if ( !fall ) { int move; if (ch->in_obj) { if (to_room->sector_type == SECT_INSIDE) { send_to_char("Your vehicle won't fit in there.\n\r", ch); return rNONE; } if (!IS_SET(ch->in_obj->value[2], VEHICLE_SPACE) && to_room->sector_type == SECT_DUNNO) { send_to_char("Your vehicle cannot clear the atmosphere.\n\r", ch); return rNONE; } if ((to_room->sector_type == SECT_UNDERWATER || to_room->sector_type == SECT_OCEANFLOOR) && !IS_SET(ch->in_obj->value[2], VEHICLE_UNDERWATER)) { send_to_char("Your vehicle is not a submersible.\n\r", ch); return rNONE; } if (!IS_SET(ch->in_obj->value[2], VEHICLE_AIR)) { if (to_room->sector_type == SECT_SWAMP) { send_to_char("Your vehicle would become stuck in the mires.\n\r", ch); return rNONE; } if ((to_room->sector_type == SECT_MOUNTAIN || to_room->sector_type == SECT_HILLS || to_room->sector_type == SECT_FOREST) && !IS_SET(ch->in_obj->value[2], VEHICLE_CLIMB)) { send_to_char("Your vehicle cannot handle that rough terrain.\n\r", ch); return rNONE; } else if ((to_room->sector_type == SECT_DESERT || to_room->sector_type == SECT_BEACH) && !IS_SET(ch->in_obj->value[2], VEHICLE_SAND)) { send_to_char("Your vehicle would founder in the sand.\n\r", ch); return rNONE; } else if ((to_room->sector_type == SECT_WATER_SWIM || to_room->sector_type == SECT_WATER_NOSWIM) && !IS_SET(ch->in_obj->value[2], VEHICLE_SURFACE)) { send_to_char("Your vehicle cannot float on water.\n\r", ch); return rNONE; } else if ((to_room->sector_type == SECT_ICE || IS_SET(to_room->room_flags, ROOM_SLIPPERY)) && !IS_SET(ch->in_obj->value[2], VEHICLE_ICE)) { send_to_char("Your vehicle would slip and spin out of control on the ice.\n\r", ch); return rNONE; } else if ((to_room->sector_type == SECT_CITY || to_room->sector_type == SECT_FIELD) && !IS_SET(ch->in_obj->value[2], VEHICLE_LAND)) { send_to_char("Your vehicle is not built to travel on land.\n\r", ch); return rNONE; } } if (to_room->sector_type == SECT_UNDERGROUND && !IS_SET(ch->in_obj->value[2], VEHICLE_UNDERGROUND)) { send_to_char("Your vehicle is not built for spelunking.\n\r", ch); return rNONE; } } if ( (in_room->sector_type == SECT_AIR || to_room->sector_type == SECT_AIR || IS_SET( pexit->exit_info, EX_FLY )) && pexit->vdir == 4) { if ( ch->in_obj && !IS_SET(ch->in_obj->value[2], VEHICLE_AIR)) { send_to_char("Your vehicle can't fly.\n\r", ch); return rNONE; } else if ( ch->mount && !IS_AFFECTED(ch, AFF_MOUNTED) && !IS_AFFECTED( ch->mount, AFF_FLYING ) ) { send_to_char( "Your mount can't fly.\n\r", ch ); return rNONE; } else if ( !ch->in_obj && !ch->mount && !IS_AFFECTED(ch, AFF_FLYING) ) { send_to_char( "You'd need to fly to go there.\n\r", ch ); return rNONE; } } if ( IS_SET( pexit->exit_info, EX_CLIMB ) ) { bool found; found = FALSE; if ( ch->in_obj && IS_SET(ch->in_obj->value[2], VEHICLE_CLIMB)) found = TRUE; else if ( ch->mount && !IS_AFFECTED(ch, AFF_MOUNTED) && IS_AFFECTED( ch->mount, AFF_FLYING ) ) found = TRUE; else if ( IS_AFFECTED(ch, AFF_FLYING) ) found = TRUE; if ( !found && ch->in_obj ) { send_to_char("Your vehicle cannot traverse that steep terrain.\n\r", ch); return rNONE; } if ( !found && !ch->mount ) { if ( ( !IS_NPC(ch) && number_percent( ) > LEARNED(ch, gsn_climb) ) || drunk || ch->mental_state < -90 ) { send_to_char( "You start to climb... but lose your grip and fall!\n\r", ch); learn_from_failure( ch, gsn_climb ); if ( pexit->vdir == DIR_DOWN ) { retcode = move_char( ch, pexit, 1 ); return retcode; } if (IS_UNDERWATER(ch)) { set_char_color(AT_BLUE, ch); send_to_char( "You splash into the water!\n\r", ch); return rNONE; } else if (IS_AFFECTED(ch, AFF_FLOATING)) { set_char_color( AT_MAGIC, ch); send_to_char( "You float lightly to the ground.\n\r", ch); return rNONE; } else { if (IS_AFFECTED(ch, AFF_MOUNTED)) throw_rider(ch); set_char_color( AT_HURT, ch ); send_to_char( "OUCH! You hit the ground!\n\r", ch ); lose_hp(ch, 5); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("stunned"); WAIT_STATE(ch, PULSE_VIOLENCE*2); if (ch->position > POS_RESTING) ch->position = POS_RESTING; } return retcode; } found = TRUE; learn_from_success( ch, gsn_climb ); txt = "climbs"; } if ( !found ) { send_to_char( "You can't climb.\n\r", ch ); return rNONE; } } if ( ch->mount ) { switch (ch->mount->position) { case POS_DEAD: send_to_char( "Your mount is dead!\n\r", ch ); return rNONE; break; case POS_MORTAL: case POS_INCAP: send_to_char( "Your mount is hurt far too badly to move.\n\r", ch ); return rNONE; break; case POS_STUNNED: send_to_char( "Your mount is too stunned to do that.\n\r", ch ); return rNONE; break; case POS_SLEEPING: send_to_char( "Your mount is sleeping.\n\r", ch ); return rNONE; break; case POS_RESTING: send_to_char( "Your mount is resting.\n\r", ch); return rNONE; break; case POS_SITTING: send_to_char( "Your mount is sitting down.\n\r", ch); return rNONE; break; default: break; } if ( !IS_FLOATING(ch->mount) ) move = movement_loss[UMIN(SECT_MAX-1, in_room->sector_type)]; else move = 1; if ( ch->mount->move < move ) { send_to_char( "Your mount is too exhausted.\n\r", ch ); return rNONE; } } else { if (!IS_AFFECTED(ch, AFF_FLYING) ) { move = encumbrance( ch, movement_loss[UMIN(SECT_MAX-1, in_room->sector_type)] ); if (IS_AFFECTED(ch, AFF_HASTE)) move=move/2; if (IS_AFFECTED(ch, AFF_SLOW)) move=move*2; } else move = 1; if (ch->in_obj) move = 0; if ( ch->move < move ) { send_to_char( "You are too exhausted.\n\r", ch ); return rNONE; } } STRFREE(ch->last_taken); if ( ch->mount ) { ch->last_taken = STRALLOC("riding"); ch->mount->move -= move; } else if (IS_UNDERWATER(ch)) { ch->last_taken = STRALLOC("swimming"); ch->move -= move; } else { ch->last_taken = STRALLOC("walking"); ch->move -= move; } WAIT_STATE(ch, move); } if (!ch->in_obj && (ch->in_room->sector_type == SECT_UNDERWATER || ch->in_room->sector_type == SECT_OCEANFLOOR )) if ((ch->position <= POS_STANDING) && (!fall)) { if (ch->in_obj) if (!IS_SET(ch->in_obj->value[2], VEHICLE_UNDERWATER)) { send_to_char("Your vehicle won't go anywhere.\n\r", ch); return rNONE; } if (!can_use_bodypart(ch, BP_RFIN) && !can_use_bodypart(ch, BP_LFIN) && !can_use_bodypart(ch, BP_DFIN) && (( number_percent( ) > (IS_NPC(ch) ? 100 : LEARNED(ch, gsn_swim ) + ch->curr_talent[TAL_WATER] + 10 )))) { act(AT_BLUE, "You splash about but are unable to get anywhere.", ch, NULL, NULL, TO_CHAR); act(AT_BLUE, "$n splashes about ineffectively in the water.", ch, NULL, NULL, TO_ROOM); learn_from_failure(ch, gsn_swim); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("splashing about"); WAIT_STATE(ch, PULSE_VIOLENCE); return rNONE; } else { learn_from_success(ch, gsn_swim); } } if (IS_AFFECTED(ch, AFF_HOLD)) { if (number_range(1, get_curr_str(ch)) < 30) { send_to_char("You are held in place!\n\r", ch); return rNONE; } else { send_to_char("You break free from the hold!\n\r", ch); act(AT_ACTION, "$n breaks free!\n\r", ch, NULL, NULL, TO_ROOM); if (IS_NPC(ch)) xREMOVE_BIT(ch->affected_by, AFF_HOLD); else xREMOVE_BIT(ch->pcdata->perm_aff, AFF_HOLD); } } if (IS_SET(ch->mood, MOOD_GUARD)) { send_to_char("You are guarding this room!\n\r", ch); send_to_char("If you want to abandon your post, type GUARD again.\n\r", ch); return rNONE; } if (ch->on != NULL) /* is char on floor ??? */ { send_to_char ("Make sure you are standing on the floor first.\n\r", ch); return rNONE; } /* slippery floor, chance of falling -keo */ if (IS_SET(ch->in_room->room_flags, ROOM_SLIPPERY) && !IS_AFFECTED(ch, AFF_FLYING) && !fall && !ch->in_obj) { if (number_range(1, 200) > get_curr_dex(ch) + ch->curr_talent[TAL_FROST]) { send_to_char("You slip and fall!\n\r", ch); act(AT_ACTION, "$n slips and falls!", ch, NULL, NULL, TO_ROOM); ch->position = POS_RESTING; lose_hp(ch, 5); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("sliding on the ice"); WAIT_STATE(ch, (200 - get_curr_dex(ch)) / 5); return rNONE; } else if (ch->curr_talent[TAL_FROST] < 30) { send_to_char("You almost slip, but manage to keep your balance.\n\r", ch); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("sliding on the ice"); WAIT_STATE(ch, (200 - get_curr_dex(ch)) / 10); } else { send_to_char("You skate along the ice.\n\r", ch); } } /* sticky floor, chance of sticking -keo */ if (IS_SET(ch->in_room->room_flags, ROOM_STICKY) && !IS_AFFECTED(ch, AFF_FLYING) && !fall) { if (number_range(1,200) > get_curr_str(ch)) { send_to_char("Your feet stick to the floor.\n\r", ch); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("stuck to the floor"); WAIT_STATE(ch, (200 - get_curr_str(ch)) / 5); return rNONE; } } /* check for guards -keo */ for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { if (gch->position > POS_KNEELING && IS_SET(ch->mood, MOOD_GUARD) && (gch != ch)) { if (IS_SAME_PLANE(ch, gch)) { if(IS_AFFECTED(ch, AFF_FLYING) && !IS_AFFECTED(gch, AFF_FLYING)) { act( AT_PLAIN, "$N tries to block you, but you fly right over $S head!", ch, NULL, gch, TO_CHAR); act( AT_PLAIN, "You try to block $n, but $e flies right over your head!", ch, NULL, gch, TO_VICT); } else { if (gch->weight > ch->weight) { act( AT_PLAIN, "$N blocks your exit.", ch, NULL, gch, TO_CHAR ); act( AT_PLAIN, "You block $n's exit.", ch, NULL, gch, TO_VICT ); return rNONE; } else { act( AT_PLAIN, "$N tries to block you but you bowl $M over!", ch, NULL, gch, TO_CHAR ); act( AT_PLAIN, "You try to block $n but $e bowls you over!", ch, NULL, gch, TO_VICT ); gch->position = POS_RESTING; STRFREE(gch->last_taken); gch->last_taken = STRALLOC("stunned"); WAIT_STATE(ch, PULSE_VIOLENCE); } } } } } /* Everything went through, move them! */ if (IS_AFFECTED(ch, AFF_MOUNTED)) throw_rider(ch); if (IS_UNDERWATER(ch)) was_underwater = TRUE; /* check for traps on exit - later */ if (IS_AFFECTED(ch, AFF_SNEAK)) learn_noncombat(ch, SK_STEALTH); if ( !IS_AFFECTED(ch, AFF_SNEAK) || (!IS_NPC(ch) && number_range(1,20) > number_range(1,ch->pcdata->noncombat[SK_STEALTH]))) { if ( fall ) if (IS_UNDERWATER(ch)) txt = "sinks"; else txt = "falls"; else if (IS_UNDERWATER(ch)) txt = "swims"; else if ( !txt ) { if (ch->in_obj && ch->in_obj->action_desc) { txt = ch->in_obj->action_desc; } else if ( ch->mount ) { if ( IS_AFFECTED( ch->mount, AFF_FLYING ) ) txt = "flies"; else txt = "rides"; } else { if ( IS_AFFECTED( ch, AFF_FLYING ) ) { if ( drunk ) txt = "flies shakily"; else txt = "flies"; } else if ( ch->position == POS_SHOVE ) txt = "reels"; else if ( ch->position == POS_DRAG ) txt = "is dragged"; else { if ( drunk ) txt = "stumbles drunkenly"; else txt = "leaves"; } } } if ( ch->mount ) { sprintf( buf, "$n %s %s upon $N.", txt, dir_name[door] ); act( AT_ACTION, buf, ch, NULL, ch->mount, TO_NOTVICT ); sprintf( buf, "$n %s %s upon your back.", txt, dir_name[door] ); act( AT_ACTION, buf, ch, NULL, ch->mount, TO_VICT ); } else { sprintf( buf, "$n %s $T.", txt ); act( AT_ACTION, buf, ch, NULL, dir_name[door], TO_ROOM ); } } /* Find the trail we made when we came in and tell it where we went -- Scion */ trail=ch->in_room->first_trail; while (trail) { /* Expire old trails */ if (trail->age-current_time+1800 < 0) { TRAIL_DATA *tmp_trail; tmp_trail=trail->next; UNLINK(trail, ch->in_room->first_trail, ch->in_room->last_trail, next, prev); STRFREE(trail->name); DISPOSE(trail); trail=tmp_trail; continue; } else { if (trail->name && !strcmp(ch->name, trail->name)) { trail->to=door; trail->race=ch->nation; if (ch->max_hit/2 > ch->hit) trail->blood=TRUE; else trail->blood=FALSE; if (IS_AFFECTED(ch, AFF_FLYING)) trail->fly=TRUE; else trail->fly=FALSE; } trail=trail->next; } } rprog_leave_trigger( ch ); if( char_died(ch) ) return global_retcode; /* Oh so useful to know this -- Scion */ ch->was_in_room=ch->in_room; if ( ch->mount ) { rprog_leave_trigger( ch->mount ); if (char_died(ch)) return global_retcode; if( ch->mount ) { char_from_room( ch->mount ); char_to_room( ch->mount, to_room ); do_look(ch->mount, "auto"); } } if (ch->in_obj) { CHAR_DATA *rch; obj_from_room(ch->in_obj); obj_to_room(ch->in_obj, to_room); for (rch = ch->in_room->first_person;rch;rch = rch->next_in_room) { if (rch != ch && rch->in_obj == ch->in_obj) { char_from_room(rch); char_to_room(rch, to_room); } } } char_from_room(ch); char_to_room( ch, to_room ); /* separately to make sure it displays right */ if (ch->in_obj) { CHAR_DATA *rch; for (rch = ch->in_room->first_person;rch;rch = rch->next) { if (rch != ch && rch->in_obj == ch->in_obj) { do_look(rch, "auto"); } } } explore_room(ch, to_room); if ( !IS_AFFECTED(ch, AFF_SNEAK) && ( IS_NPC(ch) || !xIS_SET(ch->act, PLR_WIZINVIS) ) ) { if ( fall ) { if (IS_UNDERWATER(ch)) { txt = "sinks"; } else { txt = "falls"; } } if (ch->in_obj && ch->in_obj->action_desc) { txt = ch->in_obj->action_desc; } else { if (IS_UNDERWATER(ch)) txt = "swims in"; else if ( ch->mount ) { if ( IS_AFFECTED( ch->mount, AFF_FLYING ) ) txt = "flies in"; else txt = "rides in"; } else { if ( IS_AFFECTED( ch, AFF_FLYING ) ) { if ( drunk ) txt = "flies in shakily"; else txt = "flies in"; } else if ( ch->position == POS_SHOVE ) txt = "is shoved in"; else if ( ch->position == POS_DRAG ) txt = "is dragged in"; else { if ( drunk ) txt = "stumbles drunkenly in"; else txt = "arrives"; } } } dtxt = rev_exit(door); if ( ch->mount ) { sprintf( buf, "$n %s from %s upon $N.", txt, dtxt ); act( AT_ACTION, buf, ch, NULL, ch->mount, TO_NOTVICT ); } else { sprintf( buf, "$n %s from %s.", txt, dtxt ); act( AT_ACTION, buf, ch, NULL, NULL, TO_ROOM ); } } /* Create a new trail in the room we moved to unless we already have one -- Scion */ trail=ch->in_room->first_trail; while (trail && trail->name && strcmp(trail->name, ch->name)) trail=trail->next; if (!trail) { CREATE(new_trail, TRAIL_DATA, 1); new_trail->blood=FALSE; new_trail->fly=FALSE; new_trail->race=NULL; new_trail->to=-1; new_trail->from=-1; new_trail->age=current_time; new_trail->name=NULL; LINK(new_trail, ch->in_room->first_trail, ch->in_room->last_trail, next, prev); trail=new_trail; new_trail->next=NULL; new_trail->prev=NULL; } if (trail->name) STRFREE(trail->name); trail->name=STRALLOC(ch->name); trail->race=ch->nation; trail->from=door; trail->to=-1; do_look( ch, "auto" ); if ( brief ) xSET_BIT(ch->act, PLR_BRIEF); if (IS_UNDERWATER(ch) && !was_underwater) { act(AT_PLAIN, "The water is too deep to walk any further, so you begin to swim.", ch, NULL, NULL, TO_CHAR); } else if (!IS_UNDERWATER(ch) && was_underwater) { act(AT_PLAIN, "You can touch the bottom here, so you no longer need to swim.", ch, NULL, NULL, TO_CHAR); } /* BIG ugly looping problem here when the character is mptransed back to the starting room. To avoid this, check how many chars are in the room at the start and stop processing followers after doing the right number of them. -- Narn */ if ( !fall ) { CHAR_DATA *fch; CHAR_DATA *nextinroom; int chars = 0, count = 0; for ( fch = from_room->first_person; fch; fch = fch->next_in_room ) chars++; for ( fch = from_room->first_person; fch && ( count < chars ); fch = nextinroom ) { nextinroom = fch->next_in_room; count++; if ( fch != ch /* loop room bug fix here by Thoric */ && fch->master == ch && fch->position >= POS_SQUATTING && can_see(fch, ch) ) { act( AT_ACTION, "You follow $N.", fch, NULL, ch, TO_CHAR ); act( AT_ACTION, "$n follows $N.", fch, NULL, ch, TO_NOTVICT); act( AT_ACTION, "$n follows you.", fch, NULL, ch, TO_VICT); char_from_room(fch); char_to_room(fch, to_room); act( AT_ACTION, "$n follows $N.", fch, NULL, ch, TO_NOTVICT); } } } if ( ch->in_room->first_content ) retcode = check_room_for_traps( ch, TRAP_ENTER_ROOM ); if ( retcode != rNONE ) return retcode; if ( char_died(ch) ) return retcode; mprog_entry_trigger( ch ); if ( char_died(ch) ) return retcode; rprog_enter_trigger( ch ); if ( char_died(ch) ) return retcode; mprog_greet_trigger( ch ); if ( char_died(ch) ) return retcode; oprog_greet_trigger( ch ); if ( char_died(ch) ) return retcode; if (IS_AFFECTED(ch, AFF_VOID) && number_range(1,25) > ch->curr_talent[TAL_VOID]) { travel_teleport(ch); if (number_range(1,10) == 10) { act(AT_MAGIC, "You are knocked out of the Void!", ch, NULL, NULL, TO_CHAR); act(AT_MAGIC, "$n is knocked into reality!", ch, NULL, NULL, TO_ROOM); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("seeing stars"); WAIT_STATE(ch, PULSE_VIOLENCE*3); if (IS_NPC(ch)) xREMOVE_BIT(ch->affected_by, AFF_VOID); else xREMOVE_BIT(ch->pcdata->perm_aff, AFF_VOID); } return retcode; } if (!will_fall( ch, fall ) && fall > 0 ) { if (IS_UNDERWATER(ch)) { set_char_color( AT_BLUE, ch); send_to_char(" SPLASH! You land in the water!\n\r", ch); } else if (!IS_AFFECTED( ch, AFF_FLOATING ) || (ch->mount && !IS_AFFECTED( ch->mount, AFF_FLOATING))) { set_char_color( AT_HURT, ch ); send_to_char( "OUCH! You hit the ground!\n\r", ch ); lose_hp(ch, 30 * fall); if (char_died(ch)) return retcode; } else { set_char_color( AT_MAGIC, ch ); send_to_char( "You lightly float down to the ground.\n\r", ch ); } } return retcode; } void do_north( CHAR_DATA *ch, char *argument ) { move_char( ch, get_exit(ch->in_room, DIR_NORTH), 0 ); return; } void do_east( CHAR_DATA *ch, char *argument ) { move_char( ch, get_exit(ch->in_room, DIR_EAST), 0 ); return; } void do_south( CHAR_DATA *ch, char *argument ) { move_char( ch, get_exit(ch->in_room, DIR_SOUTH), 0 ); return; } void do_west( CHAR_DATA *ch, char *argument ) { move_char( ch, get_exit(ch->in_room, DIR_WEST), 0 ); return; } void do_up( CHAR_DATA *ch, char *argument ) { move_char( ch, get_exit(ch->in_room, DIR_UP), 0 ); return; } void do_down( CHAR_DATA *ch, char *argument ) { move_char( ch, get_exit(ch->in_room, DIR_DOWN), 0 ); return; } void do_northeast( CHAR_DATA *ch, char *argument ) { move_char( ch, get_exit(ch->in_room, DIR_NORTHEAST), 0 ); return; } void do_northwest( CHAR_DATA *ch, char *argument ) { move_char( ch, get_exit(ch->in_room, DIR_NORTHWEST), 0 ); return; } void do_southeast( CHAR_DATA *ch, char *argument ) { move_char( ch, get_exit(ch->in_room, DIR_SOUTHEAST), 0 ); return; } void do_southwest( CHAR_DATA *ch, char *argument ) { move_char( ch, get_exit(ch->in_room, DIR_SOUTHWEST), 0 ); return; } EXIT_DATA *find_door( CHAR_DATA *ch, char *arg, bool quiet ) { EXIT_DATA *pexit; int door; if (arg == NULL || !str_cmp(arg,"")) return NULL; pexit = NULL; if ( !str_cmp( arg, "n" ) || !str_cmp( arg, "north" ) ) door = 0; else if ( !str_cmp( arg, "e" ) || !str_cmp( arg, "east" ) ) door = 1; else if ( !str_cmp( arg, "s" ) || !str_cmp( arg, "south" ) ) door = 2; else if ( !str_cmp( arg, "w" ) || !str_cmp( arg, "west" ) ) door = 3; else if ( !str_cmp( arg, "u" ) || !str_cmp( arg, "up" ) ) door = 4; else if ( !str_cmp( arg, "d" ) || !str_cmp( arg, "down" ) ) door = 5; else if ( !str_cmp( arg, "ne" ) || !str_cmp( arg, "northeast" ) ) door = 6; else if ( !str_cmp( arg, "nw" ) || !str_cmp( arg, "northwest" ) ) door = 7; else if ( !str_cmp( arg, "se" ) || !str_cmp( arg, "southeast" ) ) door = 8; else if ( !str_cmp( arg, "sw" ) || !str_cmp( arg, "southwest" ) ) door = 9; else { for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next ) { if ( (quiet || IS_SET(pexit->exit_info, EX_ISDOOR)) && pexit->keyword && nifty_is_name( arg, pexit->keyword ) ) return pexit; } if ( !quiet ) act( AT_PLAIN, "You see no $T here.", ch, NULL, arg, TO_CHAR ); return NULL; } if ( (pexit = get_exit( ch->in_room, door )) == NULL ) { if ( !quiet) act( AT_PLAIN, "You see no $T here.", ch, NULL, arg, TO_CHAR ); return NULL; } if ( quiet ) return pexit; if ( IS_SET(pexit->exit_info, EX_SECRET) ) { act( AT_PLAIN, "You see no $T here.", ch, NULL, arg, TO_CHAR ); return NULL; } if ( !IS_SET(pexit->exit_info, EX_ISDOOR) ) { send_to_char( "You can't do that.\n\r", ch ); return NULL; } return pexit; } void set_bexit_flag( EXIT_DATA *pexit, int flag ) { EXIT_DATA *pexit_rev; SET_BIT(pexit->exit_info, flag); if ( (pexit_rev = pexit->rexit) != NULL && pexit_rev != pexit ) SET_BIT( pexit_rev->exit_info, flag ); } void remove_bexit_flag( EXIT_DATA *pexit, int flag ) { EXIT_DATA *pexit_rev; REMOVE_BIT(pexit->exit_info, flag); if ( (pexit_rev = pexit->rexit) != NULL && pexit_rev != pexit ) REMOVE_BIT( pexit_rev->exit_info, flag ); } void toggle_bexit_flag( EXIT_DATA *pexit, int flag ) { EXIT_DATA *pexit_rev; TOGGLE_BIT(pexit->exit_info, flag); if ( (pexit_rev = pexit->rexit) != NULL && pexit_rev != pexit ) TOGGLE_BIT( pexit_rev->exit_info, flag ); } void do_open( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; EXIT_DATA *pexit; int door; one_argument( argument, arg ); if ( arg[0] == '\0' ) { send_to_char( "Open what?\n\r", ch ); return; } if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL ) { /* 'open door' */ EXIT_DATA *pexit_rev; if (get_curr_int(ch) <= 10) { send_to_char("You cannot figure out how to make it work.\r\n", ch); return; } if ( IS_SET(pexit->exit_info, EX_SECRET) && pexit->keyword && !nifty_is_name( arg, pexit->keyword ) ) { ch_printf( ch, "You see no %s here.\n\r", arg ); return; } if ( !IS_SET(pexit->exit_info, EX_ISDOOR) ) { send_to_char( "You can't do that.\n\r", ch ); return; } if ( !IS_SET(pexit->exit_info, EX_CLOSED) ) { send_to_char( "It's already open.\n\r", ch ); return; } if ( IS_SET(pexit->exit_info, EX_LOCKED) ) { send_to_char( "It's locked.\n\r", ch ); return; } if ( !IS_SET(pexit->exit_info, EX_SECRET) || (pexit->keyword && nifty_is_name( arg, pexit->keyword )) ) { act( AT_ACTION, "$n opens the $d.", ch, NULL, pexit->keyword, TO_ROOM ); act( AT_ACTION, "You open the $d.", ch, NULL, pexit->keyword, TO_CHAR ); if ( (pexit_rev = pexit->rexit) != NULL && pexit_rev->to_room == ch->in_room ) { CHAR_DATA *rch; for ( rch = pexit->to_room->first_person; rch; rch = rch->next_in_room ) act( AT_ACTION, "The $d opens.", rch, NULL, pexit_rev->keyword, TO_CHAR ); } remove_bexit_flag( pexit, EX_CLOSED ); if ( (door=pexit->vdir) >= 0 && door < 10 ) check_room_for_traps( ch, trap_door[door]); return; } } if ( ( obj = get_obj_here( ch, arg ) ) != NULL ) { /* 'open object' */ if ( obj->item_type != ITEM_CONTAINER ) { ch_printf( ch, "%s is not a container.\n\r", capitalize( obj->short_descr ) ); return; } if ( !IS_SET(obj->value[1], CONT_CLOSED) ) { ch_printf( ch, "%s is already open.\n\r", capitalize( obj->short_descr ) ); return; } if ( !IS_SET(obj->value[1], CONT_CLOSEABLE) ) { ch_printf( ch, "%s cannot be opened or closed.\n\r", capitalize( obj->short_descr ) ); return; } if ( IS_SET(obj->value[1], CONT_LOCKED) ) { ch_printf( ch, "%s is locked.\n\r", capitalize( obj->short_descr ) ); return; } REMOVE_BIT(obj->value[1], CONT_CLOSED); act( AT_ACTION, "You open $p.", ch, obj, NULL, TO_CHAR ); act( AT_ACTION, "$n opens $p.", ch, obj, NULL, TO_ROOM ); check_for_trap( ch, obj, TRAP_OPEN ); return; } ch_printf( ch, "You see no %s here.\n\r", arg ); return; } void do_close( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; EXIT_DATA *pexit; int door; one_argument( argument, arg ); if ( arg[0] == '\0' ) { send_to_char( "Close what?\n\r", ch ); return; } if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL ) { /* 'close door' */ EXIT_DATA *pexit_rev; if ( !IS_SET(pexit->exit_info, EX_ISDOOR) ) { send_to_char( "You can't do that.\n\r", ch ); return; } if ( IS_SET(pexit->exit_info, EX_CLOSED) ) { send_to_char( "It's already closed.\n\r", ch ); return; } act( AT_ACTION, "$n closes the $d.", ch, NULL, pexit->keyword, TO_ROOM ); act( AT_ACTION, "You close the $d.", ch, NULL, pexit->keyword, TO_CHAR ); /* close the other side */ if ( ( pexit_rev = pexit->rexit ) != NULL && pexit_rev->to_room == ch->in_room ) { CHAR_DATA *rch; SET_BIT( pexit_rev->exit_info, EX_CLOSED ); for ( rch = pexit->to_room->first_person; rch; rch = rch->next_in_room ) act( AT_ACTION, "The $d closes.", rch, NULL, pexit_rev->keyword, TO_CHAR ); } set_bexit_flag( pexit, EX_CLOSED ); if ( (door=pexit->vdir) >= 0 && door < 10 ) check_room_for_traps( ch, trap_door[door]); return; } if ( ( obj = get_obj_here( ch, arg ) ) != NULL ) { /* 'close object' */ if ( obj->item_type != ITEM_CONTAINER ) { ch_printf( ch, "%s is not a container.\n\r", capitalize( obj->short_descr ) ); return; } if ( IS_SET(obj->value[1], CONT_CLOSED) ) { ch_printf( ch, "%s is already closed.\n\r", capitalize( obj->short_descr ) ); return; } if ( !IS_SET(obj->value[1], CONT_CLOSEABLE) ) { ch_printf( ch, "%s cannot be opened or closed.\n\r", capitalize( obj->short_descr ) ); return; } SET_BIT(obj->value[1], CONT_CLOSED); act( AT_ACTION, "You close $p.", ch, obj, NULL, TO_CHAR ); act( AT_ACTION, "$n closes $p.", ch, obj, NULL, TO_ROOM ); check_for_trap( ch, obj, TRAP_CLOSE ); return; } ch_printf( ch, "You see no %s here.\n\r", arg ); return; } /* * Keyring support added by Thoric * Idea suggested by Onyx <MtRicmer@@worldnet.att.net> of Eldarion * * New: returns pointer to key/NULL instead of TRUE/FALSE * */ OBJ_DATA *has_key( CHAR_DATA *ch, int key ) { OBJ_DATA *obj, *obj2; for ( obj = ch->first_carrying; obj; obj = obj->next_content ) { if ( obj->item_type == ITEM_KEY && obj->value[0] == key ) return obj; else if ( obj->item_type == ITEM_KEYRING ) for ( obj2 = obj->first_content; obj2; obj2 = obj2->next_content ) if ( obj2->value[0] == key ) return obj2; } if (ch->curr_talent[TAL_VOID] + ch->curr_talent[TAL_SECURITY] >=95) { obj = create_object(get_obj_index(OBJ_VNUM_KEY), 0); obj->value[0] = key; obj->timer = 1; obj_to_char(obj, ch); STRFREE(obj->obj_by); obj->obj_by = STRALLOC(ch->name); act(AT_MAGIC, "You weave the correct key from ether.", ch, NULL, NULL, TO_CHAR); act(AT_MAGIC, "$n weaves a key from ether.", ch, NULL, NULL, TO_ROOM); return obj; } return NULL; } void do_lock( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj, *key; EXIT_DATA *pexit; int count; one_argument( argument, arg ); if ( arg[0] == '\0' ) { send_to_char( "Lock what?\n\r", ch ); return; } if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL ) { /* 'lock door' */ if ( !IS_SET(pexit->exit_info, EX_ISDOOR) ) { send_to_char( "You can't do that.\n\r", ch ); return; } if ( !IS_SET(pexit->exit_info, EX_CLOSED) ) { send_to_char( "It's not closed.\n\r", ch ); return; } if ( pexit->key < 0 ) { send_to_char( "It can't be locked.\n\r", ch ); return; } if ( (key=has_key(ch, pexit->key)) == NULL ) { send_to_char( "You lack the key.\n\r", ch ); return; } if ( IS_SET(pexit->exit_info, EX_LOCKED) ) { send_to_char( "It's already locked.\n\r", ch ); return; } if ( !IS_SET(pexit->exit_info, EX_SECRET) || (pexit->keyword && nifty_is_name( arg, pexit->keyword )) ) { send_to_char( "*Click*\n\r", ch ); count = key->count; key->count = 1; act( AT_ACTION, "$n locks the $d with $p.", ch, key, pexit->keyword, TO_ROOM ); key->count = count; set_bexit_flag( pexit, EX_LOCKED ); return; } } if ( ( obj = get_obj_here( ch, arg ) ) != NULL ) { /* 'lock object' */ if ( obj->item_type != ITEM_CONTAINER ) { send_to_char( "That's not a container.\n\r", ch ); return; } if ( !IS_SET(obj->value[1], CONT_CLOSED) ) { send_to_char( "It's not closed.\n\r", ch ); return; } if ( obj->value[2] < 0 ) { send_to_char( "It can't be locked.\n\r", ch ); return; } if ( (key=has_key(ch, obj->value[2])) == NULL ) { send_to_char( "You lack the key.\n\r", ch ); return; } if ( IS_SET(obj->value[1], CONT_LOCKED) ) { send_to_char( "It's already locked.\n\r", ch ); return; } SET_BIT(obj->value[1], CONT_LOCKED); send_to_char( "*Click*\n\r", ch ); count = key->count; key->count = 1; act( AT_ACTION, "$n locks $p with $P.", ch, obj, key, TO_ROOM ); key->count = count; return; } ch_printf( ch, "You see no %s here.\n\r", arg ); return; } void do_unlock( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj, *key; EXIT_DATA *pexit; int count; one_argument( argument, arg ); if ( arg[0] == '\0' ) { send_to_char( "Unlock what?\n\r", ch ); return; } if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL ) { /* 'unlock door' */ if ( !IS_SET(pexit->exit_info, EX_ISDOOR) ) { send_to_char( "You can't do that.\n\r", ch ); return; } if ( !IS_SET(pexit->exit_info, EX_CLOSED) ) { send_to_char( "It's not closed.\n\r", ch ); return; } if ( pexit->key < 0 ) { send_to_char( "It can't be unlocked.\n\r", ch ); return; } if ( (key=has_key(ch, pexit->key)) == NULL ) { send_to_char( "You lack the key.\n\r", ch ); return; } if ( !IS_SET(pexit->exit_info, EX_LOCKED) ) { send_to_char( "It's already unlocked.\n\r", ch ); return; } if ( !IS_SET(pexit->exit_info, EX_SECRET) || (pexit->keyword && nifty_is_name( arg, pexit->keyword )) ) { send_to_char( "*Click*\n\r", ch ); count = key->count; key->count = 1; act( AT_ACTION, "$n unlocks the $d with $p.", ch, key, pexit->keyword, TO_ROOM ); key->count = count; if ( IS_SET(pexit->exit_info, EX_EATKEY) ) { separate_obj(key); extract_obj(key); } remove_bexit_flag( pexit, EX_LOCKED ); return; } } if ( ( obj = get_obj_here( ch, arg ) ) != NULL ) { /* 'unlock object' */ if ( obj->item_type != ITEM_CONTAINER ) { send_to_char( "That's not a container.\n\r", ch ); return; } if ( !IS_SET(obj->value[1], CONT_CLOSED) ) { send_to_char( "It's not closed.\n\r", ch ); return; } if ( obj->value[2] < 0 ) { send_to_char( "It can't be unlocked.\n\r", ch ); return; } if ( (key=has_key(ch, obj->value[2])) == NULL ) { send_to_char( "You lack the key.\n\r", ch ); return; } if ( !IS_SET(obj->value[1], CONT_LOCKED) ) { send_to_char( "It's already unlocked.\n\r", ch ); return; } REMOVE_BIT(obj->value[1], CONT_LOCKED); send_to_char( "*Click*\n\r", ch ); count = key->count; key->count = 1; act( AT_ACTION, "$n unlocks $p with $P.", ch, obj, key, TO_ROOM ); key->count = count; if ( IS_SET(obj->value[1], CONT_EATKEY) ) { separate_obj(key); extract_obj(key); } return; } ch_printf( ch, "You see no %s here.\n\r", arg ); return; } void do_bashdoor( CHAR_DATA *ch, char *argument ) { CHAR_DATA *gch; EXIT_DATA *pexit; ROOM_INDEX_DATA *to_room; EXIT_DATA *pexit_rev; char arg [ MAX_INPUT_LENGTH ]; if ( !IS_NPC( ch ) && LEARNED(ch, gsn_bashdoor) < 1) { send_to_char( "You're not burly enough to bash doors!\n\r", ch ); return; } one_argument( argument, arg ); if ( arg[0] == '\0' ) { send_to_char( "Bash what?\n\r", ch ); return; } if ( ( pexit = find_door( ch, arg, FALSE ) ) != NULL ) { int chance; char *keyword; if ( !IS_SET( pexit->exit_info, EX_CLOSED ) ) { send_to_char( "Calm down. It is already open.\n\r", ch ); return; } if ( IS_SET( pexit->exit_info, EX_SECRET ) ) keyword = "wall"; else keyword = pexit->keyword; if ( !IS_NPC(ch) ) chance = LEARNED(ch, gsn_bashdoor) / 2; else chance = 90; if ( IS_SET( pexit->exit_info, EX_LOCKED ) ) chance /= 3; if ( !IS_SET( pexit->exit_info, EX_BASHPROOF ) && ch->move >= 15 && number_percent( ) < ( chance + get_curr_str( ch ) )) { REMOVE_BIT( pexit->exit_info, EX_CLOSED ); if ( IS_SET( pexit->exit_info, EX_LOCKED ) ) { REMOVE_BIT( pexit->exit_info, EX_LOCKED ); pexit->key = -1; fold_area(ch->in_room->area, ch->in_room->area->filename, FALSE); } if (can_use_bodypart(ch, BP_RHOOF) || can_use_bodypart(ch, BP_LHOOF)) { act(AT_SKILL, "Crash! You kicked open the $d!", ch, NULL, keyword, TO_CHAR); act(AT_SKILL, "$n kicks open the $d!", ch, NULL, keyword, TO_ROOM); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("kicking open the door"); WAIT_STATE(ch, PULSE_VIOLENCE); } else { act(AT_SKILL, "Crash! You bashed open the $d!", ch, NULL, keyword, TO_CHAR ); act(AT_SKILL, "$n bashes open the $d!", ch, NULL, keyword, TO_ROOM ); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("bashing down the door"); WAIT_STATE(ch, PULSE_VIOLENCE*2); lose_hp(ch, 10); } learn_from_success(ch, gsn_bashdoor); if ( (to_room = pexit->to_room) != NULL && (pexit_rev = pexit->rexit) != NULL && pexit_rev->to_room == ch->in_room ) { CHAR_DATA *rch; REMOVE_BIT( pexit_rev->exit_info, EX_CLOSED ); if ( IS_SET( pexit_rev->exit_info, EX_LOCKED ) ) { REMOVE_BIT( pexit_rev->exit_info, EX_LOCKED ); pexit_rev->key = -1; } SET_BIT( pexit_rev->exit_info, EX_BASHED ); for ( rch = to_room->first_person; rch; rch = rch->next_in_room ) { act(AT_SKILL, "The $d crashes open!", rch, NULL, pexit_rev->keyword, TO_CHAR ); } } } else { if (can_use_bodypart(ch, BP_RHOOF) || can_use_bodypart(ch, BP_LHOOF)) { act(AT_SKILL, "WHAAAAM!!! You kick the $d with your hooves, but it doesn't budge.", ch, NULL, keyword, TO_CHAR ); act(AT_SKILL, "WHAAAAM!!! $n kicks the $d, but it holds firm.", ch, NULL, keyword, TO_ROOM ); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("kicking the door"); WAIT_STATE(ch, PULSE_VIOLENCE*2); } else { act(AT_SKILL, "WHAAAAM!!! You bash against the $d, but it doesn't budge.", ch, NULL, keyword, TO_CHAR ); act(AT_SKILL, "WHAAAAM!!! $n bashes against the $d, but it holds strong.", ch, NULL, keyword, TO_ROOM ); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("bashing into the door"); WAIT_STATE(ch, PULSE_VIOLENCE*4); lose_hp(ch, 10); } learn_from_failure(ch, gsn_bashdoor); /* Should be able to hear bashing from the other side -- Scion */ if ( pexit != NULL && (to_room = pexit->to_room) != NULL && (pexit_rev = pexit->rexit) != NULL && pexit_rev->to_room == ch->in_room ) { CHAR_DATA *rch; char message[MAX_STRING_LENGTH]; sprintf(message, "You hear a loud thump against the door to the %s.", dir_name[pexit_rev->vdir]); for ( rch = to_room->first_person; rch; rch = rch->next_in_room ) { act(AT_SKILL, message, rch, NULL, pexit_rev->keyword, TO_CHAR ); } } } } else { act(AT_SKILL, "WHAAAAM!!! You bash against the wall, but it doesn't budge.", ch, NULL, NULL, TO_CHAR ); act(AT_SKILL, "WHAAAAM!!! $n bashes against the wall, but it holds strong.", ch, NULL, NULL, TO_ROOM ); lose_hp(ch, 10); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("bashing into the wall"); WAIT_STATE(ch, PULSE_VIOLENCE*4); learn_from_failure(ch, gsn_bashdoor); /* Should be able to hear bashing from the other side -- Scion */ if ( pexit != NULL && (to_room = pexit->to_room) != NULL && (pexit_rev = pexit->rexit) != NULL && pexit_rev->to_room == ch->in_room ) { CHAR_DATA *rch; char message[MAX_STRING_LENGTH]; sprintf(message, "You hear a loud thump against the door to the %s.", dir_name[pexit_rev->vdir]); for ( rch = to_room->first_person; rch; rch = rch->next_in_room ) { act(AT_SKILL, message, rch, NULL, pexit_rev->keyword, TO_CHAR ); } } } if ( !char_died( ch ) ) for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { if ( IS_AWAKE( gch ) && ( IS_NPC( gch ) && !IS_AFFECTED( gch, AFF_CHARM ) ) && (xIS_SET(ch->act, ACT_AGGRESSIVE) || xIS_SET(ch->act, ACT_META_AGGR))) multi_hit( gch, ch, TYPE_UNDEFINED ); } return; } void do_stand( CHAR_DATA *ch, char *argument ) { OBJ_DATA *obj = NULL; /* Object manipulation, Maniac */ char arg[MAX_INPUT_LENGTH]; /* Get the word */ char buf[MAX_STRING_LENGTH]; /* Some text buffer */ int type = FURNITURE_UNUSED;/* On, at or in */ char type_word[5]; /* on, in, or at */ AFFECT_DATA *paf; int defon=0; type_word[0] = '\0'; buf[0] = '\0'; defon=0; defon=0; if (argument[0] != '\0') { /* Stand up, stand on/in/at object ??? */ argument = one_argument(argument, arg); if (!str_cmp(arg, "up" )) { ch->fur_pos = FURNITURE_UNUSED; send_to_char( "You stand up.\n\r", ch ); act( AT_ACTION,"$n stands up.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_STANDING; if (ch->on) { for ( paf = ch->on->pIndexData->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, FALSE ); for ( paf = ch->on->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, FALSE ); ch->on = NULL; } return; } if (!str_cmp(arg, "on" )) { type = ST_ON; strcat (type_word, "on"); } else if (!str_cmp(arg, "in" )) { type = ST_IN; strcat (type_word, "in"); } else if (!str_cmp(arg, "at" )) { type = ST_AT; strcat (type_word, "at"); } else { type = ST_ON; strcat (type_word, "on"); defon=1; } if (type > FURNITURE_NONE && !defon) argument = one_argument(argument, arg ); /* Get object */ obj = get_obj_list(ch, arg,ch->in_room->first_content); if (!obj) { send_to_char ("You don't see that here.\n\r", ch ); return; } if (obj->item_type != ITEM_FURNITURE ) { send_to_char ("You can't stand on that.\n\r", ch ); return; } if (((type == ST_ON) && (!IS_SET(obj->value[2], STAND_ON))) || ((type == ST_AT) && (!IS_SET(obj->value[2], STAND_AT))) || ((type == ST_IN) && (!IS_SET(obj->value[2], STAND_IN))) || ((ch->on != obj) && (count_users(obj) >= obj->value[0]))) { sprintf (buf, "There is no place to stand %s %s.\n\r", type_word, obj->short_descr); send_to_char (buf, ch ); return; } ch->on=obj; ch->fur_pos=type; sprintf (buf, "You stand %s $p.", type_word ); act (AT_ACTION,buf, ch, obj, NULL,TO_CHAR ); sprintf (buf, "$n stands %s $p.", type_word ); act (AT_ACTION,buf, ch, obj, NULL, TO_ROOM ); for ( paf = ch->on->pIndexData->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); for ( paf = ch->on->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); return; } switch ( ch->position ) { case POS_SLEEPING: if ( IS_AFFECTED(ch, AFF_SLEEP) || IS_AFFECTED(ch, AFF_DREAMWORLD) ) { send_to_char( "You can't seem to wake up!\n\r", ch ); return; } if (IS_SET(ch->in_room->room_flags, ROOM_STICKY)) { send_to_char("You wake, but your back is stuck to the floor.\n\r",ch); act(AT_ACTION, "$n wakes up, but can't get up.", ch, NULL, NULL, TO_ROOM); ch->position = POS_RESTING; break; } send_to_char( "You wake and climb quickly to your feet.\n\r", ch ); act( AT_ACTION, "$n arises from $s slumber.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_STANDING; break; case POS_RESTING: if (IS_AFFECTED(ch, AFF_HOLD)) { send_to_char("You've fallen and you can't get up.\n\r", ch); return; } if (IS_SET(ch->in_room->room_flags, ROOM_STICKY)) { if (number_range(1,100) > get_curr_str(ch)) { send_to_char("Your back is stuck to the floor.\n\r",ch); return; } else { send_to_char("You pry your back off the floor.\n\r",ch); } } send_to_char( "You gather yourself and stand up.\n\r", ch ); act( AT_ACTION, "$n rises from $s rest.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_STANDING; break; case POS_KNEELING: if (IS_SET(ch->in_room->room_flags, ROOM_STICKY)) { if (number_range(1,100) > get_curr_str(ch)) { send_to_char("Your knees are stuck to the floor.\n\r",ch); return; } else { send_to_char("You pry your knees off the floor.\n\r",ch); } } send_to_char( "You get off your knees and stand.\n\r", ch); act(AT_ACTION, "$n clambers to $s feet.", ch, NULL, NULL, TO_ROOM); ch->position = POS_STANDING; break; case POS_SITTING: if (IS_SET(ch->in_room->room_flags, ROOM_STICKY)) { if (number_range(1,100) > get_curr_str(ch)) { send_to_char("Your ass is stuck to the floor.\n\r",ch); return; } else { send_to_char("You pry your ass off the floor.\n\r",ch); } } send_to_char( "You move quickly to your feet.\n\r", ch ); act( AT_ACTION, "$n rises up.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_STANDING; break; case POS_SQUATTING: send_to_char( "You stand up straight.\n\r", ch ); act( AT_ACTION, "$n stands up straight.", ch, NULL, NULL, TO_ROOM); ch->position = POS_STANDING; break; case POS_STANDING: if(!ch->on) send_to_char( "You are already standing.\n\r", ch ); break; } if(ch->on) { ch->position = POS_STANDING; for ( paf = ch->on->pIndexData->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, FALSE ); for ( paf = ch->on->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, FALSE ); ch->on = NULL; ch->fur_pos = FURNITURE_UNUSED; } return; } void do_sit( CHAR_DATA *ch, char *argument ) { OBJ_DATA *obj = NULL; /* Object manipulation, Maniac */ char arg[MAX_INPUT_LENGTH]; /* Get the word */ char buf[MAX_STRING_LENGTH]; /* Some text buffer */ int type = FURNITURE_UNUSED;/* On, at or in */ char type_word[5]; /* on, in, or at */ AFFECT_DATA *paf; int defon=0; type_word[0] = '\0'; buf[0] = '\0'; defon=0; switch ( ch->position ) { case POS_SLEEPING: if ( IS_AFFECTED(ch, AFF_SLEEP) ) { send_to_char( "You can't seem to wake up!\n\r", ch ); return; } send_to_char( "You wake and sit up.\n\r", ch ); act( AT_ACTION, "$n wakes and sits up.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_SITTING; break; case POS_RESTING: send_to_char( "You stop resting and sit up.\n\r", ch ); act( AT_ACTION, "$n stops resting and sits up.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_SITTING; break; case POS_SQUATTING: case POS_KNEELING: send_to_char( "You cross your legs and sit.\n\r", ch); act(AT_ACTION, "$n crosses $s legs and sits.", ch, NULL, NULL, TO_ROOM); ch->position = POS_SITTING; break; case POS_STANDING: /* Stand up, stand on/in/at object ??? */ argument = one_argument(argument, arg); if(arg[0]) { if (!str_cmp(arg, "on" )) { type = SI_ON; strcat (type_word, "on"); } else if(!str_cmp(arg, "in" )) { type = SI_IN; strcat (type_word, "in"); } else if (!str_cmp(arg, "at" )) { type = SI_AT; strcat (type_word, "at"); } else { type = SI_ON; strcat (type_word, "on"); defon=1; } if (type > FURNITURE_NONE && !defon) argument = one_argument(argument, arg ); /* Get object */ obj = get_obj_list(ch, arg,ch->in_room->first_content); if (!obj) { send_to_char ("You don't see that here.\n\r", ch ); return; } if (obj->item_type != ITEM_FURNITURE ) { send_to_char ("You can't sit on that.\n\r", ch ); return; } if (((type == SI_ON) && (!IS_SET(obj->value[2], SIT_ON))) || ((type == SI_AT) && (!IS_SET(obj->value[2], SIT_AT))) || ((type == SI_IN) && (!IS_SET(obj->value[2], SIT_IN))) || ((ch->on != obj) && (count_users(obj) >= obj->value[0]))) { sprintf (buf, "There is no place to sit %s %s.\n\r", type_word, obj->short_descr); send_to_char (buf, ch ); return; } ch->position = POS_SITTING; /* Heavy characters ought to break furniture! -- Scion :P */ if (!xIS_SET(obj->extra_flags, ITEM_MAGIC) && ch->weight >= ((obj->value[0] * 300) + number_range(-30, 30))) { act( AT_ACTION, "$p breaks under your weight!", ch, obj, NULL, TO_CHAR ); act( AT_ACTION, "$p breaks under $n's weight!", ch, obj, NULL, TO_ROOM ); make_scraps( obj ); ch->position = POS_RESTING; break; } else { ch->on = obj; ch->fur_pos = type; /* By Standing on object... get affects -- Maniac -- */ for ( paf = ch->on->pIndexData->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); for ( paf = ch->on->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); sprintf (buf, "You sit %s $p.", type_word ); act (AT_ACTION,buf, ch, obj, NULL,TO_CHAR ); sprintf (buf, "$n sits %s $p.", type_word ); act (AT_ACTION,buf, ch, obj, NULL, TO_ROOM ); break; } } ch->position = POS_SITTING; send_to_char( "You sit down.\n\r", ch ); act( AT_ACTION, "$n sits down.", ch, NULL, NULL, TO_ROOM ); break; case POS_SITTING: send_to_char( "You are already sitting.\n\r", ch ); return; case POS_MOUNTED: send_to_char( "You are already sitting - on your mount.\n\r", ch ); return; } return; } /* will need to add more furniture flags if we want people to be * able to kneel on stuff -keo */ void do_kneel( CHAR_DATA *ch, char *argument ) { switch ( ch->position ) { case POS_SLEEPING: if ( IS_AFFECTED(ch, AFF_SLEEP) ) { send_to_char( "You can't seem to wake up!\n\r", ch ); return; } send_to_char( "You wake and climb to your knees.\n\r", ch ); act( AT_ACTION, "$n wakes and climbs to $s knees.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_KNEELING; break; case POS_RESTING: case POS_SITTING: send_to_char("You climb to your knees.\n\r", ch); act(AT_ACTION, "$n climbs to $s knees.", ch, NULL, NULL, TO_ROOM); ch->position = POS_KNEELING; break; case POS_SQUATTING: case POS_STANDING: send_to_char("You drop to your knees.\n\r", ch); act(AT_ACTION, "$n drops to $s knees.", ch, NULL, NULL, TO_ROOM); ch->position = POS_KNEELING; break; case POS_MOUNTED: send_to_char("I don't think your mount would like that.\n\r", ch); case POS_KNEELING: send_to_char("You are already kneeling.\n\r", ch); } } /* will need to add more furniture flags if we want people to be * able to squat on stuff -keo */ void do_squat( CHAR_DATA *ch, char *argument ) { switch ( ch->position ) { case POS_SLEEPING: if ( IS_AFFECTED(ch, AFF_SLEEP) ) { send_to_char( "You can't seem to wake up!\n\r", ch ); return; } send_to_char( "You wake and crouch.\n\r", ch ); act( AT_ACTION, "$n wakes and crouches.", ch, NULL, NULL, TO_ROOM); ch->position = POS_SQUATTING; break; case POS_RESTING: case POS_SITTING: case POS_KNEELING: send_to_char("You move into a crouch.\n\r", ch); act(AT_ACTION, "$n moves into a crouch.", ch, NULL, NULL, TO_ROOM); ch->position = POS_SQUATTING; break; case POS_STANDING: send_to_char("You crouch down.\n\r", ch); act(AT_ACTION, "$n crouches down.", ch, NULL, NULL, TO_ROOM); ch->position = POS_SQUATTING; break; case POS_MOUNTED: send_to_char("I don't think your mount would like that.\n\r", ch); case POS_SQUATTING: send_to_char("You are already crouching.\n\r", ch); } } void do_rest( CHAR_DATA *ch, char *argument ) { OBJ_DATA *obj = NULL; /* Object manipulation, Maniac */ char arg[MAX_INPUT_LENGTH]; /* Get the word */ char buf[MAX_STRING_LENGTH]; /* Some text buffer */ int type = FURNITURE_UNUSED;/* On, at or in */ char type_word[5]; /* on, in, or at */ AFFECT_DATA *paf; int defon=0; type_word[0] = '\0'; buf[0] = '\0'; defon=0; switch ( ch->position ) { case POS_SLEEPING: if ( IS_AFFECTED(ch, AFF_SLEEP) ) { send_to_char( "You can't seem to wake up!\n\r", ch ); return; } send_to_char( "You rouse from your slumber.\n\r", ch ); act( AT_ACTION, "$n rouses from $s slumber.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_RESTING; break; case POS_SQUATTING: case POS_KNEELING: send_to_char( "You lie down and rest.\n\r", ch); act(AT_ACTION, "$n lies down and rests.\n\r", ch, NULL, NULL, TO_ROOM); ch->position = POS_RESTING; break; case POS_RESTING: send_to_char( "You are already resting.\n\r", ch ); return; case POS_STANDING: argument = one_argument(argument, arg ); /* Get object */ if(arg[0]) { if (!str_cmp(arg, "on" )) { type = RE_ON; strcat (type_word, "on"); } else if (!str_cmp(arg, "in" )) { type = RE_IN; strcat (type_word, "in"); } else if (!str_cmp(arg, "at" )) { type = RE_AT; strcat (type_word, "at"); } else { defon=1; type = RE_ON; strcat (type_word, "on"); } if (type > FURNITURE_NONE && !defon) argument = one_argument(argument, arg ); /* Get object */ obj = get_obj_list(ch, arg,ch->in_room->first_content); if (!obj) { send_to_char ("You don't see that here.\n\r", ch ); return; } if (obj->item_type != ITEM_FURNITURE ) { send_to_char ("You can't rest on that.\n\r", ch ); return; } if (((type == RE_ON) && (!IS_SET(obj->value[2], REST_ON))) || ((type == RE_AT) && (!IS_SET(obj->value[2], REST_AT))) || ((type == RE_IN) && (!IS_SET(obj->value[2], REST_IN))) || ((ch->on != obj) && (count_users(obj) >= obj->value[0]))) { sprintf (buf, "There is no place to rest %s %s.\n\r", type_word, obj->short_descr); send_to_char (buf, ch ); return; } /* Heavy characters ought to break furniture! -- Scion :P */ if (!xIS_SET(obj->extra_flags, ITEM_MAGIC) && ch->weight >= ((obj->value[0] * 300) + number_range(-30, 30))) { act( AT_ACTION, "$p breaks under your weight!", ch, obj, NULL, TO_CHAR ); act( AT_ACTION, "$p breaks under $n's weight!", ch, obj, NULL, TO_ROOM ); make_scraps( obj ); ch->position = POS_RESTING; break; } else { ch->position = POS_RESTING; ch->on = obj; ch->fur_pos = type; /* By Standing on object... get affects -- Maniac -- */ for ( paf = ch->on->pIndexData->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); for ( paf = ch->on->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); sprintf (buf, "You rest %s $p.", type_word ); act (AT_ACTION,buf, ch, obj, NULL,TO_CHAR ); sprintf (buf, "$n rests %s $p.", type_word ); act (AT_ACTION,buf, ch, obj, NULL, TO_ROOM ); break; } } ch->position = POS_RESTING; send_to_char( "You sprawl out haphazardly.\n\r", ch ); act( AT_ACTION, "$n sprawls out haphazardly.", ch, NULL, NULL, TO_ROOM ); break; case POS_SITTING: send_to_char( "You lie back and sprawl out to rest.\n\r", ch ); act( AT_ACTION, "$n lies back and sprawls out to rest.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_RESTING; break; case POS_MOUNTED: send_to_char( "You'd better dismount first.\n\r", ch ); return; } rprog_rest_trigger( ch ); return; } void do_sleep( CHAR_DATA *ch, char *argument ) { OBJ_DATA *obj = NULL; /* Object manipulation, Maniac */ char arg[MAX_INPUT_LENGTH]; /* Get the word */ char buf[MAX_STRING_LENGTH]; /* Some text buffer */ int type = FURNITURE_UNUSED;/* On, at or in */ char type_word[5]; /* on, in, or at */ AFFECT_DATA *paf; int defon=0; type_word[0] = '\0'; buf[0] = '\0'; defon=0; if (IS_AFFECTED(ch, AFF_DREAMWORLD)) do_wake(ch, ""); if (IS_SET(ch->mood, MOOD_READY)) do_relax(ch, ""); if (ch->singing) do_sing(ch, "none"); switch ( ch->position ) { case POS_SLEEPING: send_to_char( "You are already sleeping.\n\r", ch ); return; case POS_RESTING: if ( ch->mental_state > 30 && (number_percent()+10) < ch->mental_state ) { send_to_char( "You just can't seem to calm yourself down enough to sleep.\n\r", ch ); act( AT_ACTION, "$n closes $s eyes for a few moments, but just can't seem to go to sleep.", ch, NULL, NULL, TO_ROOM ); return; } send_to_char( "You close your eyes and drift into slumber.\n\r", ch ); act( AT_ACTION, "$n closes $s eyes and drifts into a deep slumber.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_SLEEPING; break; case POS_SITTING: case POS_KNEELING: case POS_SQUATTING: if ( ch->mental_state > 30 && (number_percent()+5) < ch->mental_state ) { send_to_char( "You just can't seem to calm yourself down enough to sleep.\n\r", ch ); act( AT_ACTION, "$n closes $s eyes for a few moments, but just can't seem to go to sleep.", ch, NULL, NULL, TO_ROOM ); return; } send_to_char( "You slump over and fall dead asleep.\n\r", ch ); act( AT_ACTION, "$n nods off and slowly slumps over, dead asleep.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_SLEEPING; break; case POS_STANDING: if ( ch->mental_state > 30 && number_percent() < ch->mental_state ) { send_to_char( "You just can't seem to calm yourself down enough to sleep.\n\r", ch ); act( AT_ACTION, "$n closes $s eyes for a few moments, but just can't seem to go to sleep.", ch, NULL, NULL, TO_ROOM ); return; } /* sleep on/in/at object ??? */ argument = one_argument(argument, arg); if(arg[0]) { if (!str_cmp(arg, "on" )) { type = SL_ON; strcat (type_word, "on"); } else if (!str_cmp(arg, "in" )) { type = SL_IN; strcat (type_word, "in"); } else if (!str_cmp(arg, "at" )) { type = SL_AT; strcat (type_word, "at"); } else { type = SL_ON; strcat (type_word, "on"); defon=1; } if (type > FURNITURE_NONE && !defon) argument = one_argument(argument, arg ); /* Get object */ obj = get_obj_list(ch, arg,ch->in_room->first_content); if (!obj) { send_to_char ("You don't see that here.\n\r", ch ); return; } if (obj->item_type != ITEM_FURNITURE ) { send_to_char ("You can't sleep on that.\n\r", ch ); return; } if (((type == SL_ON) && (!IS_SET(obj->value[2], SLEEP_ON))) || ((type == SL_AT) && (!IS_SET(obj->value[2], SLEEP_AT))) || ((type == SL_IN) && (!IS_SET(obj->value[2], SLEEP_IN))) || ((ch->on != obj) && (count_users(obj) >= obj->value[0]))) { sprintf (buf, "There is no place to sleep %s %s.\n\r", type_word, obj->short_descr); send_to_char (buf, ch ); return; } /* Heavy characters ought to break furniture! -- Scion :P */ if (!xIS_SET(obj->extra_flags, ITEM_MAGIC) && ch->weight >= ((obj->value[0] * 300) + number_range(-30, 30))) { act( AT_ACTION, "$p breaks under your weight!", ch, obj, NULL, TO_CHAR ); act( AT_ACTION, "$p breaks under $n's weight!", ch, obj, NULL, TO_ROOM ); make_scraps( obj ); ch->position = POS_RESTING; break; } else { ch->on = obj; ch->fur_pos = type; /* By Standing on object... get affects -- Maniac -- */ for ( paf = ch->on->pIndexData->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); for ( paf = ch->on->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); sprintf (buf, "You sleep %s $p.", type_word ); act (AT_ACTION,buf, ch, obj, NULL,TO_CHAR ); sprintf (buf, "$n sleeps %s $p.", type_word ); act (AT_ACTION,buf, ch, obj, NULL, TO_ROOM ); ch->position = POS_SLEEPING; break; } } send_to_char( "You collapse into a deep sleep.\n\r", ch ); act( AT_ACTION, "$n collapses into a deep sleep.", ch, NULL, NULL, TO_ROOM ); ch->position = POS_SLEEPING; break; case POS_MOUNTED: send_to_char( "You really should dismount first.\n\r", ch ); return; } rprog_sleep_trigger( ch ); return; } void do_wake( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; one_argument( argument, arg ); if ( arg[0] == '\0' ) { /* leaving dreamworld -keo */ if (IS_AFFECTED(ch, AFF_DREAMWORLD)) { if ( !IS_AFFECTED(ch, AFF_SLEEP) ) { act( AT_MAGIC, "You step out of the world of dreams.", ch, NULL, NULL, TO_CHAR); act( AT_MAGIC, "$n slowly fades out of the dream.", ch, NULL, NULL, TO_ROOM); drop_dream_items(ch, ch->last_carrying); if (IS_NPC(ch)) xREMOVE_BIT(ch->affected_by, AFF_DREAMWORLD); else xREMOVE_BIT(ch->pcdata->perm_aff, AFF_DREAMWORLD); act( AT_MAGIC, "$n slowly fades into the waking world.", ch, NULL, NULL, TO_ROOM); return; } else { send_to_char("You can't seem to wake up!\n\r", ch); return; } } else { do_stand( ch, argument ); } return; } if ( !IS_AWAKE(ch) ) { send_to_char( "You are asleep yourself!\n\r", ch ); return; } if ( ( victim = get_char_room( ch, arg ) ) == NULL ) { send_to_char( "They aren't here.\n\r", ch ); return; } if ( IS_AWAKE(victim) ) { act( AT_PLAIN, "$N is already awake.", ch, NULL, victim, TO_CHAR ); return; } if ( IS_AFFECTED(victim, AFF_SLEEP) || victim->position < POS_SLEEPING ) { act( AT_PLAIN, "You can't seem to wake $M!", ch, NULL, victim, TO_CHAR ); return; } if (IS_SET(ch->in_room->room_flags, ROOM_STICKY)) { act(AT_ACTION, "You wake $M, but $s back is stuck to the floor.\n\r",ch, NULL, victim, TO_CHAR); victim->position = POS_RESTING; act(AT_ACTION, "$n wakes you, but your back is stuck to the floor.\n\r", ch, NULL, victim, TO_VICT); return; } act( AT_ACTION, "You wake $M.", ch, NULL, victim, TO_CHAR ); victim->position = POS_STANDING; act( AT_ACTION, "$n wakes you.", ch, NULL, victim, TO_VICT ); return; } /* * "Climb" in a certain direction. -Thoric */ void do_climb( CHAR_DATA *ch, char *argument ) { EXIT_DATA *pexit; bool found; found = FALSE; if ( argument[0] == '\0' ) { for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next ) if ( IS_SET( pexit->exit_info, EX_xCLIMB ) ) { move_char( ch, pexit, 0 ); return; } send_to_char( "You cannot climb here.\n\r", ch ); return; } if ( (pexit = find_door( ch, argument, TRUE )) != NULL && IS_SET( pexit->exit_info, EX_xCLIMB )) { move_char( ch, pexit, 0 ); return; } send_to_char( "You cannot climb there.\n\r", ch ); return; } /* * "enter" something (moves through an exit) -Thoric */ void do_enter( CHAR_DATA *ch, char *argument ) { EXIT_DATA *pexit; bool found; OBJ_DATA *obj; found = FALSE; if ( argument[0] == '\0' ) { for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next ) if ( IS_SET( pexit->exit_info, EX_xENTER ) ) { move_char( ch, pexit, 0 ); return; } if ( ch->in_room->sector_type != SECT_INSIDE && IS_OUTSIDE(ch) ) for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next ) if ( pexit->to_room && (pexit->to_room->sector_type == SECT_INSIDE || IS_SET(pexit->to_room->room_flags, ROOM_INDOORS)) ) { move_char( ch, pexit, 0 ); return; } send_to_char( "You cannot find an entrance here.\n\r", ch ); return; } /* enter a vehicle */ obj = get_obj_list( ch, argument, ch->in_room->first_content); pexit = find_door( ch, argument, TRUE); if (pexit && IS_SET( pexit->exit_info, EX_xENTER )) { move_char( ch, pexit, 0 ); return; } /* If we got this far, we must have an obj */ if (!obj || (obj->item_type != ITEM_VEHICLE && obj->item_type != ITEM_FOUNTAIN)) { send_to_char("You can\'t enter that!\n\r", ch); return; } if (ch->in_obj) { send_to_char("You are already in a vehicle.\n\r", ch); return; } act(AT_ACTION, "$n gets in $p.", ch, obj, NULL, TO_ROOM); act(AT_ACTION, "You get inside $p.", ch, obj, NULL, TO_CHAR); ch->in_obj = obj; if (obj->item_type == ITEM_FOUNTAIN && IS_AFFECTED(ch, AFF_FLAMING)) { act( AT_BLUE, "The water puts out the flames covering you.", ch, NULL, NULL, TO_CHAR); act( AT_BLUE, "The water puts out the flames covering $n.", ch, NULL, NULL, TO_ROOM); xREMOVE_BIT(ch->affected_by, AFF_FLAMING); } } /* * Leave through an exit. -Thoric */ void do_leave( CHAR_DATA *ch, char *argument ) { EXIT_DATA *pexit; OBJ_DATA *obj; bool found; found = FALSE; if ( argument[0] == '\0' ) { /* leave a vehible */ if (ch->in_obj) { obj = ch->in_obj; act(AT_ACTION, "$n gets out of $p.", ch, ch->in_obj, NULL, TO_ROOM); act(AT_ACTION, "You get out of $p.", ch, ch->in_obj, NULL, TO_CHAR); ch->in_obj = NULL; return; } for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next ) if ( IS_SET( pexit->exit_info, EX_xLEAVE ) ) { move_char( ch, pexit, 0 ); return; } if ( ch->in_room->sector_type == SECT_INSIDE || !IS_OUTSIDE(ch) ) for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next ) if ( pexit->to_room && pexit->to_room->sector_type != SECT_INSIDE && !IS_SET(pexit->to_room->room_flags, ROOM_INDOORS) ) { move_char( ch, pexit, 0 ); return; } send_to_char( "You cannot find an exit here.\n\r", ch ); return; } if ( (pexit = find_door( ch, argument, TRUE )) != NULL && IS_SET( pexit->exit_info, EX_xLEAVE )) { move_char( ch, pexit, 0 ); return; } send_to_char( "You cannot leave that way.\n\r", ch ); return; } /* * Check to see if an exit in the room is pulling (or pushing) players around. * Some types may cause damage. -Thoric * * People kept requesting currents (like SillyMUD has), so I went all out * and added the ability for an exit to have a "pull" or a "push" force * and to handle different types much beyond a simple water current. * * This check is called by violence_update(). I'm not sure if this is the * best way to do it, or if it should be handled by a special queue. * * Future additions to this code may include equipment being blown away in * the wind (mostly headwear), and people being hit by flying objects * * TODO: * handle more pulltypes * give "entrance" messages for players and objects * proper handling of player resistance to push/pulling */ ch_ret pullcheck( CHAR_DATA *ch, int pulse ) { ROOM_INDEX_DATA *room; EXIT_DATA *xtmp, *xit = NULL; OBJ_DATA *obj, *obj_next; bool move = FALSE, moveobj = TRUE, showroom = TRUE; int pullfact, pull; int resistance; char *tochar = NULL, *toroom = NULL, *objmsg = NULL; char *destrm = NULL, *destob = NULL, *dtxt = "somewhere"; if ( (room=ch->in_room) == NULL ) { bug( "pullcheck: %s not in a room?!?", ch->name ); return rNONE; } if (!IS_NPC(ch) && IS_SET(ch->pcdata->permissions, PERMIT_BUILD)) return rNONE; /* Find the exit with the strongest force (if any) */ for ( xtmp = room->first_exit; xtmp; xtmp = xtmp->next ) if ( xtmp->pull && xtmp->to_room && (!xit || (abs(xtmp->pull) > abs(xit->pull))) ) xit = xtmp; if ( !xit ) return rNONE; pull = xit->pull; /* strength also determines frequency */ pullfact = URANGE(1, 20-(abs(pull)/5), 20); /* strongest pull not ready yet... check for one that is */ if ( (pulse % pullfact) != 0 ) { for ( xit = room->first_exit; xit; xit = xit->next ) if ( xit->pull && xit->to_room ) { pull = xit->pull; pullfact = URANGE(1, 20-(abs(pull)/5), 20); if ( (pulse % pullfact) != 0 ) break; } if ( !xit ) return rNONE; } /* negative pull = push... get the reverse exit if any */ if ( pull < 0 ) if ( (xit=get_exit(room, rev_dir[xit->vdir])) == NULL ) return rNONE; dtxt = rev_exit(xit->vdir); /* * First determine if the player should be moved or not * Check various flags, spells, the players position and strength vs. * the pull, etc... any kind of checks you like. */ switch(xit->pulltype) { case PULL_CURRENT: case PULL_WHIRLPOOL: switch(room->sector_type) { /* allow whirlpool to be in any sector type */ default: if ( xit->pulltype == PULL_CURRENT ) break; case SECT_WATER_SWIM: case SECT_WATER_NOSWIM: if ( (ch->mount && !IS_FLOATING(ch->mount)) || (!ch->mount && !IS_FLOATING(ch)) ) move = TRUE; break; case SECT_UNDERWATER: case SECT_OCEANFLOOR: move = TRUE; break; } break; case PULL_GEYSER: case PULL_WAVE: move = TRUE; break; case PULL_WIND: case PULL_STORM: /* if not flying... check weight, position & strength */ move = TRUE; break; case PULL_COLDWIND: /* if not flying... check weight, position & strength */ /* also check for damage due to bitter cold */ move = TRUE; break; case PULL_HOTAIR: /* if not flying... check weight, position & strength */ /* also check for damage due to heat */ move = TRUE; break; /* light breeze -- very limited moving power */ case PULL_BREEZE: move = FALSE; break; /* * exits with these pulltypes should also be blocked from movement * ie: a secret locked pickproof door with the name "_sinkhole_", etc */ case PULL_EARTHQUAKE: case PULL_SINKHOLE: case PULL_QUICKSAND: case PULL_LANDSLIDE: case PULL_SLIP: case PULL_LAVA: if ( (ch->mount && !IS_FLOATING(ch->mount)) || (!ch->mount && !IS_FLOATING(ch)) ) move = TRUE; break; /* as if player moved in that direction him/herself */ case PULL_UNDEFINED: return move_char(ch, xit, 0); /* all other cases ALWAYS move */ default: move = TRUE; break; } /* assign some nice text messages */ switch(xit->pulltype) { case PULL_MYSTERIOUS: /* no messages to anyone */ showroom = FALSE; break; case PULL_WHIRLPOOL: case PULL_VACUUM: tochar = "You are sucked $T!"; toroom = "$n is sucked $T!"; destrm = "$n is sucked in from $T!"; objmsg = "$p is sucked $T."; destob = "$p is sucked in from $T!"; break; case PULL_CURRENT: case PULL_LAVA: tochar = "You drift $T."; toroom = "$n drifts $T."; destrm = "$n drifts in from $T."; objmsg = "$p drifts $T."; destob = "$p drifts in from $T."; break; case PULL_BREEZE: tochar = "You drift $T."; toroom = "$n drifts $T."; destrm = "$n drifts in from $T."; objmsg = "$p drifts $T in the breeze."; destob = "$p drifts in from $T."; break; case PULL_GEYSER: case PULL_WAVE: tochar = "You are pushed $T!"; toroom = "$n is pushed $T!"; destrm = "$n is pushed in from $T!"; destob = "$p floats in from $T."; break; case PULL_EARTHQUAKE: tochar = "The earth opens up and you fall $T!"; toroom = "The earth opens up and $n falls $T!"; destrm = "$n falls from $T!"; objmsg = "$p falls $T."; destob = "$p falls from $T."; break; case PULL_SINKHOLE: tochar = "The ground suddenly gives way and you fall $T!"; toroom = "The ground suddenly gives way beneath $n!"; destrm = "$n falls from $T!"; objmsg = "$p falls $T."; destob = "$p falls from $T."; break; case PULL_QUICKSAND: tochar = "You begin to sink $T into the quicksand!"; toroom = "$n begins to sink $T into the quicksand!"; destrm = "$n sinks in from $T."; objmsg = "$p begins to sink $T into the quicksand."; destob = "$p sinks in from $T."; break; case PULL_LANDSLIDE: tochar = "The ground starts to slide $T, taking you with it!"; toroom = "The ground starts to slide $T, taking $n with it!"; destrm = "$n slides in from $T."; objmsg = "$p slides $T."; destob = "$p slides in from $T."; break; case PULL_SLIP: tochar = "You lose your footing!"; toroom = "$n loses $s footing!"; destrm = "$n slides in from $T."; objmsg = "$p slides $T."; destob = "$p slides in from $T."; break; case PULL_VORTEX: tochar = "You are sucked into a swirling vortex of colors!"; toroom = "$n is sucked into a swirling vortex of colors!"; toroom = "$n appears from a swirling vortex of colors!"; objmsg = "$p is sucked into a swirling vortex of colors!"; objmsg = "$p appears from a swirling vortex of colors!"; break; case PULL_HOTAIR: tochar = "A blast of hot air blows you $T!"; toroom = "$n is blown $T by a blast of hot air!"; destrm = "$n is blown in from $T by a blast of hot air!"; objmsg = "$p is blown $T."; destob = "$p is blown in from $T."; break; case PULL_COLDWIND: tochar = "A bitter cold wind forces you $T!"; toroom = "$n is forced $T by a bitter cold wind!"; destrm = "$n is forced in from $T by a bitter cold wind!"; objmsg = "$p is blown $T."; destob = "$p is blown in from $T."; break; case PULL_WIND: tochar = "A strong wind pushes you $T!"; toroom = "$n is blown $T by a strong wind!"; destrm = "$n is blown in from $T by a strong wind!"; objmsg = "$p is blown $T."; destob = "$p is blown in from $T."; break; case PULL_STORM: tochar = "The raging storm drives you $T!"; toroom = "$n is driven $T by the raging storm!"; destrm = "$n is driven in from $T by a raging storm!"; objmsg = "$p is blown $T."; destob = "$p is blown in from $T."; break; default: if ( pull > 0 ) { tochar = "You are pulled $T!"; toroom = "$n is pulled $T."; destrm = "$n is pulled in from $T."; objmsg = "$p is pulled $T."; objmsg = "$p is pulled in from $T."; } else { tochar = "You are pushed $T!"; toroom = "$n is pushed $T."; destrm = "$n is pushed in from $T."; objmsg = "$p is pushed $T."; objmsg = "$p is pushed in from $T."; } break; } /* Do the moving */ if ( move ) { /* display an appropriate exit message */ if ( tochar ) { act(AT_PLAIN, tochar, ch, NULL, dir_name[xit->vdir], TO_CHAR ); send_to_char("\n\r", ch); } if ( toroom ) act(AT_PLAIN, toroom, ch, NULL, dir_name[xit->vdir], TO_ROOM ); /* display an appropriate entrance message */ /* it wasn't so appropriate, moved below -keo */ /* if ( destrm && xit->to_room->first_person ) { act(AT_PLAIN, destrm, xit->to_room->first_person, NULL, dtxt, TO_CHAR ); act(AT_PLAIN, destrm, xit->to_room->first_person, NULL, dtxt, TO_ROOM ); } */ /* move the char */ if ( xit->pulltype == PULL_SLIP ) return move_char(ch, xit, 1); char_from_room(ch); char_to_room(ch, xit->to_room); if ( showroom ) do_look(ch, "auto"); act(AT_PLAIN, destrm, ch, NULL, dtxt, TO_ROOM ); /* move the mount too */ if ( ch->mount ) { char_from_room(ch->mount); char_to_room(ch->mount, xit->to_room); if ( showroom ) do_look(ch->mount, "auto"); } } /* move objects in the room */ if ( moveobj ) { for ( obj = room->first_content; obj; obj = obj_next ) { obj_next = obj->next_content; if ( IS_OBJ_STAT(obj, ITEM_BURIED) || IS_OBJ_STAT(obj, ITEM_NO_TAKE) ) continue; resistance = get_obj_weight(obj); if ( IS_OBJ_STAT(obj, ITEM_METAL) ) resistance = (resistance * 6) / 5; switch(obj->item_type) { case ITEM_SCROLL: case ITEM_NOTE: case ITEM_TRASH: resistance >>= 2; break; case ITEM_SCRAPS: case ITEM_CONTAINER: resistance >>= 1; break; case ITEM_PEN: case ITEM_WAND: resistance = (resistance * 5) / 6; break; case ITEM_CORPSE_PC: case ITEM_CORPSE_NPC: case ITEM_FOUNTAIN: resistance <<= 2; break; } /* is the pull greater than the resistance of the object? */ if ( (abs(pull) * 10) > resistance ) { if ( objmsg && room->first_person ) { act(AT_PLAIN, objmsg, room->first_person, obj, dir_name[xit->vdir], TO_CHAR); act(AT_PLAIN, objmsg, room->first_person, obj, dir_name[xit->vdir], TO_ROOM); } if ( destob && xit->to_room->first_person ) { act(AT_PLAIN, destob, xit->to_room->first_person, obj, dtxt, TO_CHAR); act(AT_PLAIN, destob, xit->to_room->first_person, obj, dtxt, TO_ROOM); } obj_from_room(obj); obj_to_room(obj, xit->to_room); } } } return rNONE; } /* Sets a character's home room -- Scion */ void do_home(CHAR_DATA *ch, char *argument) { char arg[MAX_INPUT_LENGTH]; int slot; ROOM_INDEX_DATA *room; if (IS_NPC(ch)) { send_to_char("You haven't such a great memory.\n\r", ch); return; } if (argument && argument[0]!='\0') { argument = one_argument(argument, arg); if (is_number(arg)) slot = atoi(arg); if (slot < 0 || slot > 7) slot = 0; } else slot=0; if (!strcmp(arg, "list")) { send_to_char("Memorized locations:\r\n",ch); for (slot=0; slot<8; slot++) { room=get_room_index(ch->pcdata->memorize[slot]); sprintf(arg, "%d: %s\r\n", slot, (room ? room->name : "None")); send_to_char(arg, ch); } send_to_char("You will recall to slot 0.\r\n",ch); return; } /* Fix later */ /* if () { send_to_char("You cannot see your surroundings to memorize them.\n\r", ch); return; } */ switch (ch->substate) { case SUB_NONE: add_timer( ch, TIMER_DO_FUN, 5, do_home, 1); send_to_char( "You begin to memorize your surroundings...\n\r", ch ); act( AT_PLAIN, "$n looks around, trying to memorize $s surroundings...", ch, NULL, NULL, TO_ROOM); ch->recall=slot; return; case SUB_TIMER_DO_ABORT: act( AT_PLAIN, "$n cannot seem to concentrate.",ch, NULL, NULL, TO_ROOM); send_to_char("You just can't seem to concentrate...\r\n",ch); ch->substate=SUB_NONE; return; default: ch->substate = SUB_NONE; ch->pcdata->memorize[ch->recall]=ch->in_room->vnum; act( AT_PLAIN, "$n nods, indicating that $e has memorized $s surroundings.", ch, NULL, NULL, TO_ROOM); send_to_char( "You now feel familiar with this place.\r\n",ch); return; } } /* Moved here from the old clans.c, what the hell where they doing there anyway? -- Scion */ void do_shove( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; int exit_dir; EXIT_DATA *pexit; CHAR_DATA *victim; bool nogo; ROOM_INDEX_DATA *to_room; int chance = 0; argument = one_argument( argument, arg ); argument = one_argument( argument, arg2 ); if ( arg[0] == '\0' ) { send_to_char( "Shove whom?\n\r", ch); return; } if ( ( victim = get_char_room( ch, arg ) ) == NULL ) { send_to_char( "They aren't here.\n\r", ch); return; } if (victim == ch) { send_to_char("You shove yourself around, to no avail.\n\r", ch); return; } if (!IS_SAME_PLANE(ch, victim)) { send_to_char("You pass right through them!\n\r", ch); return; } if ( (victim->position) != POS_STANDING ) { act( AT_PLAIN, "$N isn't standing up.", ch, NULL, victim, TO_CHAR ); return; } if ( arg2[0] == '\0' ) { send_to_char( "Shove them in which direction?\n\r", ch); return; } exit_dir = get_dir( arg2 ); if ( IS_SET(victim->in_room->room_flags, ROOM_SAFE) && get_timer(victim, TIMER_SHOVEDRAG) <= 0) { send_to_char("That character cannot be shoved right now.\n\r", ch); return; } victim->position = POS_SHOVE; nogo = FALSE; if ((pexit = get_exit(ch->in_room, exit_dir)) == NULL ) nogo = TRUE; else if ( IS_SET(pexit->exit_info, EX_CLOSED) && (!IS_AFFECTED(victim, AFF_PASS_DOOR) || IS_SET(pexit->exit_info, EX_NOPASSDOOR)) ) nogo = TRUE; if ( nogo ) { send_to_char( "There's no exit in that direction.\n\r", ch ); victim->position = POS_STANDING; return; } to_room = pexit->to_room; chance += ((get_curr_str(ch) + ch->weight) - ((get_curr_str(victim) + get_curr_dex(victim)) / 2) + victim->weight); if (chance < number_percent( )) { send_to_char("You failed.\n\r", ch); victim->position = POS_STANDING; return; } act( AT_ACTION, "You shove $M.", ch, NULL, victim, TO_CHAR ); act( AT_ACTION, "$n shoves $N.", ch, NULL, victim, TO_NOTVICT ); act( AT_ACTION, "$n shoves you.", ch, NULL, victim, TO_VICT ); move_char( victim, get_exit(ch->in_room,exit_dir), 0); if ( !char_died(victim) ) victim->position = POS_STANDING; if ( IS_SET(ch->in_room->room_flags, ROOM_SAFE) && get_timer(ch, TIMER_SHOVEDRAG) <= 0 ) add_timer( ch, TIMER_SHOVEDRAG, 10, NULL, 0 ); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("shoving"); WAIT_STATE(ch, PULSE_VIOLENCE); STRFREE(victim->last_taken); victim->last_taken = STRALLOC("being shoved"); WAIT_STATE(ch, PULSE_VIOLENCE); } void do_drag( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; int exit_dir; CHAR_DATA *victim; OBJ_DATA *obj; EXIT_DATA *pexit; ROOM_INDEX_DATA *to_room; bool nogo; int chance = 0; int move_drain=0; argument = one_argument( argument, arg ); argument = one_argument( argument, arg2 ); if ( arg[0] == '\0' ) { send_to_char( "Drag whom?\n\r", ch); return; } if ( ( victim = get_char_room( ch, arg ) ) == NULL ) { if ((obj=get_obj_here(ch, arg))==NULL) { send_to_char( "They aren't here.\n\r", ch); return; } if (obj && obj->carried_by) { send_to_char( "Objects must be on the ground in order to be dragged.\r\n", ch); return; } } /* The desired thing to drag is an obj, not a char -- Scion */ if (!victim) { if (ch->in_room->pShop) { send_to_char("You can't drag items without paying in a shop.\n\r", ch); return; } if ( arg2[0] == '\0' ) { send_to_char( "Drag it in which direction?\n\r", ch); return; } exit_dir = get_dir( arg2 ); nogo = FALSE; if ((pexit = get_exit(ch->in_room, exit_dir)) == NULL ) nogo = TRUE; else if ( IS_SET(pexit->exit_info, EX_CLOSED) ) nogo = TRUE; if ( nogo ) { send_to_char( "There's no exit in that direction.\n\r", ch ); return; } to_room = pexit->to_room; chance += ((ch->weight + get_curr_str(ch)/4) - (obj->weight)); move_drain = number_percent() - chance; if (ch->move <= 0 || chance < move_drain+chance) { send_to_char("You can't seem to move it.\n\r", ch); return; } act( AT_ACTION, "You drag $p into the next room.", ch, obj, NULL, TO_CHAR ); act( AT_ACTION, "$n drags $p from the room.", ch, obj, NULL, TO_ROOM); obj_from_room(obj); /* Move ch to the room too.. they are doing dragging - Scryn */ move_char( ch, get_exit(ch->in_room,exit_dir), 0); obj_to_room(obj, to_room); act(AT_ACTION, "$n drags $p in behind $m.", ch, obj, NULL, TO_ROOM); for (victim=ch->was_in_room->first_person; victim; victim=victim->next_in_room) { if (victim->on==obj) { char_from_room(victim); char_to_room(victim, to_room); do_look(victim, "auto"); } } ch->move -= URANGE(5, move_drain, 100); return; } if ( victim == ch ) { send_to_char("You take yourself by the scruff of your neck, but go nowhere.\n\r", ch); return; } if (!IS_SAME_PLANE(ch, victim)) { send_to_char("You pass right through them!\n\r", ch); return; } if ( /*!IS_SET(victim->pcdata->flags, PCFLAG_DEADLY) && -- Scion */ victim->position > 8 ) { send_to_char("They don't seem to need your assistance.\n\r", ch ); return; } if ( arg2[0] == '\0' ) { send_to_char( "Drag them in which direction?\n\r", ch); return; } exit_dir = get_dir( arg2 ); if ( IS_SET(victim->in_room->room_flags, ROOM_SAFE) /*&& get_timer( victim, TIMER_SHOVEDRAG ) <= 0*/) { send_to_char("That character cannot be dragged right now.\n\r", ch); return; } nogo = FALSE; if ((pexit = get_exit(ch->in_room, exit_dir)) == NULL ) nogo = TRUE; else if ( IS_SET(pexit->exit_info, EX_CLOSED) && (!IS_AFFECTED(victim, AFF_PASS_DOOR) || IS_SET(pexit->exit_info, EX_NOPASSDOOR)) ) nogo = TRUE; if ( nogo ) { send_to_char( "There's no exit in that direction.\n\r", ch ); return; } to_room = pexit->to_room; chance += ((ch->weight + get_curr_str(ch)/10) - (victim->weight)); move_drain = number_percent() - chance; if (ch->move <= 0 || chance < move_drain+chance) { send_to_char("You failed.\n\r", ch); act( AT_ACTION, "$n tries to drag you from the room, but fails.", ch, NULL, victim, TO_VICT); return; } if ( victim->position < POS_STANDING ) { sh_int temp; temp = victim->position; victim->position = POS_DRAG; act( AT_ACTION, "You drag $M into the next room.", ch, NULL, victim, TO_CHAR ); act( AT_ACTION, "$n grabs you and drags you from the room.", ch, NULL, victim, TO_VICT ); move_char( victim, get_exit(ch->in_room,exit_dir), 0); if ( !char_died(victim) ) victim->position = temp; /* Move ch to the room too.. they are doing dragging - Scryn */ move_char( ch, get_exit(ch->in_room,exit_dir), 0); ch->move -= URANGE(5, move_drain, 100); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("dragging"); WAIT_STATE(ch, PULSE_VIOLENCE); STRFREE(victim->last_taken); victim->last_taken = STRALLOC("being dragged"); WAIT_STATE(ch, PULSE_VIOLENCE); return; } send_to_char("You cannot do that to someone who is standing.\n\r", ch); return; } /* Typing 'fly' should make you perm fly until you run out of moves or type 'land' -- Scion */ void do_fly(CHAR_DATA *ch, char *argument) { if (!can_use_bodypart(ch, BP_RWING) && !can_use_bodypart(ch, BP_LWING)) { send_to_char("You can't seem to be able to get off the ground.\r\n", ch); return; } if (IS_AFFECTED(ch, AFF_FLYING)) { send_to_char("You are already flying.\r\n", ch); return; } act(AT_PLAIN, "You spread your wings and take to the sky.", ch, NULL, NULL, TO_CHAR); act(AT_PLAIN, "$n spreads $s wings and takes to the sky.", ch, NULL, NULL, TO_ROOM); if (IS_NPC(ch)) xSET_BIT(ch->affected_by, AFF_FLYING); else xSET_BIT(ch->pcdata->perm_aff, AFF_FLYING); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("taking off"); WAIT_STATE(ch, PULSE_VIOLENCE); } /* Stop flying (gracefully, we hope) -- Scion */ void do_land(CHAR_DATA *ch, char *argument) { if (!has_bodypart(ch, BP_RWING)) { send_to_char("How exactly do you intend to do that?\r\n", ch); return; } if (!IS_AFFECTED(ch, AFF_FLYING)) { send_to_char("You aren't flying at the moment.\r\n", ch); return; } act(AT_PLAIN, "You settle gracefully to the ground.", ch, NULL, NULL, TO_CHAR); act(AT_PLAIN, "$n settles gracefully to the ground.", ch, NULL, NULL, TO_ROOM); if (IS_NPC(ch)) xREMOVE_BIT(ch->affected_by, AFF_FLYING); else xREMOVE_BIT(ch->pcdata->perm_aff, AFF_FLYING); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("landing"); WAIT_STATE(ch, PULSE_VIOLENCE); } /* get rid of all their dream items. modified from drop_artifacts -keo */ void drop_dream_items(CHAR_DATA *ch, OBJ_DATA *obj) { /* Expecting a ch->last_carrying or an obj->last_content ( We go BACKWARDS through the lists!) */ if (!obj) return; while (obj) { if (obj->last_content) drop_dream_items(ch, obj->last_content); if (IS_OBJ_STAT(obj, ITEM_DREAMWORLD)) { OBJ_DATA *tobj; tobj=obj; obj=obj->prev_content; if (tobj->in_obj) obj_from_obj(tobj); if (tobj->carried_by) obj_from_char(tobj); extract_obj(tobj); } else obj = obj->prev_content; } }