/*___________________________________________________________________________*
)()( 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;
}