/*___________________________________________________________________________* )()( DalekenMUD 1.12 (C) 2000 )()( `][' by Martin Thomson, Lee Brooks, `][' || Ken Herbert and David Jacques || || ----------------------------------------------------------------- || || Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, || || David Love, Guilherme 'Willie' Arnold, and Mitchell Tse. || || Merc 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. || || ----------------------------------------------------------------- || || Any use of this software must follow the licenses of the || || creators. Much time and thought has gone into this software and || || you are benefitting. We hope that you share your changes too. || || What goes around, comes around. || || ----------------------------------------------------------------- || || act_move.c || || Player movement and miscellaneous other actions. || *_/<>\_________________________________________________________________/<>\_*/ #include "mud.h" #include "event.h" const char *const dir_name[] = { "north", "east", "south", "west", "up", "down" }; const int rev_dir[] = { DIR_SOUTH, DIR_WEST, DIR_NORTH, DIR_EAST, DIR_DOWN, DIR_UP }; const int movement_loss[SECT_MAX] = { 1, 2, 2, 3, 4, 6, 4, 1, 5, 10, 6, 1, 10 }; /* * Local functions. */ int find_door args( ( CHAR_DATA *ch, const char *arg ) ); int find_first_step args( ( ROOM_INDEX_DATA *start, ROOM_INDEX_DATA *target ) ); void add_track_q args( ( ROOM_INDEX_DATA *room, int dir ) ); void clean_track_q args( ( void ) ); void found_prey args( ( CHAR_DATA *ch, CHAR_DATA *victim ) ); /* * External functions. */ void one_hit args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dt, int wpn ) ); void move_char( CHAR_DATA *ch, int door ) { CHAR_DATA *fch; CHAR_DATA *fch_next; CHAR_DATA *vmob, *vnext; OBJ_DATA *obj, *objnext; EXIT_DATA *pexit; ROOM_INDEX_DATA *in_room; ROOM_INDEX_DATA *to_room; int moved = PLR_MOVED; /* Same for both ACT & PLR bits */ bool stumble = FALSE; if( door < 0 || door > 5 ) { bug( "Do_move: bad door %d.", door ); return; } /* * Prevents infinite move loop in * maze zone when group has 2 leaders - Kahn */ if( xIS_SET( ch->act, moved ) ) return; for( vmob = ch->in_room->people; vmob; vmob = vmob->next_in_room ) { if( !vmob->deleted && vmob->fighting == ch ) { send_to_char( "Not while someone here want's to kill you.\n\r", ch ); return; } } if( IS_AFFECTED( ch, AFF_HOLD ) ) { AFFECT_DATA *af; char buf[100]; send_to_char( "You are stuck in a snare! You can't move!\n\r", ch ); WAIT_STATE( ch, PULSE_VIOLENCE / 2 ); web_update( ch ); for( af = ch->affected; af; af = af->next ) { if( af->deleted || !xIS_SET( af->bitvector, AFF_HOLD ) || af->duration < 0 ) continue; if( --af->duration == 0 ) { affect_remove( ch, af ); sprintf( buf, "You are no longer held back by '%s'.\n\r", skill_table[af->type].name ); send_to_char( buf, ch ); } } return; } in_room = ch->in_room; if( ( IS_AFFECTED( ch, AFF_CONFUSION ) && number_bits( 1 ) ) || ( !IS_NPC( ch ) && number_bits( 7 ) < UMIN( 55, ch->pcdata->condition[COND_DRUNK] / 10 - 27 ) ) ) { stumble = TRUE; act( "&y$n stumbles and staggers wildly about.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You trip over your own fool feet.\n\r", ch ); door = number_range( 0, 5 ); } if( !( pexit = in_room->exit[door] ) || !( to_room = pexit->to_room ) ) { if( stumble ) { act( "$n whacks into a wall.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You run into a wall... Ow that hurt!\n\r", ch ); } else send_to_char( "Alas, you cannot go that way.\n\r", ch ); return; } if( IS_SET( pexit->exit_info, EX_CLOSED ) ) { if( !IS_AFFECTED( ch, AFF_PASS_DOOR ) && !IS_SET( race_table[ch->race].race_abilities, RACE_PASSDOOR ) ) { if( stumble ) { act( "$n whacks into a closed door.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You run into a door... Ow that hurt!\n\r", ch ); } act( "The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR ); return; } if( IS_SET( pexit->exit_info, EX_PASSPROOF ) && !IS_IMMORTAL( ch ) ) { if( stumble ) act( "$n whacks into a closed door.", ch, NULL, NULL, TO_ROOM ); act( "You are unable to pass through the $d. Ouch!", ch, NULL, pexit->keyword, TO_CHAR ); return; } } if( 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; } if( ( to_room->area->plane->min_level > get_trust( ch ) || ( !IS_NPC( ch ) && to_room->area != in_room->area && IS_SET( to_room->area->area_flags, AREA_HIDE ) ) ) && !IS_BUILDER( ch, to_room->area ) ) { send_to_char( "&rSomething holds you back from going there.&n\n\r", ch ); return; } if( room_is_private( to_room ) ) { send_to_char( "That room is private right now.\n\r", ch ); return; } if( !IS_NPC( ch ) ) { int move; if( door == DIR_UP && ( to_room->sector_type == SECT_AIR || in_room->sector_type == SECT_AIR ) && !IS_SET( ch->body_parts, BODY_PART_WINGS ) && !xIS_SET( ch->affected_by, AFF_FLYING ) && !IS_SET( to_room->room_flags, ROOM_FALL ) ) { send_to_char( "You can't fly.\n\r", ch ); return; } if( to_room->sector_type == SECT_SPACE && !xIS_SET( ch->affected_by, AFF_FLYING ) && !IS_SET( to_room->room_flags, ROOM_FALL ) ) { send_to_char( "You can't fly there.\n\r", ch ); return; } if( to_room->sector_type != SECT_WATER_NOSWIM && to_room->sector_type != SECT_UNDERWATER && !IS_SET( to_room->room_flags, ROOM_FLOODED ) && !xIS_SET( ch->affected_by, AFF_FLYING ) && !IS_SET( ch->body_parts, BODY_PART_TAIL ) && !IS_SET( ch->body_parts, BODY_PART_WINGS ) && !IS_SET( ch->body_parts, BODY_PART_LEGS ) ) { send_to_char( "You flap around but you cant move!\n\r", ch ); return; } if( in_room->sector_type == SECT_WATER_NOSWIM || to_room->sector_type == SECT_WATER_NOSWIM ) { for( obj = ch->carrying; obj; obj = obj->next_content ) if( obj->item_type == ITEM_BOAT ) break; /* * Suggestion for flying above water by Sludge */ if( !obj && !IS_SET( ch->body_parts, BODY_PART_WINGS ) && !xIS_SET( ch->affected_by, AFF_FLYING ) && !IS_SET( race_table[ch->race].race_abilities, RACE_SWIM ) ) { send_to_char( "You need a boat to go there.\n\r", ch ); return; } } if( ( in_room->sector_type == SECT_UNDERWATER || to_room->sector_type == SECT_UNDERWATER || IS_SET( in_room->room_flags, ROOM_FLOODED ) || IS_SET( to_room->room_flags, ROOM_FLOODED ) ) && !IS_SET( race_table[ch->race].race_abilities, RACE_SWIM ) && !IS_AFFECTED( ch, AFF_BREATHING ) && !IS_IMMORTAL( ch ) ) { send_to_char( "You need to be able to swim to go there.\n\r", ch ); return; } move = movement_loss[UMIN( SECT_MAX - 1, in_room->sector_type )] + movement_loss[UMIN( SECT_MAX - 1, to_room->sector_type )]; /* * Flying persons lose constant minimum movement. */ if( IS_SET( ch->body_parts, BODY_PART_WINGS ) || xIS_SET( ch->affected_by, AFF_FLYING ) ) move = 2; if( ch->move < move ) { if( !get_success( ch, gsn_stamina, 100 ) ) { send_to_char( "You are too exhausted.\n\r", ch ); return; } if( ch->hit < ch->max_hit / 3 ) { send_to_char( "Your body is too exhausted, " "your tired muscles will move no more.\n\r", ch ); return; } send_to_char( "You push your tired body past it's limits.\n\r", ch ); move -= ch->move; ch->move = 0; ch->hit -= move; WAIT_STATE( ch, skill_table[gsn_stamina].beats ); } else { if( IS_AFFECTED( ch, AFF_HASTE ) ) WAIT_STATE( ch, PULSE_PER_SECOND / 2 ); else WAIT_STATE( ch, PULSE_PER_SECOND ); ch->move -= move; } } if( !IS_AFFECTED( ch, AFF_SNEAK ) && ( IS_NPC( ch ) || !xIS_SET( ch->act, PLR_WIZINVIS ) ) ) { if( IS_NPC( ch ) ) REMOVE_BIT( SysInfo->flags, SYSINFO_ACT_TRIGGER ); if( ( ( in_room->sector_type == SECT_WATER_SWIM ) || ( in_room->sector_type == SECT_UNDERWATER ) || IS_SET( in_room->room_flags, ROOM_FLOODED ) ) && ( ( to_room->sector_type == SECT_WATER_SWIM ) || ( to_room->sector_type == SECT_UNDERWATER ) || IS_SET( to_room->room_flags, ROOM_FLOODED ) ) ) act( "&g$n swims $T.", ch, NULL, dir_name[door], TO_ROOM ); else { if( stumble ) act( "&g$n staggers $T.", ch, NULL, dir_name[door], TO_ROOM ); if( !IS_NPC( ch ) && ch->pcdata->setmout && ch->pcdata->setmout[0] != '\0' ) act( "&g$n $t $T.", ch, ch->pcdata->setmout, dir_name[door], TO_ROOM ); else act( "&g$n leaves $T.", ch, NULL, dir_name[door], TO_ROOM ); } } /* * Leave program */ if( ch->in_room == in_room && xIS_SET( in_room->progtypes, LEAVE_PROG ) ) greet_leave_trigger( ch, NULL, in_room, NULL, door, LEAVE_PROG ); for( vmob = in_room->people; ch->in_room == in_room && vmob != NULL; vmob = vnext ) { vnext = vmob->next_in_room; if( !vmob->deleted && IS_NPC( vmob ) && ch != vmob && vmob->fighting == NULL && IS_AWAKE( vmob ) && xIS_SET( vmob->pIndexData->progtypes, LEAVE_PROG ) ) greet_leave_trigger( ch, vmob, NULL, NULL, door, LEAVE_PROG ); } for( obj = in_room->contents; ch->in_room == in_room && obj != NULL; obj = objnext ) { objnext = obj->next_content; if( !obj->deleted && !ch->deleted && xIS_SET( obj->pIndexData->progtypes, LEAVE_PROG ) ) greet_leave_trigger( ch, NULL, NULL, obj, door, LEAVE_PROG ); } /* Safety check, the character may have been deleted or moved by the program. */ if( ch->deleted || ch->in_room != in_room ) return; char_from_room( ch ); char_to_room( ch, to_room ); if( !IS_AFFECTED( ch, AFF_SNEAK ) && ( IS_NPC( ch ) || !xIS_SET( ch->act, PLR_WIZINVIS ) ) ) { if( IS_NPC( ch ) ) REMOVE_BIT( SysInfo->flags, SYSINFO_ACT_TRIGGER ); if( stumble ) act( "&g$n staggers in from the $T.", ch, NULL, dir_name[rev_dir[door]], TO_ROOM ); else if( !IS_NPC( ch ) && ch->pcdata->setmin && ch->pcdata->setmin[0] != '\0' ) act( "&g$n $t $T.", ch, ch->pcdata->setmin, dir_name[rev_dir[door]], TO_ROOM ); else act( "&g$n has arrived from the $t.", ch, dir_name[rev_dir[door]], NULL, TO_ROOM ); } /* * Because of the addition of the deleted flag, we can do this -Kahn */ if( !IS_NPC( ch ) && !IS_IMMORTAL( ch ) ) { if( to_room->sector_type == SECT_UNDERWATER && !str_cmp( race_table[ch->race].name, "Vampire" ) ) { send_to_char( "Arrgh! Large body of water!\n\r", ch ); act( "$n thrashes underwater!", ch, NULL, NULL, TO_ROOM ); damage( ch, ch, 20, TYPE_UNDEFINED, WEAR_NONE ); } else if( !IS_AFFECTED( ch, AFF_BREATHING ) && to_room->sector_type == SECT_UNDERWATER && !IS_SET( ch->body_parts, BODY_PART_GILLS ) ) { send_to_char( "You can't breathe!\n\r", ch ); act( "$n sputters and chokes!", ch, NULL, NULL, TO_ROOM ); damage( ch, ch, ch->level + 5, gsn_breathing, WEAR_NONE ); } else if( ch->in_room->sector_type == SECT_SPACE && !IS_AFFECTED( ch, AFF_BREATHING ) ) { send_to_char( "You can't breathe!\n\r", ch ); act( "$n can't breathe, $e is turning red!", ch, NULL, NULL, TO_ROOM ); damage( ch, ch, ch->hit / 20 + 5, gsn_breathing, WEAR_NONE ); } } /* * Suggested by D'Sai from A Moment in Tyme Mud. Why have mobiles * see the room? -Kahn */ if( ch->desc ) do_look( ch, AUTOLOOK ); /* * Greet and Entry programs. */ if( IS_NPC( ch ) && xIS_SET( ch->pIndexData->progtypes, ENTRY_PROG ) ) mprog_percent_check( ch, NULL, NULL, NULL, ENTRY_PROG ); if( ch->in_room == to_room ) { if( ( xIS_SET( to_room->progtypes, ALL_GREET_PROG ) && greet_leave_trigger( ch, NULL, to_room, NULL, rev_dir[door], ALL_GREET_PROG ) == 0 ) || ( xIS_SET( to_room->progtypes, GREET_PROG ) && !IS_AFFECTED( ch, AFF_SNEAK ) && greet_leave_trigger( ch, NULL, to_room, NULL, rev_dir[door], GREET_PROG ) == 0 ) ) { char_from_room( ch ); char_to_room( ch, in_room ); return; } } for( vmob = to_room->people; ch->in_room == to_room && vmob != NULL; vmob = vnext ) { vnext = vmob->next_in_room; if( vmob->deleted || !IS_NPC( vmob ) || ch == vmob ) continue; if( IS_SET( spec_table[vmob->spec_fun].usage, SPEC_ENTER ) && ( *spec_table[vmob->spec_fun].spec_fun ) ( vmob, ch, SPEC_ENTER, NULL ) ) continue; if( vmob->fighting == NULL && IS_AWAKE( vmob ) ) { if( xIS_SET( vmob->pIndexData->progtypes, ALL_GREET_PROG ) ) greet_leave_trigger( ch, vmob, NULL, NULL, rev_dir[door], ALL_GREET_PROG ); if( xIS_SET( vmob->pIndexData->progtypes, GREET_PROG ) && !IS_AFFECTED( ch, AFF_SNEAK ) && can_see( vmob, ch ) ) greet_leave_trigger( ch, vmob, NULL, NULL, rev_dir[door], GREET_PROG ); } } for( obj = to_room->contents; ch->in_room == to_room && obj != NULL; obj = objnext ) { objnext = obj->next_content; if( obj->deleted || ch->deleted ) continue; if( xIS_SET( obj->pIndexData->progtypes, ALL_GREET_PROG ) ) greet_leave_trigger( ch, NULL, NULL, obj, rev_dir[door], ALL_GREET_PROG ); if( xIS_SET( obj->pIndexData->progtypes, GREET_PROG ) && !IS_AFFECTED( ch, AFF_SNEAK ) ) greet_leave_trigger( ch, NULL, NULL, obj, rev_dir[door], GREET_PROG ); } /* * Following. */ xSET_BIT( ch->act, moved ); for( fch = in_room->people; fch; fch = fch_next ) { fch_next = fch->next_in_room; if( fch->deleted ) continue; if( fch->master == ch && fch->position > POS_RESTING ) { if( fch->fighting ) act( "&rYou can't leave while you are still fighting.", fch, NULL, NULL, TO_CHAR ); else { if( fch->position == POS_SITTING ) fch->position = POS_STANDING; act( "You follow $N.", fch, NULL, ch, TO_CHAR ); move_char( fch, door ); } } } xREMOVE_BIT( ch->act, moved ); return; } void do_north( CHAR_DATA *ch, const char *argument ) { move_char( ch, DIR_NORTH ); return; } void do_east( CHAR_DATA *ch, const char *argument ) { move_char( ch, DIR_EAST ); return; } void do_south( CHAR_DATA *ch, const char *argument ) { move_char( ch, DIR_SOUTH ); return; } void do_west( CHAR_DATA *ch, const char *argument ) { move_char( ch, DIR_WEST ); return; } void do_up( CHAR_DATA *ch, const char *argument ) { move_char( ch, DIR_UP ); return; } void do_down( CHAR_DATA *ch, const char *argument ) { move_char( ch, DIR_DOWN ); return; } int find_door( CHAR_DATA *ch, const char *arg ) { EXIT_DATA *pexit; int door; if( !str_prefix( arg, "north" ) ) door = 0; else if( !str_prefix( arg, "east" ) ) door = 1; else if( !str_prefix( arg, "south" ) ) door = 2; else if( !str_prefix( arg, "west" ) ) door = 3; else if( !str_prefix( arg, "up" ) ) door = 4; else if( !str_prefix( arg, "down" ) ) door = 5; else { for( door = 0; door <= 5; door++ ) { if( ( pexit = ch->in_room->exit[door] ) && IS_SET( pexit->exit_info, EX_ISDOOR ) && pexit->keyword && is_name( arg, pexit->keyword ) ) return door; } return -1; } if( !( pexit = ch->in_room->exit[door] ) || !IS_SET( pexit->exit_info, EX_ISDOOR ) ) return -1; return door; } void do_open( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; int door, dam; if( argument[0] == '\0' ) { send_to_char( "Open what?\n\r", ch ); return; } if( ( door = find_door( ch, argument ) ) >= 0 ) { /* 'open door' */ EXIT_DATA *pexit; EXIT_DATA *pexit_rev; ROOM_INDEX_DATA *to_room; pexit = ch->in_room->exit[door]; 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; } REMOVE_BIT( pexit->exit_info, EX_CLOSED ); act( "&y$n opens the $d.&n", ch, NULL, pexit->keyword, TO_ROOM ); send_to_char( "Ok.\n\r", ch ); /* * open the other side */ if( ( to_room = pexit->to_room ) && ( pexit_rev = to_room->exit[rev_dir[door]] ) && pexit_rev->to_room == ch->in_room ) { CHAR_DATA *rch; REMOVE_BIT( pexit_rev->exit_info, EX_CLOSED ); for( rch = to_room->people; rch; rch = rch->next_in_room ) { if( rch->deleted ) continue; act( "&yThe $d opens.&n", rch, NULL, pexit_rev->keyword, TO_ALL ); break; } } /* trapped door routine */ if( IS_SET( pexit->exit_info, EX_TRAPPED ) ) { int trap; trap = number_range( gsn_first_trap, gsn_last_trap ); dam = 4 + ch->level / 2 + ch->hit / 10; if( number_percent( ) < power( 8, 7, get_curr_dex( ch ) - 16 ) ) { act( "&rA $t shoots out and barely misses $n!&n", ch, skill_table[trap].noun_damage, NULL, TO_ROOM ); act( "&rA $t shoots out and barely misses you!&n", ch, skill_table[trap].noun_damage, NULL, TO_CHAR ); } else { act( "&rA $t shoots out and strikes $n!&n", ch, skill_table[trap].noun_damage, NULL, TO_ROOM ); act( "&rA $t shoots out and strikes you!&n", ch, skill_table[trap].noun_damage, NULL, TO_CHAR ); damage( ch, ch, dam, trap, WEAR_NONE ); } } if( door == DIR_DOWN ) char_fall_check( ch, 0 ); return; } if( ( obj = get_obj_here( ch, argument ) ) ) { /* 'open 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 already open.\n\r", ch ); return; } if( !IS_SET( obj->value[1], CONT_CLOSEABLE ) ) { send_to_char( "You can't do that.\n\r", ch ); return; } if( IS_SET( obj->value[1], CONT_LOCKED ) ) { send_to_char( "It's locked.\n\r", ch ); return; } if( IS_SET( obj->value[1], CONT_TRAPPED ) ) { send_to_char( "That was trapped!\n\r", ch ); dam = 4 + ch->level / 2 + ch->hit / 12; if( number_percent( ) < power( 10, 7, get_curr_dex( ch ) - 15 ) ) { act( "&rA small dart shoots out and barely misses $n!&n", ch, NULL, NULL, TO_ROOM ); act( "&rA small dart shoots out and barely misses you!&n", ch, NULL, NULL, TO_CHAR ); } else { act( "&rA small dart shoots out and strikes $n!&n", ch, NULL, NULL, TO_ROOM ); act( "&rA small dart shoots out and strikes you!&n", ch, NULL, NULL, TO_CHAR ); damage( ch, ch, dam, gsn_first_trap, WEAR_NONE ); } } REMOVE_BIT( obj->value[1], CONT_CLOSED ); send_to_char( "Ok.\n\r", ch ); act( "&y$n opens $p&y.&n", ch, obj, NULL, TO_ROOM ); if( xIS_SET( obj->pIndexData->progtypes, OPEN_PROG ) ) oprog_percent_check( ch, obj, NULL, OPEN_PROG ); return; } act( "I see no $T here.", ch, NULL, argument, TO_CHAR ); return; } void do_close( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; int door; if( argument[0] == '\0' ) { send_to_char( "Close what?\n\r", ch ); return; } if( ( door = find_door( ch, argument ) ) >= 0 ) { /* 'close door' */ EXIT_DATA *pexit; EXIT_DATA *pexit_rev; ROOM_INDEX_DATA *to_room; pexit = ch->in_room->exit[door]; if( IS_SET( pexit->exit_info, EX_CLOSED ) ) { send_to_char( "It's already closed.\n\r", ch ); return; } if( IS_SET( pexit->exit_info, EX_BASHED ) ) { act( "The $d has been bashed open and cannot be closed.", ch, NULL, pexit->keyword, TO_CHAR ); return; } SET_BIT( pexit->exit_info, EX_CLOSED ); act( "&y$n closes the $d.&n", ch, NULL, pexit->keyword, TO_ROOM ); send_to_char( "Ok.\n\r", ch ); /* close the other side */ if( ( to_room = pexit->to_room ) && ( pexit_rev = to_room->exit[rev_dir[door]] ) && pexit_rev->to_room == ch->in_room ) { CHAR_DATA *rch; SET_BIT( pexit_rev->exit_info, EX_CLOSED ); for( rch = to_room->people; rch; rch = rch->next_in_room ) { if( rch->deleted ) continue; act( "The $d closes.", rch, NULL, pexit_rev->keyword, TO_CHAR ); } } return; } if( ( obj = get_obj_here( ch, argument ) ) ) { /* 'close 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 already closed.\n\r", ch ); return; } if( !IS_SET( obj->value[1], CONT_CLOSEABLE ) ) { send_to_char( "You can't do that.\n\r", ch ); return; } SET_BIT( obj->value[1], CONT_CLOSED ); send_to_char( "Ok.\n\r", ch ); act( "&y$n closes $p&y.&n", ch, obj, NULL, TO_ROOM ); if( xIS_SET( obj->pIndexData->progtypes, CLOSE_PROG ) ) oprog_percent_check( ch, obj, NULL, CLOSE_PROG ); return; } act( "I see no $T here.", ch, NULL, argument, TO_CHAR ); return; } OBJ_DATA *has_key( CHAR_DATA *ch, int key ) { OBJ_DATA *obj; for( obj = ch->carrying; obj; obj = obj->next_content ) { if( !obj->deleted && obj->pIndexData->vnum == key && can_see_obj( ch, obj ) ) return obj; } return NULL; } void do_lock( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; int door; if( argument[0] == '\0' ) { send_to_char( "Lock what?\n\r", ch ); return; } if( ( door = find_door( ch, argument ) ) >= 0 ) { /* 'lock door' */ EXIT_DATA *pexit; EXIT_DATA *pexit_rev; ROOM_INDEX_DATA *to_room; pexit = ch->in_room->exit[door]; 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( !has_key( ch, pexit->key ) ) { 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; } SET_BIT( pexit->exit_info, EX_LOCKED ); send_to_char( "&y*Click*&n\n\r", ch ); act( "&y$n locks the $d.&n", ch, NULL, pexit->keyword, TO_ROOM ); /* lock the other side */ if( ( to_room = pexit->to_room ) && ( pexit_rev = to_room->exit[rev_dir[door]] ) && pexit_rev->to_room == ch->in_room ) { SET_BIT( pexit_rev->exit_info, EX_LOCKED ); } return; } if( ( obj = get_obj_here( ch, argument ) ) ) { /* '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( !has_key( ch, obj->value[2] ) ) { 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 ); act( "$n locks $p.", ch, obj, NULL, TO_ROOM ); return; } act( "I see no $T here.", ch, NULL, argument, TO_CHAR ); return; } void do_unlock( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; int door; if( argument[0] == '\0' ) { send_to_char( "Unlock what?\n\r", ch ); return; } if( ( door = find_door( ch, argument ) ) >= 0 ) { /* 'unlock door' */ EXIT_DATA *pexit; EXIT_DATA *pexit_rev; ROOM_INDEX_DATA *to_room; pexit = ch->in_room->exit[door]; 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( !( obj = has_key( ch, pexit->key ) ) ) { 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; } REMOVE_BIT( pexit->exit_info, EX_LOCKED ); send_to_char( "&y*Click*&n\n\r", ch ); act( "&y$n unlocks the $d.&n", ch, NULL, pexit->keyword, TO_ROOM ); /* unlock the other side */ if( ( to_room = pexit->to_room ) && ( pexit_rev = to_room->exit[rev_dir[door]] ) && pexit_rev->to_room == ch->in_room ) REMOVE_BIT( pexit_rev->exit_info, EX_LOCKED ); if( xIS_SET( obj->pIndexData->progtypes, USE_PROG ) ) oprog_percent_check( ch, obj, NULL, USE_PROG ); if( IS_SET( pexit->exit_info, EX_EAT_KEY ) ) { act( "The $d makes a grinding noise and $p turns to powder!", ch, obj, pexit->keyword, TO_ALL ); extract_obj( obj ); } return; } if( ( obj = get_obj_here( ch, argument ) ) ) { /* '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( !has_key( ch, obj->value[2] ) ) { 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; } if( IS_SET( obj->value[1], CONT_EAT_KEY ) ) { extract_obj( has_key( ch, obj->value[2] ) ); act( "$p eats the key!", ch, obj, NULL, TO_ALL ); } REMOVE_BIT( obj->value[1], CONT_LOCKED ); send_to_char( "*Click*\n\r", ch ); act( "$n unlocks $p.", ch, obj, NULL, TO_ROOM ); return; } act( "I see no $T here.", ch, NULL, argument, TO_CHAR ); return; } void do_pick( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; CHAR_DATA *gch; char arg[MAX_INPUT_LENGTH]; int door; EVENT *e; one_argument( argument, arg ); if( arg[0] == '\0' ) { send_to_char( "Pick what?\n\r", ch ); return; } /* look for guards */ for( gch = ch->in_room->people; gch; gch = gch->next_in_room ) { if( gch->deleted ) continue; if( IS_NPC( gch ) && IS_AWAKE( gch ) && ch->level + 5 < gch->level ) { act( "$N is standing too close to the lock.", ch, NULL, gch, TO_CHAR ); return; } } WAIT_STATE( ch, skill_table[gsn_pick_lock].beats ); if( ( door = find_door( ch, arg ) ) >= 0 ) { /* 'pick door' */ EXIT_DATA *pexit; pexit = ch->in_room->exit[door]; if( !IS_SET( pexit->exit_info, EX_CLOSED ) ) { send_to_char( "It's not closed.\n\r", ch ); return; } if( !IS_SET( pexit->exit_info, EX_LOCKED ) ) { send_to_char( "It's already unlocked.\n\r", ch ); return; } act( "$n begin$% to pick the $d.", ch, NULL, pexit->keyword, TO_ALL ); if( IS_SET( pexit->exit_info, EX_TRAPPED ) ) create_char_event( ch, evn_picktrap, number_range( 1, skill_table[gsn_pick_lock].beats ) ); e = create_char_event( ch, evn_picklock, skill_table[gsn_pick_lock].beats ); e->data[0] = 0; /* picking a door */ e->data[1] = door; /* which door to pick */ return; } if( ( obj = get_obj_here( ch, arg ) ) ) { /* 'pick 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( !IS_SET( obj->value[1], CONT_LOCKED ) ) { send_to_char( "It's already unlocked.\n\r", ch ); return; } act( "$n begin$% to pick $p.", ch, obj, NULL, TO_ALL ); if( IS_SET( obj->value[1], CONT_TRAPPED ) ) create_char_event( ch, evn_picktrap, number_range( 1, skill_table[gsn_pick_lock].beats ) ); e = create_char_event( ch, evn_picklock, skill_table[gsn_pick_lock].beats ); e->data[0] = 1; /* picking a container */ e->extra.type = TARGET_OBJ; e->extra.target.obj = obj; return; } act( "I see no $T here.", ch, NULL, arg, TO_CHAR ); return; } void do_stand( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj = NULL; char buf[MAX_INPUT_LENGTH]; if( argument[0] != '\0' ) { if( ch->position == POS_FIGHTING ) { send_to_char( "Maybe you should finish fighting first?\n\r", ch ); return; } one_argument( argument, buf ); if( !str_cmp( buf, "on" ) || !str_cmp( buf, "in" ) || !str_cmp( buf, "at" ) ) argument = one_argument( argument, buf ); obj = get_obj_list( ch, argument, ch->in_room->contents ); if( obj == NULL ) { send_to_char( "You don't see that here.\n\r", ch ); return; } if( obj->item_type != ITEM_FURNITURE || ( !IS_SET( obj->value[0], FURN_STAND_AT ) && !IS_SET( obj->value[0], FURN_STAND_ON ) && !IS_SET( obj->value[0], FURN_STAND_IN ) ) ) { send_to_char( "You can't seem to find a place to stand.\n\r", ch ); return; } if( ch->on != obj && count_users( obj ) >= obj->value[1] ) { act( "There's no room to stand on $p.", ch, obj, NULL, TO_CHAR ); return; } /* hack to ensure a message when a player is already standing */ ch->position = POS_RESTING; ch->on = obj; } switch( ch->position ) { case POS_GETTING_UP: case POS_SMASHED: ch->position = POS_STANDING; act( "&y$n manage$% to stand.", ch, NULL, NULL, TO_ALL ); break; case POS_SLEEPING: if( IS_AFFECTED( ch, AFF_SLEEP ) ) { send_to_char( "You can't wake up!\n\r", ch ); return; } ch->position = POS_STANDING; if( obj == NULL) { act( "&g$n wake$% and stand$% up.", ch, NULL, NULL, TO_ALL ); ch->on = NULL; } else if( IS_SET( obj->value[0], FURN_STAND_ON ) ) act( "$n wake$% and stand$% on $p.", ch, obj, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_STAND_AT ) ) act("$n wake$% and stand$% at $p.", ch, obj, NULL, TO_ALL ); else act( "&g$n wake$% and stand$% in $p.", ch, obj, NULL, TO_ALL ); break; case POS_RESTING: case POS_SITTING: ch->position = POS_STANDING; if( !obj ) { act( "&g$n stand$% up.&n", ch, NULL, NULL, TO_ALL ); ch->on = NULL; } else if( IS_SET( obj->value[0], FURN_STAND_ON ) ) act( "$n stand$% on $p.", ch, obj, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_STAND_AT ) ) act("$n stand$% at $p.", ch, obj, NULL, TO_ALL ); else act( "&g$n stand$% in $p.", ch, obj, NULL, TO_ALL ); break; case POS_FIGHTING: send_to_char( "You are already fighting!\n\r", ch ); break; case POS_STANDING: send_to_char( "You are already standing.\n\r", ch ); break; } return; } void do_sit( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; char buf[MAX_INPUT_LENGTH]; const char *waksit; if( IS_AFFECTED( ch, AFF_DEAD ) ) { send_to_char( "You can't rest until you die.\n\r", ch ); return; } if( ch->position == POS_FIGHTING ) { send_to_char( "Not while you're fighting!\n\r", ch ); return; } /* okay, now that we know we can rest, find an object to rest on */ if( argument[0] != '\0' ) { one_argument( argument, buf ); if( !str_cmp( buf, "on" ) || !str_cmp( buf, "in" ) || !str_cmp( buf, "at" ) ) argument = one_argument( argument, buf ); obj = get_obj_list( ch, argument, ch->in_room->contents ); if( obj == NULL ) { send_to_char( "You don't see that here.\n\r", ch ); return; } } else obj = ch->on; if( obj != NULL ) { if( obj->item_type != ITEM_FURNITURE || ( !IS_SET( obj->value[0], FURN_REST_ON ) && !IS_SET( obj->value[0], FURN_REST_IN ) && !IS_SET( obj->value[0], FURN_REST_AT ) ) ) { send_to_char( "You can't rest on that.\n\r", ch ); return; } if( obj != NULL && ch->on != obj && count_users( obj ) >= obj->value[1] ) { act( "There's no more room on $p.", ch, obj, NULL, TO_CHAR ); return; } ch->on = obj; } stop_juggling( ch ); switch( ch->position ) { case POS_SLEEPING: case POS_RESTING: if( IS_AFFECTED( ch, AFF_SLEEP ) ) { send_to_char( "You can't wake up!\n\r", ch ); return; } if( xIS_SET( ch->in_room->progtypes, REST_PROG ) && rprog_percent_check( ch->in_room, ch, NULL, NULL, REST_PROG ) == 0 ) return; if( ch->position == POS_SLEEPING ) waksit = "wake"; else waksit = "sit"; ch->position = POS_SITTING; if( !obj ) act( "&g$n $T$% up and sit$%.&n", ch, NULL, waksit, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_ON ) ) act( "$n $T$% up and sit$% on $p.", ch, obj, waksit, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_AT ) ) act( "$n $T$% up and sit$% at $p.", ch, obj, waksit, TO_ALL ); else act( "$n $T$% up and sit$% in $p.", ch, obj, waksit, TO_ALL ); break; case POS_SITTING: send_to_char( "You are already sitting.\n\r", ch ); break; case POS_FIGHTING: send_to_char( "Not while you're fighting!\n\r", ch ); break; case POS_STANDING: if( xIS_SET( ch->in_room->progtypes, REST_PROG ) && rprog_percent_check( ch->in_room, ch, NULL, NULL, REST_PROG ) == 0 ) return; if( !obj ) act( "&g$n sit$% down.", ch, NULL, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_ON ) ) act("$n sit$% on $p.", ch, obj, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_AT ) ) act("$n sit$% at $p.", ch, obj, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_IN ) ) act("$n sit$% in $p.", ch, obj, NULL, TO_ALL ); ch->position = POS_SITTING; break; } return; } void do_rest( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; char buf[MAX_INPUT_LENGTH]; if( IS_AFFECTED( ch, AFF_DEAD ) ) { send_to_char( "You can't rest until you die.\n\r", ch ); return; } if( ch->position == POS_FIGHTING ) { send_to_char( "Not while you're fighting!\n\r", ch ); return; } /* okay, now that we know we can rest, find an object to rest on */ if( argument[0] != '\0' ) { one_argument( argument, buf ); if( !str_cmp( buf, "on" ) || !str_cmp( buf, "in" ) || !str_cmp( buf, "at" ) ) argument = one_argument( argument, buf ); obj = get_obj_list( ch, argument, ch->in_room->contents ); if( obj == NULL ) { send_to_char( "You don't see that here.\n\r", ch ); return; } } else obj = ch->on; if( obj != NULL ) { if( obj->item_type != ITEM_FURNITURE || ( !IS_SET( obj->value[0], FURN_REST_ON ) && !IS_SET( obj->value[0], FURN_REST_IN ) && !IS_SET( obj->value[0], FURN_REST_AT ) ) ) { send_to_char( "You can't rest on that.\n\r", ch ); return; } if( obj != NULL && ch->on != obj && count_users( obj ) >= obj->value[1] ) { act( "There's no more room on $p.", ch, obj, NULL, TO_CHAR ); return; } ch->on = obj; } stop_juggling( ch ); switch( ch->position ) { case POS_SLEEPING: if( IS_AFFECTED( ch, AFF_SLEEP ) ) { send_to_char( "You can't wake up!\n\r", ch ); return; } if( xIS_SET( ch->in_room->progtypes, REST_PROG ) && rprog_percent_check( ch->in_room, ch, NULL, NULL, REST_PROG ) == 0 ) return; ch->position = POS_RESTING; if( !obj ) act( "&g$n wake$% up and rest$%.&n", ch, NULL, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_ON ) ) act("$n wake$% up and rest$% on $p.", ch, obj, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_AT ) ) act("$n wake$% up and rest$% at $p.", ch, obj, NULL, TO_ALL ); else act("$n wake$% up and rest$% in $p.", ch, obj, NULL, TO_ALL ); break; case POS_RESTING: send_to_char( "You are already resting.\n\r", ch ); break; case POS_FIGHTING: send_to_char( "Not while you're fighting!\n\r", ch ); break; case POS_SITTING: if( xIS_SET( ch->in_room->progtypes, REST_PROG ) && rprog_percent_check( ch->in_room, ch, NULL, NULL, REST_PROG ) == 0 ) return; if( !obj ) act( "&g$n rest$%.", ch, NULL, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_ON ) ) act("$n recline$% back on $p.", ch, obj, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_AT ) ) act("$n recline$% back at $p.", ch, obj, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_IN ) ) act("$n reclines back in $p.", ch, obj, NULL, TO_ALL ); ch->position = POS_RESTING; break; case POS_STANDING: if( xIS_SET( ch->in_room->progtypes, REST_PROG ) && rprog_percent_check( ch->in_room, ch, NULL, NULL, REST_PROG ) == 0 ) return; if( !obj ) act( "&g$n sit$% down and rest$%.&n", ch, NULL, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_ON ) ) act("$n sit$% on $p and rest$%.", ch, obj, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_AT ) ) act("$n sit$% at $p and rest$%.", ch, obj, NULL, TO_ALL ); else if( IS_SET( obj->value[0], FURN_REST_IN ) ) act("$n sit$% in $p and rest$%.", ch, obj, NULL, TO_ALL ); ch->position = POS_RESTING; break; } return; } void do_sleep( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; char buf[MAX_INPUT_LENGTH]; if( IS_AFFECTED( ch, AFF_DEAD ) ) { send_to_char( "You can't rest until you die.\n\r", ch ); return; } stop_juggling( ch ); switch( ch->position ) { case POS_SLEEPING: send_to_char( "You are already sleeping.\n\r", ch ); break; case POS_GETTING_UP: case POS_SMASHED: if( ch->fighting ) { send_to_char( "That could be a bad idea right now.\n\r", ch ); return; } case POS_SITTING: case POS_RESTING: case POS_STANDING: if( argument[0] == '\0' && ch->on == NULL ) { act( "&g$n fall$% fast sleep$%.&n", ch, NULL, NULL, TO_ALL ); ch->position = POS_SLEEPING; break; } if( argument[0] == '\0' ) obj = ch->on; else { one_argument( argument, buf ); if( !str_cmp( buf, "on" ) || !str_cmp( buf, "in" ) || !str_cmp( buf, "at" ) ) argument = one_argument( argument, buf ); obj = get_obj_list( ch, argument, ch->in_room->contents ); } if( !obj || obj->item_type != ITEM_FURNITURE || ( !IS_SET( obj->value[0], FURN_SLEEP_ON ) && !IS_SET( obj->value[0], FURN_SLEEP_IN ) && !IS_SET( obj->value[0], FURN_SLEEP_AT ) ) ) { send_to_char( "You can't sleep on that!\n\r", ch ); return; } if( obj != NULL && ch->on != obj && count_users( obj ) >= obj->value[1] ) { act( "There's no more room on $p.", ch, obj, NULL, TO_CHAR ); return; } if( xIS_SET( ch->in_room->progtypes, SLEEP_PROG ) && rprog_percent_check( ch->in_room, ch, NULL, NULL, SLEEP_PROG ) == 0 ) return; ch->on = obj; if( IS_SET( obj->value[0], FURN_SLEEP_IN ) ) { act( "You go to sleep in $p.", ch, obj, NULL, TO_CHAR ); act("$n goes to sleep in $p.", ch, obj, NULL, TO_ROOM ); } else if( IS_SET( obj->value[0], FURN_SLEEP_ON ) ) { act( "You go to sleep on $p.", ch, obj, NULL, TO_CHAR ); act("$n goes to sleep on $p.", ch, obj, NULL, TO_ROOM ); } else { act( "You go to sleep at $p.", ch, obj, NULL, TO_CHAR ); act("$n goes to sleep at $p.", ch, obj, NULL, TO_ROOM ); } ch->position = POS_SLEEPING; break; case POS_FIGHTING: send_to_char( "&rNot while you're fighting!&n\n\r", ch ); break; } return; } void do_wake( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *victim; char arg[MAX_INPUT_LENGTH]; one_argument( argument, arg ); if( arg[0] == '\0' ) { 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 ) ) ) { send_to_char( "They aren't here.\n\r", ch ); return; } if( IS_AWAKE( victim ) ) { act( "$N is already awake.", ch, NULL, victim, TO_CHAR ); return; } if( IS_AFFECTED( victim, AFF_SLEEP ) ) { act( "&rYou can't wake $M!&n", ch, NULL, victim, TO_CHAR ); return; } if( victim->wait > 0 && ( victim->position == POS_SMASHED || victim->position == POS_GETTING_UP ) ) { send_to_char( "They are awake but too heavy to help up.\n\r", ch ); return; } act( "&gYou wake $M.&n", ch, NULL, victim, TO_CHAR ); act( "&g$n wakes you.&n", ch, NULL, victim, TO_VICT ); do_stand( victim, "" ); return; } void do_sneak( CHAR_DATA *ch, const char *argument ) { AFFECT_DATA af; /* Don't allow charmed mobs to do this, check player's skill */ if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) ) || ( !IS_NPC( ch ) && !can_use( ch, gsn_sneak ) ) ) { bad_command( ch ); return; } send_to_char( "You attempt to move silently.\n\r", ch ); affect_strip( ch, gsn_sneak ); if( IS_NPC( ch ) || number_percent( ) < ch->pcdata->learned[gsn_sneak] ) { af.type = gsn_sneak; af.level = ch->level; af.duration = ch->level; af.location = APPLY_NONE; af.modifier = 0; vset( af.bitvector, AFF_SNEAK ); affect_to_char( ch, &af, NULL ); } return; } void do_hide( CHAR_DATA *ch, const char *argument ) { /* Dont allow charmed mobiles to do this, check player's skill */ if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) ) || ( !IS_NPC( ch ) && !can_use( ch, gsn_hide ) ) ) { bad_command( ch ); return; } send_to_char( "You attempt to hide.\n\r", ch ); if( IS_AFFECTED( ch, AFF_HIDE ) ) xREMOVE_BIT( ch->affected_by, AFF_HIDE ); if( IS_NPC( ch ) || number_percent( ) < ch->pcdata->learned[gsn_hide] ) xSET_BIT( ch->affected_by, AFF_HIDE ); return; } void do_move_hidden( CHAR_DATA *ch, const char *argument ) { AFFECT_DATA af; /* Dont allow charmed mobiles to do this, check player's skill */ if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) ) || ( !IS_NPC( ch ) && !can_use( ch, gsn_move_hidden ) ) ) { bad_command( ch ); return; } if( can_use( ch, gsn_sneak ) ) do_sneak( ch, "" ); if( IS_AFFECTED( ch, AFF_HIDE ) ) xREMOVE_BIT( ch->affected_by, AFF_HIDE ); affect_strip( ch, gsn_move_hidden ); send_to_char( "You attempt to move in the shadows.\n\r", ch ); af.type = gsn_move_hidden; af.level = 0; af.duration = 2 * ch->level / 3; af.location = APPLY_NONE; af.modifier = 0; vset( af.bitvector, AFF_HIDE ); if( IS_NPC( ch ) || number_percent() < ch->pcdata->learned[gsn_move_hidden] ) affect_to_char( ch, &af, ch ); return; } /* * Contributed by Alander. */ void do_visible( CHAR_DATA *ch, const char *argument ) { AFFECT_DATA *af; for( af = ch->affected; af; af = af->next ) { if( af->deleted || af->duration < 0 ) continue; if( af->type == gsn_invis || af->type == gsn_mass_invis || af->type == gsn_vanish || af->type == gsn_sneak || af->type == gsn_move_hidden ) affect_remove( ch, af ); } if( !IS_NPC( ch ) ) { ROOM_INDEX_DATA *room = ch->in_room; char_from_room( ch ); xREMOVE_BIT( ch->act, PLR_WIZINVIS ); char_to_room( ch, room ); } else xREMOVE_BIT( ch->act, ACT_BURIED ); send_to_char( "Ok.\n\r", ch ); act( "$n becomes visible.", ch, NULL, NULL, TO_ROOM ); return; } void do_recall( CHAR_DATA *ch, const char *argument ) { ROOM_INDEX_DATA *location; char buf[MAX_STRING_LENGTH]; int place; if( !str_cmp( argument, "reset" ) ) { ch->recall_room = -1; send_to_char( "&gRecall is set to default location.&n\n\r", ch ); return; } if( IS_SET( ch->in_room->room_flags, ROOM_NO_RECALL ) || is_affected( ch, gsn_hex ) ) { send_to_char( "&rYou stand on cursed ground, you can't recall.&n\n\r", ch ); return; } if( !str_cmp( argument, "set" ) ) { send_to_char( "&gRecall set to this room.&n\n\r", ch ); ch->recall_room = ch->in_room->vnum; return; } act( "&g$n recalls.&n", ch, NULL, NULL, TO_ROOM ); if( !str_cmp( argument, "|clan|" ) ) { if( !is_clan( ch ) ) /* sanity check */ { send_to_char( "You don't belong to any clan, guild or order!\n\r", ch ); return; } place = ch->pcdata->clan->recall; } else if( ch->recall_room > 0 ) place = ch->recall_room; else place = ch->in_room->area->recall; if( !( location = get_room_index( place ) ) || location->area->plane != ch->in_room->area->plane ) { send_to_char( "You are completely lost.\n\r", ch ); return; } if( ch->in_room == location ) return; if( ch->fighting ) { int lose; if( number_bits( 1 ) == 0 ) { WAIT_STATE( ch, PULSE_PER_SECOND ); lose = ( ch->desc ) ? 2500 : 5000; gain_exp( ch, 0 - lose ); sprintf( buf, "&yYou failed! &rYou lose &y%d&r exps.&n\n\r", lose / 100 ); send_to_char( buf, ch ); return; } lose = ( ch->desc ) ? 5000 : 10000; gain_exp( ch, 0 - lose ); sprintf( buf, "&yYou recall from combat! &rYou lose &y%d&r exps.&n\n\r", lose / 100 ); send_to_char( buf, ch ); stop_fighting( ch, TRUE ); } ch->move /= 2; act( "&g$n disappears.&n", ch, NULL, NULL, TO_ROOM ); char_from_room( ch ); char_to_room( ch, location ); act( "&g$n appears in the room.&n", ch, NULL, NULL, TO_ROOM ); do_look( ch, AUTOLOOK ); return; } void do_arena( CHAR_DATA *ch, const char *argument ) { ROOM_INDEX_DATA *arena; if( IS_SET( ch->in_room->room_flags, ROOM_NO_RECALL ) || is_affected( ch, gsn_hex ) ) { send_to_char( "You are cursed, you cannot seek the arena.\n\r", ch ); return; } arena = get_room_index( ROOM_VNUM_ARENA ); act( "$n leaves for battle!", ch, NULL, NULL, TO_ROOM ); char_from_room( ch ); char_to_room( ch, arena ); act( "$n arrives ready for a fight!", ch, NULL, NULL, TO_ROOM ); do_look( ch, AUTOLOOK ); return; } void do_train( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *mob; const char *pOutput; int *pAbility; int cost; int bone_flag = 0; /* Added for training of hp ma mv */ if( IS_NPC( ch ) ) return; /* * Check for trainer. */ for( mob = ch->in_room->people; mob; mob = mob->next_in_room ) { if( IS_NPC( mob ) && xIS_SET( mob->act, ACT_TRAIN ) ) break; } if( !mob || argument[0] == '\0' ) { argument = "foo"; } if( !str_prefix( "str", argument ) ) { cost = ch->pcdata->perm_str - ( race_table[ch->race].str_mod + 15 ); if( class_table[ch->class].attr_prime == APPLY_STR ) cost--; pAbility = &ch->pcdata->perm_str; pOutput = "strength"; } else if( !str_prefix( "int", argument ) ) { cost = ch->pcdata->perm_int - ( race_table[ch->race].int_mod + 15 ); if( class_table[ch->class].attr_prime == APPLY_INT ) cost--; pAbility = &ch->pcdata->perm_int; pOutput = "intelligence"; } else if( !str_prefix( "wis", argument ) ) { cost = ch->pcdata->perm_wis - ( race_table[ch->race].wis_mod + 15 ); if( class_table[ch->class].attr_prime == APPLY_WIS ) cost--; pAbility = &ch->pcdata->perm_wis; pOutput = "wisdom"; } else if( !str_prefix( "dex", argument ) ) { cost = ch->pcdata->perm_dex - ( race_table[ch->race].dex_mod + 15 ); if( class_table[ch->class].attr_prime == APPLY_DEX ) cost--; pAbility = &ch->pcdata->perm_dex; pOutput = "dexterity"; } else if( !str_prefix( "con", argument ) ) { cost = ch->pcdata->perm_con - ( race_table[ch->race].con_mod + 15 ); if( class_table[ch->class].attr_prime == APPLY_CON ) cost--; pAbility = &ch->pcdata->perm_con; pOutput = "constitution"; } else if( !str_prefix( "magic ", argument ) ) { cost = 250; argument += 6; if( !str_prefix( "air", argument ) ) { pAbility = &ch->pcdata->perm_magic[MAGIC_AIR]; pOutput = "air magic"; bone_flag = MAGIC_AIR; } else if( !str_prefix( "earth", argument ) ) { pAbility = &ch->pcdata->perm_magic[MAGIC_EARTH]; pOutput = "earth magic"; bone_flag = MAGIC_EARTH; } else if( !str_prefix( "fire", argument ) ) { pAbility = &ch->pcdata->perm_magic[MAGIC_FIRE]; pOutput = "fire magic"; bone_flag = MAGIC_FIRE; } else if( !str_prefix( "spirit", argument ) ) { pAbility = &ch->pcdata->perm_magic[MAGIC_SPIRIT]; pOutput = "spirit magic"; bone_flag = MAGIC_SPIRIT; } else if( !str_prefix( "water", argument ) ) { pAbility = &ch->pcdata->perm_magic[MAGIC_WATER]; pOutput = "water magic"; bone_flag = MAGIC_WATER; } else { send_to_char( "Syntax: train magic <element>\n\r" "Air, Earth, Fire, Spirit and Water.\n\r", ch ); return; } bone_flag++; } /* ---------------- By Bonecrusher ------------------- */ else if( !str_cmp( argument, "hp" ) ) { cost = 15 + class_table[ch->class].fMana; bone_flag = -1; pAbility = &ch->max_hit; pOutput = "hit points"; } else if( !str_prefix( "mana ", argument ) ) { cost = 25 - class_table[ch->class].fMana; bone_flag = -2; argument += 5; if( !str_prefix( "air", argument ) ) { pAbility = &ch->max_mana[MAGIC_AIR]; pOutput = "air mana"; } else if( !str_prefix( "earth", argument ) ) { pAbility = &ch->max_mana[MAGIC_EARTH]; pOutput = "earth mana"; } else if( !str_prefix( "fire", argument ) ) { pAbility = &ch->max_mana[MAGIC_FIRE]; pOutput = "fire mana"; } else if( !str_prefix( "spirit", argument ) ) { pAbility = &ch->max_mana[MAGIC_SPIRIT]; pOutput = "spirit mana"; } else if( !str_prefix( "water", argument ) ) { pAbility = &ch->max_mana[MAGIC_WATER]; pOutput = "water mana"; } else { send_to_char( "Syntax: train mana <element>\n\r" "Air, Earth, Fire, Spirit and Water.\n\r", ch ); return; } } else if( !str_cmp( argument, "move" ) ) { cost = 10; bone_flag = -1; pAbility = &ch->max_move; pOutput = "move points"; } /* -------------------------------------------- */ else { if( mob ) act( "&c$N looks you over thoughtfully, judging your worth.", ch, NULL, mob, TO_CHAR ); charprintf( ch, "&gYou have &c%d&g practice sessions.\n\r", ch->practice ); send_to_char( "&bStat ( current ) Cost to train\n\r", ch ); cost = ch->pcdata->perm_str - 15 - race_table[ch->race].str_mod; charprintf( ch, "&bStrength ( &c%3d&b ) &r%d\n\r", ch->pcdata->perm_str, ( class_table[ch->class].attr_prime == APPLY_STR ) ? power( 300, 50, cost - 1 ) : power( 300, 50, cost ) ); cost = ch->pcdata->perm_int - 15 - race_table[ch->race].int_mod; charprintf( ch, "&bIntelligence( &c%3d&b ) &r%d\n\r", ch->pcdata->perm_int, ( class_table[ch->class].attr_prime == APPLY_INT ) ? power( 300, 50, cost - 1 ) : power( 300, 50, cost ) ); cost = ch->pcdata->perm_wis - 15 - race_table[ch->race].wis_mod; charprintf( ch, "&bWisdom ( &c%3d&b ) &r%d\n\r", ch->pcdata->perm_wis, ( class_table[ch->class].attr_prime == APPLY_WIS ) ? power( 300, 50, cost - 1 ) : power( 300, 50, cost ) ); cost = ch->pcdata->perm_dex - 15 - race_table[ch->race].dex_mod; charprintf( ch, "&bDexterity ( &c%3d&b ) &r%d\n\r", ch->pcdata->perm_dex, ( class_table[ch->class].attr_prime == APPLY_DEX ) ? power( 300, 50, cost - 1 ) : power( 300, 50, cost ) ); cost = ch->pcdata->perm_con - 15 - race_table[ch->race].con_mod; charprintf( ch, "&bConstitution( &c%3d&b ) &r%d\n\r", ch->pcdata->perm_con, ( class_table[ch->class].attr_prime == APPLY_CON ) ? power( 300, 50, cost - 1 ) : power( 300, 50, cost ) ); send_to_char( "&gMagic:\n\r", ch ); charprintf( ch, " &cAir &b( &c%3d&b ) &r250\n\r", ch->pcdata->perm_magic[MAGIC_AIR] ); charprintf( ch, " &yEarth &b( &c%3d&b ) &r250\n\r", ch->pcdata->perm_magic[MAGIC_EARTH] ); charprintf( ch, " &rFire &b( &c%3d&b ) &r250\n\r", ch->pcdata->perm_magic[MAGIC_FIRE] ); charprintf( ch, " &wSpirit &b( &c%3d&b ) &r250\n\r", ch->pcdata->perm_magic[MAGIC_SPIRIT] ); charprintf( ch, " &bWater &b( &c%3d&b ) &r250\n\r", ch->pcdata->perm_magic[MAGIC_WATER] ); charprintf( ch, "&yhp: &r%2d&y mana: &r%2d&y move: &r10&n\n\r", 15 + class_table[ch->class].fMana, 25 - class_table[ch->class].fMana ); return; } if( bone_flag == 0 ) cost = power( 300, 50, cost ); if( cost > ch->practice ) { send_to_char( "&rYou don't have enough practices.&n\n\r", ch ); return; } ch->practice -= cost; if( bone_flag == 0 ) /* standard stat train */ *pAbility += 1; else if( bone_flag == -1 ) /* train hps or moves */ *pAbility += number_fuzzy( 2 ); else if( bone_flag == -2 ) /* train mana */ *pAbility += dice( 2, 6 ) + 8; else /* train magic */ { bone_flag--; *pAbility += 1; ch->max_mana[bone_flag] += dice( 2, 6 ) + 18; } if( bone_flag >= 0 ) { act( "&gYour &y$T&g increases!&n", ch, NULL, pOutput, TO_CHAR ); act( "&g$n's &y$T&g increases!&n", ch, NULL, pOutput, TO_ROOM ); } else { act( "&gYour &y$T&g increase!&n", ch, NULL, pOutput, TO_CHAR ); act( "&g$n's &y$T&g increase!&n", ch, NULL, pOutput, TO_ROOM ); } return; } void do_chameleon( CHAR_DATA *ch, const char *argument ) { if( !IS_NPC( ch ) && !can_use( ch, gsn_chameleon ) ) { bad_command( ch ); return; } send_to_char( "You attempt to blend in with your surroundings.\n\r", ch ); if( IS_AFFECTED( ch, AFF_HIDE ) ) xREMOVE_BIT( ch->affected_by, AFF_HIDE ); if( IS_NPC( ch ) || get_success( ch, gsn_chameleon, 100 ) ) xSET_BIT( ch->affected_by, AFF_HIDE ); return; } void do_heighten( CHAR_DATA *ch, const char *argument ) { AFFECT_DATA af; if( !IS_NPC( ch ) && !can_use( ch, gsn_heighten ) ) { bad_command( ch ); return; } if( is_affected( ch, gsn_heighten ) ) { send_to_char( "Your senses are allready heightened.\n\r", ch ); return; } if( IS_NPC( ch ) || get_success( ch, gsn_heighten, 100 ) ) { af.type = gsn_heighten; af.level = 0; af.duration = 24; af.modifier = 0; af.location = APPLY_NONE; vset( af.bitvector, AFF_DETECT_INVIS ); xSET_BIT( af.bitvector, AFF_DETECT_HIDDEN ); xSET_BIT( af.bitvector, AFF_INFRARED ); affect_to_char( ch, &af, NULL ); send_to_char( "Your senses are heightened.\n\r", ch ); } else send_to_char( "You fail to heighten your senses.\n\r", ch ); return; } /* * Bash code by Thelonius for EnvyMud ( originally bash_door ) * Damage modified using Morpheus's code * Message for bashproof doors by that wacky guy Kahn */ void do_bash( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *gch; char arg[MAX_INPUT_LENGTH]; int door; if( IS_NPC( ch ) || ( !IS_NPC( ch ) && !can_use( ch, gsn_bash ) ) ) { send_to_char( "You're not enough of a warrior 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( ch->fighting ) { send_to_char( "You can't break off your fight.\n\r", ch ); return; } if( ( door = find_door( ch, arg ) ) >= 0 ) { ROOM_INDEX_DATA *to_room; EXIT_DATA *pexit; EXIT_DATA *pexit_rev; int chance; pexit = ch->in_room->exit[door]; if( !IS_SET( pexit->exit_info, EX_CLOSED ) ) { send_to_char( "Calm down. It is already open.\n\r", ch ); return; } WAIT_STATE( ch, skill_table[gsn_bash].beats ); if( !IS_NPC( ch ) ) chance = get_success( ch, gsn_bash, 200 ) / 2; else chance = 0; if( IS_SET( pexit->exit_info, EX_LOCKED ) ) chance /= 2; if( IS_SET( pexit->exit_info, EX_BASHPROOF ) ) { act( "WHAAAAM!!! You bash against the $d, but it doesn't budge.", ch, NULL, pexit->keyword, TO_CHAR ); act( "WHAAAAM!!! $n bashes against the $d, but it holds strong.", ch, NULL, pexit->keyword, TO_ROOM ); damage( ch, ch, ( ch->max_hit / 5 ), gsn_bash, WEAR_NONE ); return; } if( ( get_curr_str( ch ) >= 20 ) && number_percent( ) < ( chance + 4 * ( get_curr_str( ch ) - 20 ) ) ) { /* Success */ REMOVE_BIT( pexit->exit_info, EX_CLOSED ); if( IS_SET( pexit->exit_info, EX_LOCKED ) ) REMOVE_BIT( pexit->exit_info, EX_LOCKED ); SET_BIT( pexit->exit_info, EX_BASHED ); act( "Crash! You bashed open the $d!", ch, NULL, pexit->keyword, TO_CHAR ); act( "$n bashes open the $d!", ch, NULL, pexit->keyword, TO_ROOM ); damage( ch, ch, ( ch->max_hit / 20 ), gsn_bash, WEAR_NONE ); /* Bash through the other side */ if( ( to_room = pexit->to_room ) && ( pexit_rev = to_room->exit[rev_dir[door]] ) && 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 ); SET_BIT( pexit_rev->exit_info, EX_BASHED ); for( rch = to_room->people; rch; rch = rch->next_in_room ) { if( rch->deleted ) continue; act( "The $d crashes open!", rch, NULL, pexit_rev->keyword, TO_CHAR ); } } } else { /* Failure */ act( "OW! You bash against the $d, but it doesn't budge.", ch, NULL, pexit->keyword, TO_CHAR ); act( "$n bashes against the $d, but it holds strong.", ch, NULL, pexit->keyword, TO_ROOM ); damage( ch, ch, ( ch->max_hit / 10 ), gsn_bash, WEAR_NONE ); } } /* * Check for "guards"... anyone bashing a door is considered as * a potential aggressor, and there's a 25% chance that mobs * will do unto before being done unto. * But first...let's make sure ch ain't dead? That'd be a pain. */ if( ch->deleted || ch->hit <= 1 ) return; for( gch = ch->in_room->people; gch; gch = gch->next_in_room ) { if( !gch->deleted && gch != ch && IS_AWAKE( gch ) && !gch->fighting && can_see( gch, ch ) && IS_NPC( gch ) && !IS_AFFECTED( gch, AFF_CHARM ) && ( ch->level - gch->level <= 4 ) && number_bits( 2 ) == 0 ) multi_hit( gch, ch, TYPE_UNDEFINED ); } return; } /* * Snare skill by Binky for EnvyMud */ void do_snare( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *victim; AFFECT_DATA af; char arg[MAX_INPUT_LENGTH]; one_argument( argument, arg ); /* * First, this checks for case of no second argument (valid only * while fighting already). Later, if an argument is given, it * checks validity of argument. Unsuccessful snares flow through * and receive messages at the end of the function. */ if( arg[0] == '\0' ) { if( !( victim = ch->fighting ) ) { send_to_char( "Ensnare whom?\n\r", ch ); return; } /* No argument, but already fighting: valid use of snare */ WAIT_STATE( ch, skill_table[gsn_snare].beats ); /* Only appropriately skilled PCs and uncharmed mobs */ if( ( IS_NPC( ch ) && !IS_AFFECTED( ch, AFF_CHARM ) ) || ( !IS_NPC( ch ) && number_percent( ) < ch->pcdata->learned[gsn_snare] ) ) { affect_strip( victim, gsn_snare ); af.type = gsn_snare; af.level = 0; af.duration = 1 + ( ( ch->level ) / 8 ); af.location = APPLY_NONE; af.modifier = 0; vset( af.bitvector, AFF_HOLD ); affect_to_char( victim, &af, NULL ); act( "You have ensnared $M!", ch, NULL, victim, TO_CHAR ); act( "$n has ensnared you!", ch, NULL, victim, TO_VICT ); act( "$n has ensnared $N.", ch, NULL, victim, TO_NOTVICT ); } else { act( "You failed to ensnare $M. Uh oh!", ch, NULL, victim, TO_CHAR ); act( "$n tried to ensnare you! Get $m!", ch, NULL, victim, TO_VICT ); act( "$n attempted to ensnare $N, but failed!", ch, NULL, victim, TO_NOTVICT ); } } else /* argument supplied */ { if( !( victim = get_char_room( ch, arg ) ) ) { send_to_char( "They aren't here.\n\r", ch ); return; } if( !IS_NPC( ch ) && !IS_NPC( victim ) ) { send_to_char( "You can't ensnare another player.\n\r", ch ); return; } if( victim != ch->fighting ) /* TRUE if not fighting, or fighting */ { /* if person other than victim */ if( ch->fighting ) /* TRUE if fighting other than vict. */ { send_to_char( "Take care of the person you are fighting first!\n\r", ch ); return; } WAIT_STATE( ch, skill_table[gsn_snare].beats ); /* here, arg supplied, ch not fighting */ /* only appropriately skilled PCs and uncharmed mobs */ if( ( IS_NPC( ch ) && !IS_AFFECTED( ch, AFF_CHARM ) ) || ( !IS_NPC( ch ) && get_success( ch, gsn_snare, 100 ) ) ) { affect_strip( victim, gsn_snare ); af.type = gsn_snare; af.level = 0; af.duration = 3 + ( ( ch->level ) / 8 ); af.location = APPLY_NONE; af.modifier = 0; vset( af.bitvector, AFF_HOLD ); affect_to_char( victim, &af, NULL ); act( "You have ensnared $M!", ch, NULL, victim, TO_CHAR ); act( "$n has ensnared you!", ch, NULL, victim, TO_VICT ); act( "$n has ensnared $N.", ch, NULL, victim, TO_NOTVICT ); } else { act( "You failed to ensnare $M. Uh oh!", ch, NULL, victim, TO_CHAR ); act( "$n tried to ensnare you! Get $m!", ch, NULL, victim, TO_VICT ); act( "$n attempted to ensnare $N, but failed!", ch, NULL, victim, TO_NOTVICT ); } if( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) ) { /* go for the one who wanted to fight : ) */ multi_hit( victim, ch->master, TYPE_UNDEFINED ); } else { multi_hit( victim, ch, TYPE_UNDEFINED ); } } else { /* we are already fighting the intended victim */ WAIT_STATE( ch, skill_table[gsn_snare].beats ); /* charmed mobs not allowed to do this */ if( ( IS_NPC( ch ) && !IS_AFFECTED( ch, AFF_CHARM ) ) || ( !IS_NPC( ch ) && get_success( ch, gsn_snare, 100 ) ) ) { affect_strip( victim, gsn_snare ); af.type = gsn_snare; af.level = 0; af.duration = 1 + ( ( ch->level ) / 8 ); af.location = APPLY_NONE; af.modifier = 0; vset( af.bitvector, AFF_HOLD ); affect_to_char( victim, &af, NULL ); act( "You have ensnared $M!", ch, NULL, victim, TO_CHAR ); act( "$n has ensnared you!", ch, NULL, victim, TO_VICT ); act( "$n has ensnared $N.", ch, NULL, victim, TO_NOTVICT ); } else { act( "You failed to ensnare $M. Uh oh!", ch, NULL, victim, TO_CHAR ); act( "$n tried to ensnare you! Get $m!", ch, NULL, victim, TO_VICT ); act( "$n attempted to ensnare $N, but failed!", ch, NULL, victim, TO_NOTVICT ); } } } return; } /* * Untangle by Thelonius for EnvyMud */ void do_untangle( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *victim; char arg[MAX_INPUT_LENGTH]; if( !IS_NPC( ch ) && !can_use( ch, gsn_untangle ) ) { send_to_char( "You aren't nimble enough.\n\r", ch ); return; } one_argument( argument, arg ); if( arg[0] == '\0' ) victim = ch; else if( !( victim = get_char_room( ch, arg ) ) ) { send_to_char( "They aren't here.\n\r", ch ); return; } if( !IS_AFFECTED( victim, AFF_HOLD ) ) { send_to_char( "They don't seem to be stuck at all.\n\r", ch ); return; } if( ( IS_NPC( ch ) && !IS_AFFECTED( ch, AFF_CHARM ) ) || ( !IS_NPC( ch ) && get_success( ch, gsn_untangle, 100 ) ) ) { affect_strip( victim, gsn_snare ); affect_strip( victim, gsn_strangle ); affect_strip( victim, gsn_web ); xREMOVE_BIT( victim->affected_by, AFF_HOLD ); if( victim != ch ) act( "$n untangle$% $n.", ch, NULL, victim, TO_ALL ); else act( "$n untangle$% $mself.", ch, NULL, NULL, TO_ALL ); } else { send_to_char( "You fail to free them from the tangle.\n\r", ch ); } } /* * Menu for all game functions. * Thelonius (Monk) 5/94 * * Removed for Daleken, there are improved versions available, * we should use those instead. */ void do_setmin( CHAR_DATA *ch, const char *argument ) { char buf[MAX_INPUT_LENGTH]; if( IS_NPC( ch ) ) return; if( !str_cmp( argument, "clear" ) || !str_cmp( argument, "reset" ) || !str_cmp( argument, "none" ) ) { free_string( ch->pcdata->setmin ); ch->pcdata->setmin = &str_empty[0]; } else if( argument[0] != '\0' ) { strcpy( buf, argument ); free_string( ch->pcdata->setmin ); ch->pcdata->setmin = str_dup( buf ); } send_to_char( "Your setmin is now set as:\n\r", ch ); sprintf( buf, " %s %s <direction>.\n\r", ch->name, ch->pcdata->setmin ); send_to_char( buf, ch ); return; } void do_setmout( CHAR_DATA *ch, const char *argument ) { char buf[MAX_INPUT_LENGTH]; if( IS_NPC( ch ) ) return; if( !str_cmp( argument, "clear" ) || !str_cmp( argument, "reset" ) || !str_cmp( argument, "none" ) ) { free_string( ch->pcdata->setmout ); ch->pcdata->setmout = &str_empty[0]; } else if( argument[0] != '\0' ) { strcpy( buf, argument ); free_string( ch->pcdata->setmout ); ch->pcdata->setmout = str_dup( buf ); } send_to_char( "Your setmout is now set as:\n\r", ch ); sprintf( buf, " %s %s <direction>.\n\r", ch->name, ch->pcdata->setmout ); send_to_char( buf, ch ); return; } void do_enter( CHAR_DATA *ch, const char *argument ) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; ROOM_INDEX_DATA *room_to; int num_found = 0; int which; which = number_argument( argument, arg ); for( obj = ch->in_room->contents; obj && num_found < which; obj = obj->next_content ) { if( obj->item_type == ITEM_PORTAL && is_obj_name( obj, arg ) ) { if( ++num_found == which ) break; } } if( !obj ) { for( obj = ch->carrying; obj && num_found < which; obj = obj->next_content ) { if( obj->item_type == ITEM_PORTAL && is_obj_name( obj, arg ) ) { if( ++num_found == which ) break; } } } if( num_found != which ) { send_to_char( "Sorry that isn't here.\n\r", ch ); return; } /* enter the portal */ room_to = get_room_index( obj->value[0] ); if( !room_to ) { send_to_char( "Sorry that isn't a real portal.\n\r", ch ); return; } if( room_is_private( room_to ) ) { send_to_char( "That room is private at the moment.\n\r", ch ); return; } if( ( room_to->area->plane->min_level > get_trust( ch ) || ( !IS_NPC( ch ) && IS_SET( room_to->area->area_flags, AREA_HIDE ) ) ) && !IS_BUILDER( ch, room_to->area ) ) { send_to_char( "&rYou would be ripped to shreds if you entered that!&n\n\r", ch ); return; } if( obj->action && obj->action[0] != '\0' ) send_to_char( obj->action, ch ); act( "$n disappears into $p.", ch, obj, NULL, TO_ROOM ); char_from_room( ch ); char_to_room( ch, room_to ); act( "The world turns inside out as $n steps from $p.", ch, obj, NULL, TO_ROOM ); if( ch->desc ) do_look( ch, AUTOLOOK ); return; } #define TRACK_ERROR -1 #define TRACK_ALLREADY_THERE -2 #define TOROOM( x, y ) ( ( x )->exit[( y )]->to_room ) TRACK_DATA *track_top = NULL, *track_bottom = NULL; /* Tracking coded by Symposium based on CircleMUD BFS. */ void do_track( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *target, *wch; char arg[MAX_INPUT_LENGTH]; int direction; int number; int count; if( argument[0] == '\0' ) { send_to_char( "Track whom?\n\r", ch ); return; } /* since we can only track characters that are in the same area we have to use a slightly modified get_char_world so that we don't end up counting all those mobiles that aren't trackable --Symposium */ if( !( target = get_char_room( ch, argument ) ) ) { target = NULL; number = number_argument( argument, arg ); count = 0; for( wch = char_list; wch; wch = wch->next ) { if( wch->deleted || !can_see( ch, wch ) || !is_char_name( wch, arg ) ) continue; if( wch->in_room && wch->in_room->area && wch->in_room->area != ch->in_room->area ) continue; if( ++count == number ) { target = wch; break; } } } if( !target || ( target->in_room->area != ch->in_room->area ) || !get_success( ch, gsn_track, 100 ) ) { send_to_char( "You can't seem to find a trail from here.\n\r", ch ); ch->tracking = NULL; return; } if( target->in_room == ch->in_room ) { send_to_char( "They are right in this room, don't strain yourself.\n\r", ch ); ch->tracking = NULL; return; } ch->tracking = target; direction = find_first_step( ch->in_room, ch->tracking->in_room ); clear_track_marks( ch->in_room ); switch( direction ) { case TRACK_ERROR: send_to_char( "The trail goes cold and you lose track of your quarry.\n\r", ch ); ch->tracking = NULL; break; case TRACK_ALLREADY_THERE: send_to_char( "&YYou have found your quarry!&n\n\r", ch ); ch->tracking = NULL; break; default: act( "&yYou sense your quarry's trail to the $t.&n", ch, dir_name[direction], NULL, TO_CHAR ); } return; } /* automatic tracking called when you autolook */ void auto_track( CHAR_DATA *ch ) { int direction; if( !ch->tracking || ch->tracking->deleted ) return; if( ch->tracking->in_room == ch->in_room ) { send_to_char( "&YYou have found your quarry!&n\n\r", ch ); ch->tracking = NULL; return; } if( ( ch->tracking->in_room->area != ch->in_room->area ) || !get_success( ch, gsn_track, 110 ) ) { send_to_char( "The trail goes cold and you lose track of your quarry.\n\r", ch ); ch->tracking = NULL; return; } direction = find_first_step( ch->in_room, ch->tracking->in_room ); clear_track_marks( ch->in_room ); switch( direction ) { case TRACK_ERROR: send_to_char( "The trail goes cold and you lose track of your quarry.\n\r", ch ); ch->tracking = NULL; break; case TRACK_ALLREADY_THERE: send_to_char( "&YYou have found your quarry!&n\n\r", ch ); ch->tracking = NULL; break; default: act( "&yYou sense your quarry's trail to the $t.&n", ch, dir_name[direction], NULL, TO_CHAR ); } return; } void add_track_q( ROOM_INDEX_DATA *room, int dir ) { TRACK_DATA *curr; curr = (TRACK_DATA *)alloc_mem( sizeof( *curr ) ); curr->room = room; curr->dir = dir; curr->next = NULL; if( track_bottom ) { track_bottom->next = curr; track_bottom = curr; } else track_top = track_bottom = curr; return; } void remove_track_q( void ) { TRACK_DATA *curr; curr = track_top; if( !( track_top = track_top->next ) ) track_bottom = NULL; free_mem( (void *)curr, sizeof( curr ) ); return; } void clean_track_q( void ) { while( track_top ) remove_track_q( ); return; } int find_first_step( ROOM_INDEX_DATA *start, ROOM_INDEX_DATA *target ) { int curr_dir; if( start == NULL || target == NULL ) { bug( "Illegal value passed to find_first_step (act_move.c)" ); return TRACK_ERROR; } if( start == target ) return TRACK_ALLREADY_THERE; SET_BIT( start->room_flags, ROOM_TRACK_MARK ); /* first, queue the first steps, saving which direction we're going. */ for( curr_dir = 0; curr_dir < 6; curr_dir++ ) if( start->exit[curr_dir] && start->exit[curr_dir]->to_room && TOROOM( start, curr_dir ) && start->exit[curr_dir] && TOROOM( start, curr_dir )->area == start->area && !IS_SET( TOROOM( start, curr_dir )->room_flags, ROOM_TRACK_MARK ) ) { SET_BIT( TOROOM( start, curr_dir )->room_flags, ROOM_TRACK_MARK ); add_track_q( TOROOM( start, curr_dir ), curr_dir ); } /* now, do the classic BFS. */ while( track_top ) { if( track_top->room == target ) { curr_dir = track_top->dir; clean_track_q( ); return curr_dir; } else /* add all rooms around the current queue head */ { for( curr_dir = 0; curr_dir < 6; ++curr_dir ) if( track_top->room->exit[curr_dir] && track_top->room->exit[curr_dir]->to_room && TOROOM( track_top->room, curr_dir ) && track_top->room->exit[curr_dir] && TOROOM( track_top->room, curr_dir )->area == track_top->room->area && !IS_SET( TOROOM( track_top->room, curr_dir )->room_flags, ROOM_TRACK_MARK ) ) { SET_BIT( TOROOM( track_top->room, curr_dir )->room_flags, ROOM_TRACK_MARK ); add_track_q( TOROOM( track_top->room, curr_dir ), track_top->dir ); } remove_track_q( ); } } return TRACK_ERROR; } /* recursor to remove all marks left by the track routine */ void clear_track_marks( ROOM_INDEX_DATA *start ) { int i; if( start && IS_SET( start->room_flags, ROOM_TRACK_MARK ) ) { REMOVE_BIT( start->room_flags, ROOM_TRACK_MARK ); for( i = 0; i < 6; ++i ) if( start->exit[i] ) clear_track_marks( TOROOM( start, i ) ); } return; } void do_charge( CHAR_DATA *ch, const char *argument ) { CHAR_DATA *target, *next; ROOM_INDEX_DATA *old_room = ch->in_room; int dir, move = 100; if( IS_NPC( ch ) ) return; if( ch->level < LEVEL_HERO && !can_use( ch, gsn_charge ) ) { send_to_char( "Maybe you should learn how first.\n\r", ch ); return; } if( argument[0] == '\0' ) { send_to_char( "Which way to go?\n\r", ch ); return; } if( ch->move < move ) { if( !get_success( ch, gsn_stamina, 100 ) ) { send_to_char( "You are too exhausted.\n\r", ch ); return; } if( ch->hit < ch->max_hit / 3 ) { send_to_char( "Your body is too exhausted, " "your tired muscles will move no more.\n\r", ch ); return; } send_to_char( "You push your tired body past it's limits.\n\r", ch ); move -= ch->move; ch->move = 0; ch->hit -= move; WAIT_STATE( ch, skill_table[gsn_stamina].beats ); } else ch->move -= move; switch( LOWER( argument[0] ) ) { case 'n': dir = DIR_NORTH; break; case 'e': dir = DIR_EAST; break; case 's': dir = DIR_SOUTH; break; case 'w': dir = DIR_WEST; break; case 'u': dir = DIR_UP; break; case 'd': dir = DIR_DOWN; break; default: send_to_char( "Please specify a direction.\n\r", ch ); return; } act( "You charge $t", ch, dir_name[dir], NULL, TO_CHAR ); act( "$n screams a battle cry and charges $t.", ch, dir_name[dir], NULL, TO_ROOM ); interpret( ch, dir_name[dir] ); if( old_room == ch->in_room ) return; act( "$n charges in from the $t.", ch, dir_name[rev_dir[dir]], NULL, TO_ROOM ); if( !get_success( ch, gsn_charge, 100 ) ) { send_to_char( "You lose your nerve.\n\r", ch ); act( "$n starts to charge but loses $s nerve.", ch, NULL, NULL, TO_ROOM ); return; } for( target = ch->in_room->people; target; target = next ) { next = target->next_in_room; if( target->deleted ) continue; if( !IS_NPC( ch ) && !IS_NPC( target ) ) continue; if( is_affected( target, AFF_CHARM ) ) continue; target->position = POS_SMASHED; target->wait = 2 * PULSE_VIOLENCE; multi_hit( ch, target, gsn_charge ); } return; } void do_disable( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; char arg[MAX_INPUT_LENGTH]; int door; int dam, trap; one_argument( argument, arg ); if( arg[0] == '\0' ) { send_to_char( "Disable what?\n\r", ch ); return; } if( ( door = find_door( ch, arg ) ) >= 0 ) { /* 'open door' */ EXIT_DATA *pexit; EXIT_DATA *pexit_rev; ROOM_INDEX_DATA *to_room; pexit = ch->in_room->exit[door]; 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_TRAPPED ) ) { send_to_char( "It's not even trapped.\n\r", ch ); return; } if( get_success( ch, gsn_disable_traps, 60 ) ) { act( "$n disables the trap on the $d.", ch, NULL, pexit->keyword, TO_ROOM ); act( "You disable the trap on the $d.", ch, NULL, pexit->keyword, TO_CHAR ); REMOVE_BIT( pexit->exit_info, EX_TRAPPED ); if( ( to_room = pexit->to_room ) && ( pexit_rev = to_room->exit[rev_dir[door]] ) && pexit_rev->to_room == ch->in_room ) { REMOVE_BIT( pexit_rev->exit_info, EX_TRAPPED ); } } else send_to_char( "Despite your efforts, the trap remains active.\n\r", ch ); trap = number_range( gsn_first_trap, gsn_last_trap ); dam = 4 + ch->level / 2 + ch->hit / 12; if( number_percent( ) < power( ch->pcdata->learned[gsn_disable_traps], 7, get_curr_dex( ch ) - 15 ) ) { act( "A $t shoots out and barely misses $n!", ch, skill_table[trap].noun_damage, NULL, TO_ROOM ); act( "A $t shoots out and barely misses you!", ch, skill_table[trap].noun_damage, NULL, TO_CHAR ); } else { act( "A $t shoots out and strikes $n!", ch, skill_table[trap].noun_damage, NULL, TO_ROOM ); act( "A $t shoots out and strikes you!", ch, skill_table[trap].noun_damage, NULL, TO_CHAR ); damage( ch, ch, dam, trap, WEAR_NONE ); } return; } if( ( obj = get_obj_here( ch, arg ) ) ) { /* 'open 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 already open.\n\r", ch ); return; } if( !IS_SET( obj->value[1], CONT_TRAPPED ) ) { send_to_char( "It's not even trapped.\n\r", ch ); return; } if( get_success( ch, gsn_disable_traps, 60 ) ) { send_to_char( "You remove the trap.\n\r", ch ); REMOVE_BIT( obj->value[1], CONT_TRAPPED ); } else send_to_char( "You fail to remove the trap.\n\r", ch ); dam = 4 + ch->level / 2 + ch->hit / 12; if( number_percent( ) < power( ch->pcdata->learned[gsn_disable_traps], 7, get_curr_dex( ch ) - 15 ) ) { act( "A small dart shoots out and barely misses $n!", ch, NULL, NULL, TO_ROOM ); act( "A small dart shoots out and barely misses you!", ch, NULL, NULL, TO_CHAR ); } else { act( "A small dart shoots out and strikes $n!", ch, NULL, NULL, TO_ROOM ); act( "A small dart shoots out and strikes you!", ch, NULL, NULL, TO_CHAR ); damage( ch, ch, dam, gsn_first_trap, WEAR_NONE ); } return; } act( "You see no $T here.", ch, NULL, arg, TO_CHAR ); return; } void do_meditate( CHAR_DATA *ch, const char *argument ) { if( IS_NPC( ch ) || !can_use( ch, gsn_meditation ) ) { send_to_char( "You lack the ability to meditate.\n\r", ch ); return; } if( ch->position != POS_RESTING && ch->position != POS_SITTING ) { send_to_char( "You must be resting first.\n\r", ch ); return; } act( "$n hums softly in an attempt to find inner peace.", ch, NULL, NULL, TO_ROOM ); send_to_char( "You try to concentrate on nothing...\n\r", ch ); if( get_success( ch, gsn_meditation, 100 ) ) ch->position = POS_MEDITATING; WAIT_STATE( ch, skill_table[gsn_meditation].beats ); return; } void throw_hit( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *thing, int dir ) { char buf[MAX_STRING_LENGTH]; int dam, basic_dam, combat_no; if( victim->position == POS_DEAD ) return; act( "$n is hit by the flying object.", victim, NULL, NULL, TO_ROOM ); send_to_char( "You are hit by the flying object.\n\r", victim ); dam = GET_AC( victim ) - 100; dam += ( get_size( ch ) - get_size( victim ) ) / 2; if( !can_see_obj( victim, thing ) ) dam += 50; if( ch->class == CLASS_NONE ) { combat_no = 400; } else { combat_no = class_table[ch->class].combat_no; } dam = dam * 100 + ch->level * combat_no; dam = UMIN( -1, dam / 100 ); dam += number_range( 0, get_hitroll( ch ) * 6 + 5 ); dam += number_range( 0, ch->level * 4 + 10 ); if( thing->item_type == ITEM_WEAPON ) { basic_dam = number_range( thing->value[1], thing->value[2] ); if( basic_dam > 100000 ) bug( "Throw_hit basic_dam range > 100000 from %d to %d", thing->value[1], thing->value[2] ); if( thing->required_skill > 0 ) basic_dam = basic_dam * 2 / 3; } else { basic_dam = number_range( thing->weight / 2, thing->weight * 3 / 2 ); basic_dam = UMIN( basic_dam, ch->level * 2 ); } if( IS_SET( thing->extra_flags, ITEM_HORNED ) && number_bits( 5 ) == 0 ) basic_dam *= 2; dam = ( dam / 10 ) + basic_dam; dam += get_damroll( ch ) / 10; /* * Now the other bonuses. */ if( thing && IS_SET( thing->extra_flags, ITEM_CHARGED ) ) { if( ch->level < L_SEN ) REMOVE_BIT( thing->extra_flags, ITEM_CHARGED ); dam += dam * get_curr_int( ch ) / 10; } if( dam < 0 ) dam = 0; /* * Hit them now then quickly stop the fight. */ damage( ch, victim, dam, gsn_throw_weapon, WEAR_NONE ); if( victim->deleted || victim->position == POS_DEAD ) return; stop_fighting( ch, FALSE ); stop_fighting( victim, FALSE ); if( IS_NPC( ch ) || !can_see( victim, ch ) ) { do_yell( victim, "Who threw that!" ); return; } sprintf( buf, "I saw you throw that, %s!", ch->name ); do_yell( victim, buf ); if( IS_NPC( victim ) && !victim->fighting && victim->position != POS_DEAD ) { if( xIS_SET( victim->act, ACT_SENTINEL ) ) { obj_from_room( thing ); obj_to_char( thing, victim ); sprintf( buf, "'%s' %s", thing->name, dir_name[dir] ); do_throw( victim, buf ); } else { if( number_bits( 2 ) == 0 ) { obj_from_room( thing ); obj_to_char( thing, victim ); act( "$n picks up $p and runs $T.", victim, thing, dir_name[dir], TO_ROOM ); } else act( "$n screams and runs $T.", victim, thing, dir_name[dir], TO_ROOM ); strcpy( buf, dir_name[dir] ); interpret( victim, buf ); if( victim->in_room == ch->in_room ) { act( "$N has just arrived and $E is not happy.", ch, NULL, victim, TO_CHAR ); act( "$N has arrived and $E is after $n with a vengeance.", ch, NULL, victim, TO_ROOM ); multi_hit( victim, ch, TYPE_UNDEFINED ); } else { sprintf( buf, "Hey %s, where did you go?", ch->name ); do_yell( victim, buf ); } } } return; } void do_throw( CHAR_DATA *ch, const char *argument ) { OBJ_DATA *obj; CHAR_DATA *target, *victim = NULL; EXIT_DATA *pexit; char arg[MAX_INPUT_LENGTH]; int number; int dir; char buf[MAX_INPUT_LENGTH]; /* Throwing people around is handled in fight.c */ if( throw( ch, argument ) ) return; argument = one_argument( argument, arg ); if( arg[0] == '\0' ) { send_to_char( "Throw what or who?\n\r", ch ); return; } if( ch->fighting ) { send_to_char( "No way!\n\r", ch ); return; } if( !str_cmp( arg, "all" ) ) { send_to_char( "You can't throw everything at once.\n\r", ch ); return; } if( !( obj = get_obj_carry( ch, arg ) ) ) { send_to_char( "You do not have that item.\n\r", ch ); return; } if( !can_drop_obj( ch, obj ) ) { send_to_char( "You can't let go of it.\n\r", ch ); return; } switch( LOWER( argument[0] ) ) { case 'n': dir = DIR_NORTH; pexit = ch->in_room->exit[DIR_NORTH]; break; case 'e': dir = DIR_EAST; pexit = ch->in_room->exit[DIR_EAST]; break; case 's': dir = DIR_SOUTH; pexit = ch->in_room->exit[DIR_SOUTH]; break; case 'w': dir = DIR_WEST; pexit = ch->in_room->exit[DIR_WEST]; break; case 'u': dir = DIR_UP; pexit = ch->in_room->exit[DIR_UP]; break; case 'd': dir = DIR_DOWN; pexit = ch->in_room->exit[DIR_DOWN]; break; default: send_to_char( "Which way was that?\n\r", ch ); return; } /* change the constant here to whatever you think best */ number = str_app_wield( get_curr_str( ch ) ) - get_obj_weight( obj ); number *= get_success( ch, gsn_throw_weapon, 100 ); number /= get_obj_weight( obj ); if( obj->item_type == ITEM_WEAPON ) number += str_app_wield( get_curr_str( ch ) ); number += number_percent(); obj_from_char( obj ); if( number < 0 ) { send_to_char( "You try to throw it, but it's too heavy to throw.\n\r", ch ); act( "$n tries to throw $p but $e fumbles and drops it.\n\r", ch, obj, NULL, TO_ROOM ); obj_to_room( obj, ch->in_room ); return; } act( "$n throw$% $p $T.", ch, obj, dir_name[dir], TO_ALL ); if( !pexit ) { act( "$p thuds into the wall.", ch, obj, NULL, TO_ROOM ); act( "$p thuds into the wall.", ch, obj, NULL, TO_CHAR ); obj_to_room( obj, ch->in_room ); if( obj->item_type == ITEM_EXPLOSIVE ) explode( obj ); return; } if( IS_SET( pexit->exit_info, EX_CLOSED ) ) { act( "$p thuds into a door.", ch, obj, NULL, TO_ROOM ); act( "$p thuds into a door.", ch, obj, NULL, TO_CHAR ); obj_to_room( obj, ch->in_room ); if( obj->item_type == ITEM_EXPLOSIVE ) explode( obj ); return; } obj_to_room( obj, pexit->to_room ); sprintf( buf, "%s flys in from the %s and lands at your feet.\n\r", capitalize( obj->short_descr ), dir_name[rev_dir[dir]] ); send_to_room( buf, pexit->to_room ); if( obj->item_type == ITEM_EXPLOSIVE ) { explode( obj ); return; } number = 0; for( target = pexit->to_room->people; target; target = target->next_in_room ) { if( !is_safe( target, ch ) && number_range( 0, number++ ) == 0 ) victim = target; } if( victim ) throw_hit( ch, victim, obj, rev_dir[dir] ); return; } void sink( CHAR_DATA *ch ) { ROOM_INDEX_DATA *toroom; OBJ_DATA *boat; if( ch->in_room->sector_type != SECT_WATER_SWIM && ch->in_room->sector_type != SECT_WATER_NOSWIM && ch->in_room->sector_type != SECT_UNDERWATER && !IS_SET( ch->in_room->room_flags, ROOM_FLOODED ) ) return; for( boat = ch->carrying; boat; boat = boat->next_content ) { if( !boat->deleted && boat->item_type == ITEM_BOAT ) break; } if( !ch->in_room->exit[boat ? DIR_UP : DIR_DOWN] || !( toroom = ch->in_room->exit[boat ? DIR_UP : DIR_DOWN]->to_room ) ) return; if( toroom->sector_type != SECT_WATER_SWIM && toroom->sector_type != SECT_WATER_NOSWIM && toroom->sector_type != SECT_UNDERWATER && !IS_SET( toroom->room_flags, ROOM_FLOODED ) ) return; if( boat ) { act( "&bYour boat forces you to float higher in the water.", ch, NULL, NULL, TO_CHAR ); act( "&b$n floats up, bouyed by $s boat.", ch, NULL, NULL, TO_ROOM ); } else act( "&b$n slowly sink$% in the water.", ch, NULL, NULL, TO_ALL ); char_from_room( ch ); char_to_room( ch, toroom ); if( boat ) act( "&b$n has bobbed up from below.", ch, NULL, NULL, TO_ROOM ); else act( "&b$n has drifted in from above.", ch, NULL, NULL, TO_ROOM ); do_look( ch, AUTOLOOK ); return; } void found_prey( CHAR_DATA *ch, CHAR_DATA *victim ) { char buf [ MAX_STRING_LENGTH ]; char victname [ MAX_INPUT_LENGTH ]; if( !victim || victim->deleted ) { bug( "Found_prey: null victim" ); return; } if( !victim->in_room ) { bug( "Found_prey: null victim->in_room" ); return; } sprintf( victname, ( victim->short_descr && victim->short_descr[0] ) ? victim->short_descr : victim->name ); if( !can_see( ch, victim ) ) { if( number_percent( ) < 90 ) return; switch( number_bits( 2 ) ) { case 0: sprintf( buf, "Don't make me find you, %s!", victname ); do_say( ch, buf ); break; case 1: act( "$n sniffs around the room for $N.", ch, NULL, victim, TO_CANSEE ); do_say( ch, "I can smell your blood!" ); break; case 2: sprintf( buf, "I'm going to tear %s apart!", victname ); do_yell( ch, buf ); break; case 3: do_say( ch, "Just wait until I find you..." ); break; } return; } if( IS_SET( ch->in_room->room_flags, ROOM_SAFE ) ) { if( number_bits( 3 ) ) return; switch( number_bits( 2 ) ) { case 0: do_say( ch, "C'mon out, you coward!" ); sprintf( buf, "%s is a bloody coward!", victname ); do_yell( ch, buf ); break; case 1: sprintf( buf, "Let's take this outside, %s", victname ); do_say( ch, buf ); break; case 2: sprintf( buf, "%s is a yellow-bellied wimp!", victname ); do_yell( ch, buf ); break; case 3: act( "$n take$% a few swipes at $N.", ch, NULL, victim, TO_ALL ); break; } return; } switch( number_bits( 2 ) ) { case 0: sprintf( buf, "Your blood is mine, %s!", victname ); do_yell( ch, buf); break; case 1: sprintf( buf, "Alas, we meet again, %s!", victname ); do_say( ch, buf ); break; case 2: sprintf( buf, "What do you want on your tombstone, %s?", victname ); do_say( ch, buf ); break; case 3: act( "$n lunges at $N from out of nowhere!", ch, NULL, victim, TO_ROOM ); act( "You lunge at $N catching $M off guard!", ch, NULL, victim, TO_CHAR ); break; } ch->tracking = NULL; multi_hit( ch, victim, TYPE_UNDEFINED ); return; } /* Mobs can now track a character that has fled. * This means they follow them and there is a greater chance that * they will attack them -Symposium * Returns true when the hunt needs to continue. */ bool mob_track_update( CHAR_DATA *ch ) { int direction; if( xIS_SET( ch->act, ACT_SENTINEL ) || !xIS_SET( ch->act, ACT_HUNTER ) || !can_see( ch, ch->tracking ) ) { ch->tracking = NULL; return FALSE; } /* if( IS_AFFECTED( ch, AFF_BLEEDING ) || ch->hit < ch->tracking->hit ) { if( ch->tracking->in_room == ch->in_room ) do_flee( ch, "" ); return TRUE; } */ if( ch->in_room == ch->tracking->in_room ) { if( ch->fighting ) return FALSE; found_prey( ch, ch->tracking ); return FALSE; } act( "$n carefully sniffs the air.", ch, NULL, NULL, TO_CANSEE ); if( number_percent( ) < 30 - URANGE( -25, ch->level + ch->tracking->level, 25 ) ) { act( "$n loses track of $s quarry.", ch, NULL, NULL, TO_CANSEE ); ch->tracking = NULL; return FALSE; } direction = find_first_step( ch->in_room, ch->tracking->in_room ); clear_track_marks( ch->in_room ); if( IS_SET( ch->in_room->exit[direction]->exit_info, EX_CLOSED ) ) { do_open( ch, dir_name[direction] ); return TRUE; } switch( direction ) { case TRACK_ERROR: act( "$n loses track of $s quarry.", ch, NULL, NULL, TO_CANSEE ); ch->tracking = NULL; return FALSE; case TRACK_ALLREADY_THERE: if( ch->tracking && ch->in_room == ch->tracking->in_room ) found_prey( ch, ch->tracking ); ch->tracking = NULL; return FALSE; default: move_char( ch, direction ); break; } return TRUE; } void do_push_drag( CHAR_DATA *ch, const char *argument, const char *verb ) { char arg1[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; ROOM_INDEX_DATA *in_room; ROOM_INDEX_DATA *to_room; CHAR_DATA *victim; EXIT_DATA *pexit; OBJ_DATA *obj; int door; argument = one_argument( argument, arg1 ); victim = get_char_room( ch, arg1 ); obj = get_obj_list( ch, arg1, ch->in_room->contents ); if( arg1[0] == '\0' || argument[0] == '\0' ) { sprintf( buf, "%s whom or what where?\n\r", capitalize( verb ) ); send_to_char( buf, ch ); return; } if( ( !victim || !can_see( ch,victim ) ) && ( !obj || !can_see_obj( ch,obj ) ) ) { sprintf( buf,"%s whom or what where?\n\r", capitalize( verb ) ); send_to_char( buf, ch ); return; } if( !str_prefix( argument, "north" ) ) door = 0; else if( !str_prefix( argument, "east" ) ) door = 1; else if( !str_prefix( argument, "south" ) ) door = 2; else if( !str_prefix( argument, "west" ) ) door = 3; else if( !str_prefix( argument, "up" ) ) door = 4; else if( !str_prefix( argument, "down" ) ) door = 5; else { sprintf( buf, "Alas, you cannot %s in that direction.\n\r", verb ); send_to_char( buf, ch ); return; } if( obj ) { in_room = obj->in_room; if( ( pexit = in_room->exit[door] ) == NULL || ( to_room = pexit->to_room ) == NULL ) { sprintf( buf, "Alas, you cannot %s in that direction.\n\r", verb ); send_to_char( buf, ch ); return; } if( !IS_IMMORTAL( ch ) && ( IS_SET( ch->in_room->room_flags, ROOM_SAFE ) || IS_SET( ch->in_room->room_flags, ROOM_PRIVATE ) || IS_SET( ch->in_room->room_flags, ROOM_SOLITARY ) || IS_SET( ch->in_room->room_flags, ROOM_NO_RECALL ) || number_percent() > 75 || !IS_SET( obj->wear_flags, ITEM_TAKE ) ) ) { send_to_char( "It won't budge.\n\r", ch ); return; } if( IS_SET( pexit->exit_info, EX_CLOSED ) || IS_SET( pexit->exit_info, EX_PASSPROOF ) ) { act( "You cannot $t it through the $d.", ch, verb, pexit->keyword, TO_CHAR ); act( "$n decides to $t $P around!", ch, verb, obj, TO_ROOM ); return; } act( "You attempt to $T $p out of the room.", ch, obj, verb, TO_CHAR ); act( "$n is attempting to $T $p out of the room.", ch, obj, verb, TO_ROOM ); if( obj->weight > ( 2 * can_carry_w( ch ) ) ) { act( "$p is too heavy to $T.\n\r", ch, obj, verb, TO_CHAR); act( "$n attempts to $T $p, but it is too heavy.\n\r", ch, obj, verb, TO_ROOM); return; } if( ch->move > 25 ) { if( !str_cmp( verb, "drag" ) ) move_char( ch, door ); if( ch->in_room == in_room ) return; ch->move -= 25; send_to_char( "You succeed!\n\r", ch ); act( "$n succeeds!", ch, NULL, NULL, TO_ROOM ); obj_from_room( obj ); obj_to_room( obj, to_room ); } else { sprintf( buf, "You are too tired to %s anything around!\n\r", verb ); send_to_char( buf, ch ); } } else { if( ch == victim ) { act( "You $t yourself about the room and look very silly.", ch, verb, NULL, TO_CHAR ); act( "$n decides to be silly and $t $mself about the room.", ch, verb, NULL, TO_ROOM ); return; } in_room = victim->in_room; if( ( pexit = in_room->exit[door] ) == NULL || ( to_room = pexit->to_room ) == NULL ) { sprintf( buf, "Alas, you cannot %s them that way.\n\r", verb ); send_to_char( buf, ch ); return; } if( IS_SET( pexit->exit_info, EX_CLOSED ) && ( !IS_AFFECTED( victim, AFF_PASS_DOOR ) || IS_SET( pexit->exit_info, EX_PASSPROOF ) ) ) { act( "You try to $t them through the $d.", ch, verb, pexit->keyword, TO_CHAR ); act( "$n decides to $t you around!", ch, verb, victim, TO_VICT ); act( "$n decides to $t $N around!", ch, verb, victim, TO_NOTVICT ); return; } act( "You attempt to $t $N out of the room.", ch, verb, victim, TO_CHAR ); act( "$n is attempting to $t you out of the room!", ch, verb, victim, TO_VICT ); act( "$n is attempting to $t $N out of the room.", ch, verb, victim, TO_NOTVICT ); if( !IS_IMMORTAL( ch ) || ( IS_NPC( victim ) && ( xIS_SET( victim->act,ACT_TRAIN ) || xIS_SET( victim->act, ACT_PRACTICE ) || xIS_SET( victim->act, ACT_BANKER ) || victim->pIndexData->pShop ) ) || victim->in_room == NULL || IS_SET( victim->in_room->room_flags, ROOM_SAFE ) || IS_SET( victim->in_room->room_flags, ROOM_PRIVATE ) || IS_SET( victim->in_room->room_flags, ROOM_SOLITARY ) || IS_SET( victim->in_room->room_flags, ROOM_NO_RECALL ) || IS_SET( ch->in_room->room_flags, ROOM_NO_RECALL ) || ( !str_cmp( verb, "drag" ) && victim->position >= POS_STANDING ) || ( !str_cmp( verb, "push" ) && victim->position != POS_STANDING ) || is_safe( ch, victim ) || ( number_bits( 2 ) == 0 ) || victim->level >= ch->level + 5 || ( !IS_NPC( victim ) && victim->level >= LEVEL_HERO ) ) { send_to_char( "They won't budge.\n\r", ch ); return; } if( IS_NPC( victim ) && number_bits( 2 ) == 0 ) { do_say( victim, "Hey don't push me around!" ); multi_hit( victim, ch, TYPE_UNDEFINED ); } else if( ch->move > 25 ) { ch->move -= 25; send_to_char( "You succeed!\n\r", ch ); act( "$n succeeds!", ch, NULL, NULL, TO_ROOM ); if( !str_cmp( verb, "drag" ) ) move_char( ch, door ); move_char( victim, door ); } else { sprintf( buf, "You are too tired to %s anybody around!\n\r", verb ); send_to_char( buf, ch ); } } return; } void do_push( CHAR_DATA *ch, const char *argument ) { do_push_drag( ch, argument, "push" ); return; } void do_drag( CHAR_DATA *ch, const char *argument ) { do_push_drag( ch, argument, "drag" ); return; }