/*___________________________________________________________________________*
)()( 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. ||
|| ----------------------------------------------------------------- ||
|| fight.c ||
|| Combat, combat skills and death code. ||
*_/<>\_________________________________________________________________/<>\_*/
#include <math.h>
#include "mud.h"
#include "event.h"
#if !defined( PI )
#define PI 3.14159265358979323846
#endif
/* fight.c functions */
void set_fighting args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
bool disarm args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
void one_hit args( ( CHAR_DATA *ch, CHAR_DATA *victim,
int dt, int wpn ) );
bool check_atemi args( ( CHAR_DATA *ch, CHAR_DATA *victim ) );
CHAR_DATA *find_target( CHAR_DATA *ch, const char *argument,
const char *cmd )
{
CHAR_DATA *victim;
if( ch->fighting )
return ch->fighting;
if( argument == NULL || argument[0] == '\0' )
{
charprintf( ch, "%s whom?\n\r", cmd );
return NULL;
}
if( !check_blind( ch ) )
return NULL;
if( !( victim = get_char_room( ch, argument ) ) )
{
send_to_char( "They aren't here.\n\r", ch );
return NULL;
}
if( !IS_NPC( victim ) )
{
if( ch != victim && !xIS_SET( victim->act, PLR_OUTLAW )
&& !xIS_SET( victim->act, PLR_BATTLE )
&& !IS_SET( ch->in_room->room_flags, ROOM_ARENA )
&& !is_clan_enemy( victim, ch ) )
{
send_to_char( "You must MURDER a player.\n\r", ch );
return NULL;
}
}
else
{
if( IS_AFFECTED( victim, AFF_CHARM ) && victim->master )
{
send_to_char( "You must MURDER a charmed creature.\n\r", ch );
return NULL;
}
}
if( is_safe( ch, victim ) )
return NULL;
if( IS_AFFECTED( ch, AFF_CHARM )
&& ( !IS_NPC( victim ) || ch->master == victim ) )
{
send_to_char( "You lack the self control to attack someone!\n\r", ch );
return NULL;
}
if( ch->fighting && ch->fighting != victim )
{
send_to_char( "You are too busily occupied fighting someone else.\n\r",
ch );
return NULL;
}
check_killer( ch, victim );
return victim;
}
void do_kill( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
if( !( victim = find_target( ch, argument, "Kill" ) ) )
return;
if( ch->fighting )
{
send_to_char( "You do the best you can!\n\r", ch );
return;
}
if( victim == ch )
{
send_to_char( "You hit yourself. Ouch!\n\r", ch );
multi_hit( ch, ch, TYPE_UNDEFINED );
return;
}
WAIT_STATE( ch, PULSE_PER_SECOND );
multi_hit( ch, victim, TYPE_UNDEFINED );
return;
}
/*
* I'm only allowing backstabbing with the primary weapon...immortals
* who wield two weapons, with the first not being a dagger, will be
* unable to backstab or circle. Tough cookie. --- Thelonius
*/
void do_backstab( CHAR_DATA *ch, const char *argument )
{
OBJ_DATA *obj;
CHAR_DATA *victim;
if( !IS_NPC( ch ) && !can_use( ch, gsn_backstab ) )
{
send_to_char(
"You better leave the assassin trade to thieves.\n\r", ch );
return;
}
if( !( victim = find_target( ch, argument, "Backstab" ) ) )
return;
if( victim == ch )
{
send_to_char( "How can you sneak up on yourself?\n\r", ch );
return;
}
if( ( !( obj = get_eq_char( ch, WEAR_WIELD_R ) ) &&
!( obj = get_eq_char( ch, WEAR_WIELD_DOUBLE ) ) )
|| obj->value[3] != 11 )
{
send_to_char( "You need to wield a piercing weapon.\n\r", ch );
return;
}
if( victim->fighting )
{
send_to_char( "You can't backstab a fighting person.\n\r", ch );
return;
}
if( IS_AWAKE( victim ) && victim->hit < victim->max_hit )
{
act( "$N is hurt and suspicious ... you can't sneak up.",
ch, NULL, victim, TO_CHAR );
return;
}
WAIT_STATE( ch, skill_table[gsn_backstab].beats );
if( !IS_AWAKE( victim ) || IS_NPC_CLASS( ch )
|| get_success( ch, gsn_backstab, 100 ) )
{
if( !IS_AWAKE( victim ) )
victim->position = POS_STANDING;
if( check_atemi( ch, victim ) )
multi_hit( ch, victim, gsn_atemi );
else
multi_hit( ch, victim, gsn_backstab );
}
else
damage( ch, victim, 0, gsn_backstab, obj->wear_loc );
return;
}
bool check_atemi( CHAR_DATA *ch, CHAR_DATA *victim )
{
OBJ_DATA *obj;
if( !get_success( ch, gsn_atemi, 100 ) || number_bits( 3 ) != 0 )
return FALSE;
switch( number_bits( 4 ) )
{
default:
break;
case 0:
/* Knock them unconcious for a moment (extra damage later) */
act( "$n crumple$% to the ground.",
victim, NULL, ch, TO_ALL );
victim->position = POS_SLEEPING;
WAIT_STATE( victim, 2 * PULSE_VIOLENCE );
if( IS_NPC( victim ) )
create_char_event( victim, evn_stand_up, 2 * PULSE_VIOLENCE );
return TRUE;
case 1: case 2: case 3:
/* effectively a ram */
send_to_char( "You are stuck from behind and find yourself reeling.\n\r", victim );
act( "$n reels backwards from $O savage blow.",
victim, NULL, ch, TO_ROOM );
victim->position = POS_SMASHED;
WAIT_STATE( victim, 3 * PULSE_VIOLENCE );
if( IS_NPC( victim ) )
create_char_event( victim, evn_stand_up, 3 * PULSE_VIOLENCE );
return TRUE;
case 4: case 5: case 6: case 7:
/* lag the opponent a little, make them get up */
act( "$n is forced to $s knees by $O strike!",
victim, NULL, ch, TO_ALL );
victim->position = POS_GETTING_UP;
WAIT_STATE( victim, PULSE_VIOLENCE );
if( IS_NPC( victim ) )
create_char_event( victim, evn_stand_up, PULSE_VIOLENCE );
return TRUE;
case 8:
/* double backstab with each weapon */
if( !( obj = get_eq_char( ch, WEAR_WIELD_R ) ) )
return FALSE;
if( !( obj = get_eq_char( ch, WEAR_WIELD_L ) )
|| obj->value[3] != 11 )
return FALSE;
act( "$n strike$% $N with each hand, ONE-TWO!",
ch, NULL, victim, TO_ALL );
one_hit( ch, victim, gsn_atemi, WEAR_WIELD_L );
return TRUE;
case 9:
/* drop weapon/shield */
if( !( obj = get_eq_char( victim, WEAR_WIELD_R ) )
&& !( obj = get_eq_char( victim, WEAR_WIELD_L ) )
&& !( obj = get_eq_char( victim, WEAR_WIELD_DOUBLE ) )
&& !( obj = get_eq_char( victim, WEAR_SHIELD ) ) )
return FALSE;
act( "$O strike paralyses $n and forces $m to drop $p.",
victim, obj, ch, TO_ROOM );
act( "Your arm goes numb and you drop $p.",
victim, obj, victim, TO_CHAR );
obj_from_char( obj );
obj_to_room( obj, victim->in_room );
return TRUE;
case 10: case 11:
/* Remove all dodges and parries etc. for the next round */
act( "$O strike momentarily stuns $n.", victim, NULL, ch, TO_ALL );
act( "You're stunned by $n's blow.", victim, NULL, ch, TO_CHAR );
victim->extra_bits |= CH_EX_RESET;
return TRUE;
}
return FALSE;
}
void do_circle( CHAR_DATA *ch, const char *argument )
{
OBJ_DATA *obj;
CHAR_DATA *rch;
CHAR_DATA *victim;
if( ( !IS_NPC( ch ) && !can_use( ch, gsn_circle ) )
|| ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) ) )
{
send_to_char(
"You'd better leave the assassin trade to thieves.\n\r", ch );
return;
}
if( !ch->fighting )
{
send_to_char( "You must be fighting in order to do that.\n\r", ch );
return;
}
if( !( victim = find_target( ch, argument, "Circle around" ) ) )
return;
if( victim == ch )
{
send_to_char( "You spin around in a circle. Whee!\n\r", ch );
return;
}
if( victim != ch->fighting )
{
send_to_char( "One fight at a time.\n\r", ch );
return;
}
if( !victim->fighting )
{
act( "Why? $E isn't bothering anyone.", ch, NULL, victim, TO_CHAR );
return;
}
if( !is_same_group( ch, victim->fighting ) )
{
send_to_char( "Why call attention to yourself?\n\r", ch );
return;
}
for( rch = ch->in_room->people; rch; rch = rch->next_in_room )
if( rch->fighting == ch )
break;
if( rch )
{
send_to_char( "You're too busy being hit right now.\n\r", ch );
return;
}
if( ( !( obj = get_eq_char( ch, WEAR_WIELD_R ) )
&& !( obj = get_eq_char( ch, WEAR_WIELD_DOUBLE ) ) )
|| obj->value[3] != 11 )
{
send_to_char( "You need to wield a piercing weapon.\n\r", ch );
return;
}
act( "$n circle$% around behind $N...", ch, NULL, victim, TO_ALL );
WAIT_STATE( ch, skill_table[gsn_circle].beats );
if( IS_NPC_CLASS( ch ) || get_success( ch, gsn_circle, 50 ) )
{
stop_fighting( victim, FALSE );
multi_hit( ch, victim, gsn_circle );
}
else
act( "You failed to get around $M", ch, NULL, victim, TO_CHAR );
return;
}
void do_flee( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
ROOM_INDEX_DATA *was_in;
ROOM_INDEX_DATA *now_in;
int attempt;
if( !( victim = ch->fighting ) )
{
if( ch->position == POS_FIGHTING )
ch->position = POS_STANDING;
send_to_char( "You aren't fighting anyone.\n\r", ch );
return;
}
if( ch->position < POS_FIGHTING )
{
send_to_char( "Get up first.\n\r", ch );
return;
}
if( !IS_NPC( ch->fighting )
&& ch->fighting->pcdata->pc_bits >= PC_BIT_STRANGLE )
{
act( "$N has $S hands around your throat, free yourself first!",
ch, NULL, ch->fighting, TO_CHAR );
return;
}
if( IS_AFFECTED( ch, AFF_BERSERK ) )
{
send_to_char( "You can't flee, you're BERSERK!\n\r", ch );
return;
}
if( IS_AFFECTED( ch, AFF_HOLD ) )
{
send_to_char( "You are stuck in a snare! You can't move!\n\r", ch );
act( "$n wants to flee, but is caught in a snare!",
ch, NULL, NULL, TO_ROOM );
return;
}
was_in = ch->in_room;
for( attempt = 0; attempt < 6; attempt++ )
{
EXIT_DATA *pexit;
int door;
door = number_door( );
if( ( pexit = was_in->exit[door] ) == 0
|| !pexit->to_room
|| IS_SET( pexit->exit_info, EX_CLOSED )
|| ( IS_NPC( ch )
&& ( IS_SET( pexit->to_room->room_flags, ROOM_NO_MOB )
|| ( xIS_SET( ch->act, ACT_STAY_AREA )
&& pexit->to_room->area != ch->in_room->area ) ) ) )
continue;
stop_fighting( ch, TRUE );
move_char( ch, door );
if( ( now_in = ch->in_room ) == was_in )
continue;
ch->in_room = was_in;
act( "$n has fled!", ch, NULL, NULL, TO_ROOM );
ch->in_room = now_in;
if( !IS_NPC( ch ) )
{
send_to_char( "&rYou flee from combat! You lose 25 exps.&n\n\r", ch );
gain_exp( ch, -2500 );
if( IS_NPC( victim ) && xIS_SET( victim->act, ACT_HUNTER ) )
{
victim->tracking = ch;
create_char_event( victim, evn_hunt_fleer,
number_range( PULSE_MOBILE / 2,
3 * PULSE_MOBILE / 2 ) );
}
}
else
{
ch->tracking = NULL;
strip_events( &ch->events, evn_hunt_fleer );
ch->fearing = victim;
}
return;
}
send_to_char( "You failed! You lose 10 exps.\n\r", ch );
gain_exp( ch, -10 );
return;
}
void do_berserk( CHAR_DATA *ch, const char *argument )
{
AFFECT_DATA af;
/* Don't allow charmed mobs to do this, check player's level */
if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
|| ( !IS_NPC_CLASS( ch ) && !can_use( ch, gsn_berserk ) ) )
{
send_to_char( "You're not enough of a warrior to go Berserk.\n\r",
ch );
return;
}
if( IS_AFFECTED( ch, AFF_CALM ) )
{
send_to_char( "You are feeling too mellow to berserk.\n\r", ch );
return;
}
if( !ch->fighting )
{
send_to_char( "You aren't fighting anyone.\n\r", ch );
return;
}
if( IS_AFFECTED( ch, AFF_BERSERK ) )
return;
send_to_char(
"Your weapon hits your foe and blood splatters all over!\n\r",
ch );
send_to_char( "The taste of blood begins to drive you crazy!\n\r",
ch );
if( get_success( ch, gsn_berserk, 100 ) )
{
af.type = gsn_berserk;
af.level = LEVEL_HERO;
af.duration = -1;
af.location = APPLY_HITROLL;
af.modifier = ch->level / 6;
vset( af.bitvector, AFF_BERSERK );
affect_to_char( ch, &af, NULL );
af.location = APPLY_DAMROLL;
affect_to_char( ch, &af, NULL );
af.location = APPLY_AC;
af.modifier *= 7;
affect_to_char( ch, &af, NULL );
send_to_char( "You have gone BERSERK!\n\r", ch );
act( "$n has gone BERSERK!", ch, NULL, NULL, TO_ROOM );
return;
}
send_to_char( "You shake off the madness.\n\r", ch );
return;
}
void do_rescue( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
CHAR_DATA *fch;
int count;
/* Don't allow charmed mobs to do this, check player's level */
if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
|| ( !IS_NPC( ch ) && !can_use( ch, gsn_rescue ) ) )
{
send_to_char(
"You'd better leave the heroic acts to warriors.\n\r", ch );
return;
}
if( IS_AFFECTED( ch, AFF_BERSERK ) )
{
send_to_char( "You can't rescue anyone, you're BERSERK!\n\r", ch );
return;
}
if( argument[0] == '\0' )
{
send_to_char( "Rescue whom?\n\r", ch );
return;
}
if( !check_blind( ch ) )
return;
if( !( victim = get_char_room( ch, argument ) ) )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
if( victim == ch )
{
send_to_char( "What about fleeing instead?\n\r", ch );
return;
}
if( !IS_NPC( ch ) && IS_NPC( victim ) )
{
send_to_char( "They don't need your help!\n\r", ch );
return;
}
if( ch->fighting == victim )
{
send_to_char( "Too late.\n\r", ch );
return;
}
if( !victim->fighting )
{
send_to_char( "That person is not fighting right now.\n\r", ch );
return;
}
if( !is_same_group( ch, victim ) )
{
send_to_char( "Why would you want to?\n\r", ch );
return;
}
WAIT_STATE( ch, skill_table[gsn_rescue].beats );
count = 0;
for( fch = victim->in_room->people; fch; fch = fch->next_in_room )
{
if( !IS_NPC( fch )
|| fch->deleted )
continue;
if( fch->fighting == victim )
{
if( number_range( 0, count ) == 0 )
break;
count++;
}
}
if( !fch
|| ( !IS_NPC( ch ) && !get_success( ch, gsn_rescue, 100 ) ) )
{
send_to_char( "You fail the rescue.\n\r", ch );
return;
}
act( "&c$n rescue$% $N!", ch, NULL, victim, TO_ALL );
for( fch = victim->in_room->people; fch; fch = fch->next_in_room )
{
if( fch->fighting != victim )
continue;
if( IS_AFFECTED( fch, AFF_BERSERK ) )
{
act( "$N's blind rage prevents you from distracting him.",
ch, NULL, fch, TO_CHAR );
continue;
}
stop_fighting( fch, FALSE );
set_fighting( fch, ch );
}
return;
}
void do_taunt( CHAR_DATA *ch, const char *argument )
{
AFFECT_DATA af;
if( IS_NPC( ch ) || !can_use( ch, gsn_taunt ) )
{
send_to_char( "You can laugh, but you still don't get the joke.\n\r",
ch );
return;
}
if( argument[0] == '\0' )
{
WAIT_STATE( ch, skill_table[gsn_taunt].beats );
affect_strip( ch, gsn_taunt );
if( get_success( ch, gsn_taunt, 100 ) )
{
if( IS_AFFECTED( ch, AFF_TAUNT ) )
send_to_char( "You try to behave with more decorum.\n\r", ch );
else
{
act( "$n begins to laugh at everyone viciously.",
ch, NULL, NULL, TO_ROOM );
send_to_char( "You now invite trouble.\n\r", ch );
af.type = gsn_taunt;
af.level = 0;
af.duration = -1;
af.location = APPLY_SPEED;
af.modifier = 2 + ch->level / 50;
vset( af.bitvector, AFF_TAUNT );
affect_to_char( ch, &af, NULL );
}
}
}
else
{
CHAR_DATA *vch;
if( !( vch = get_char_room( ch, argument ) ) )
{
send_to_char( "You can't taunt someone who isn't here.\n\r", ch );
return;
}
WAIT_STATE( ch, skill_table[gsn_taunt].beats );
if( IS_AFFECTED( vch, AFF_BERSERK ) )
{
act( "You taunt $N but $E is raging too much to notice.",
ch, NULL, vch, TO_CHAR );
act( "$n is trying to attract your attention, unsuccessfully.",
ch, NULL, vch, TO_VICT );
act( "$n taunts $N but $E is raging too much to notice.",
ch, NULL, vch, TO_NOTVICT );
return;
}
act( "You taunt $N mercilessly and $E turns on you in a rage!",
ch, NULL, vch, TO_CHAR );
act( "$n says something derogatory about your mother, ARRGGGHHHH!",
ch, NULL, vch, TO_VICT );
act( "$n taunts $N and $E turns to attack!",
ch, NULL, vch, TO_NOTVICT );
af.type = gsn_berserk;
af.level = LEVEL_HERO;
af.duration = -1;
af.location = APPLY_HITROLL;
af.modifier = vch->level / 6;
vset( af.bitvector, AFF_BERSERK );
affect_to_char( vch, &af, NULL );
stop_fighting( vch, FALSE );
set_fighting( vch, ch );
}
return;
}
void do_kick( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
/* Don't allow charmed mobs to do this, check player's level */
if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
|| ( !IS_NPC( ch ) && !can_use( ch, gsn_kick ) ) )
{
send_to_char(
"You'd better leave the martial arts to fighters.\n\r", ch );
return;
}
if( !( victim = find_target( ch, argument, "Kick" ) ) )
return;
WAIT_STATE( ch, skill_table[gsn_kick].beats );
if( get_success( ch, gsn_kick, 100 ) )
damage( ch, victim, number_range( 1, ch->level ), gsn_kick,
WEAR_NONE );
else
damage( ch, victim, 0, gsn_kick, WEAR_NONE );
return;
}
void do_snapkick( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
int dam, success;
/* Don't allow charmed mobs to do this, check player's level */
if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
|| ( !IS_NPC( ch ) && !can_use( ch, gsn_snapkick ) ) )
{
send_to_char(
"You'd better leave the martial arts to martial artists.\n\r",
ch );
return;
}
if( !( victim = find_target( ch, argument, "Kick" ) ) )
return;
success = victim->level - ch->level;
success *= 3;
success += ( get_size( victim ) - get_size( ch ) ) / 3;
success = URANGE( 5, success + number_percent( ), 100 );
dam = get_success( ch, gsn_snapkick, 100 ) / 2;
success -= dam;
if( success < 0 && number_bits( 3 ) == 0
&& victim->position >= POS_FIGHTING )
{
act( "$o snapkick slams $N into the ground!",
ch, NULL, victim, TO_ALL );
victim->position = POS_SMASHED;
WAIT_STATE( victim,
UMIN( success, skill_table[gsn_snapkick].beats * 2 ) );
if( IS_NPC( victim ) )
create_char_event( victim, evn_stand_up,
UMIN( success, skill_table[gsn_snapkick].beats * 2 ) );
}
if( dam )
{
dam = number_range( ch->level / 2, ch->level * 3 / 2 );
dam *= get_curr_str( ch ) + get_curr_dex( ch );
dam /= 30;
}
else
dam = 0;
WAIT_STATE( ch, skill_table[gsn_snapkick].beats );
damage( ch, victim, dam, gsn_snapkick, WEAR_NONE );
return;
}
void do_disarm( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
int percent;
/* Don't allow charmed mobiles to do this, check player's level */
if( ( IS_NPC( ch ) && IS_AFFECTED( ch, AFF_CHARM ) )
|| ( !IS_NPC( ch ) && !can_use( ch, gsn_disarm ) ) )
{
send_to_char( "You don't know how to disarm opponents.\n\r", ch );
return;
}
if( !get_eq_char( ch, WEAR_WIELD_R )
&& !get_eq_char( ch, WEAR_WIELD_L )
&& ( IS_NPC( ch ) || ch->pcdata->learned[gsn_barehand] <= 0 ) )
{
send_to_char( "You must wield a weapon to disarm.\n\r", ch );
return;
}
if( !ch->fighting )
{
send_to_char( "You aren't fighting anyone.\n\r", ch );
return;
}
if( !( victim = find_target( ch, argument, "Disarm" ) ) )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
if( victim->fighting != ch && ch->fighting != victim )
{
act( "$E is not fighting you!", ch, NULL, victim, TO_CHAR );
return;
}
if( !get_eq_char( victim, WEAR_WIELD_R )
&& !get_eq_char( victim, WEAR_WIELD_L )
&& !get_eq_char( victim, WEAR_WIELD_DOUBLE ) )
{
send_to_char( "Your opponent is not wielding a weapon.\n\r", ch );
return;
}
WAIT_STATE( ch, skill_table[gsn_disarm].beats );
percent = 100 + victim->level - ch->level;
percent = percent * 2 / 3;
if( !get_success( ch, gsn_disarm, percent ) || !disarm( ch, victim ) )
send_to_char( "You failed to disarm.\n\r", ch );
return;
}
void do_sla( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *rch;
rch = get_char( ch );
if( !authorized( rch, "slay" ) )
return;
send_to_char( "If you want to SLAY, spell it out.\n\r", ch );
return;
}
void do_slay( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
CHAR_DATA *rch;
char arg[MAX_INPUT_LENGTH];
rch = get_char( ch );
if( !authorized( rch, "slay" ) )
return;
argument = one_argument( argument, arg );
if( arg[0] == '\0' )
{
send_to_char( "Usage: slay <character> [type]\n\r"
"[type] is one of the following:\n\r"
"9mm, deheart, demon, immolate, laughing, pounce,\n\r"
" shatter, skin, slit.\n\r", ch );
return;
}
if( !( victim = get_char_room( ch, arg ) ) )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
if( ch == victim )
{
send_to_char( "Suicide is a mortal sin.\n\r", ch );
return;
}
if( !IS_NPC( victim ) && victim->level >= ch->level )
{
send_to_char( "You failed.\n\r", ch );
return;
}
if( argument[0] == '\0' )
act( "$n slay$% $N in cold blood!", ch, NULL, victim, TO_ALL );
else if( !str_prefix( argument, "9mm" ) )
{
act( "$n pull$% out $s 9mm and bust$% a cap in $O ass.",
ch, NULL, victim, TO_ALL );
}
else if( !str_prefix( argument, "deheart" ) )
{
act( "You rip through $N's chest and pull out $M beating "
"heart in your hand.", ch, NULL, victim, TO_CHAR );
act( "You feel a sharp pain as $n rips into your chest and tears "
"out your still beating heart.", ch, NULL, victim, TO_VICT );
act( "Specks of blood hit your face as $n rips through $N's chest "
"pulling out $S beating heart.", ch, NULL, victim, TO_NOTVICT );
}
else if ( !str_cmp( argument, "demon" ) )
{
act( "$N gesture$%, and a slavering demon appears.", ch, NULL, victim, TO_ALL );
act( "With a horrible grin, the foul creature turns on $N...\n\r"
"...who screams in panic before being eaten alive.",
victim, NULL, NULL, TO_ROOM );
act( "With a horrible grin, the foul creature turns on you...\n\r"
"...you scream in panic before being eaten alive.",
victim, NULL, NULL, TO_CHAR );
}
else if( !str_prefix( argument, "immolate" ) )
{
act( "Your fireball turns $N into a blazing inferno.",
ch, NULL, victim, TO_CHAR );
act( "$n releases a searing fireball in your direction.",
ch, NULL, victim, TO_VICT );
act( "$n points at $N, who bursts into a flaming inferno.",
ch, NULL, victim, TO_NOTVICT );
}
else if( !str_prefix( argument, "laughing" ) )
{
act( "$N point$% at $n and fall$% down laughing. $E dies laughing.",
victim, NULL, ch, TO_ROOM );
act( "$N points at you and falls down laughing.\n\r"
"You die from the humility!", victim, NULL, ch, TO_CHAR );
}
else if( !str_prefix( argument, "pounce" ) )
{
act( "Leaping upon $N with bared fangs, you tear open $S throat and "
"toss the corpse to the ground...", ch, NULL, victim, TO_CHAR );
act( "In a heartbeat, $n rips $s fangs through your throat!\n\r"
"Your blood sprays and pours to the ground as your life ends...",
ch, NULL, victim, TO_VICT );
act( "Leaping suddenly, $n sinks $s fangs into $N's throat.\n\r"
"As blood sprays and gushes to the ground, $n tosses $N's "
"dying body away.", ch, NULL, victim, TO_NOTVICT );
}
else if( !str_prefix( argument, "shatter" ) )
{
act( "$n freeze$% $N with a glance and shatter$% your frozen body "
"into tiny shards.", ch, NULL, victim, TO_ALL );
}
else if( !str_prefix( argument, "skin" ) )
{
act( "You rip the flesh from $N and send his soul to "
"the fiery depths of hell.", ch, NULL, victim, TO_CHAR );
act( "Your flesh is torn from your bones and you are sent to "
"the flames of hell.", ch, NULL, victim,TO_VICT );
act( "$n rips the flesh off of $N, releasing his soul into "
"the fiery depths of hell.", ch, NULL, victim, TO_NOTVICT );
}
else if( !str_prefix( argument, "slit" ) )
{
act( "You calmly slit $N's throat.", ch, NULL, victim, TO_CHAR );
act( "$n reaches out with a clawed finger and calmly slits $O throat.",
ch, NULL, victim, TO_ROOM );
}
raw_kill( ch, victim );
return;
}
void do_fee( CHAR_DATA *ch, const char *argument )
{
send_to_char(
"IF you wish to feed on someone or something, type FEED!\n\r",
ch );
return;
}
/* Vampiric bite. Feeding */
void do_feed( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
OBJ_DATA *obj;
AFFECT_DATA af;
int dam;
int heal;
if( !( victim = find_target( ch, argument, "Feed on" ) ) )
return;
if( victim == ch )
{
send_to_char( "You cannot lunge for your own throat.\n\r", ch );
return;
}
send_to_char( "You must have blooood!\n\r", ch );
act( "$n lunges for $O throat!", ch, NULL, victim, TO_ROOM );
WAIT_STATE( ch, PULSE_VIOLENCE );
if( !victim->fighting )
set_fighting( victim, ch );
if( str_cmp( race_table[ch->race].name, "Vampire" ) )
{
send_to_char( "You missed!\n\r", ch );
if( !ch->fighting )
set_fighting( ch, victim );
return;
}
if( ch->fighting )
{
if( number_percent( ) > ch->level + dice( 3, 5 ) )
{
send_to_char( "You missed!\n\r", ch );
return;
}
}
/* If the victim is asleep, he deserves to be bitten. : ) */
if( !ch->fighting )
{
if( number_percent( ) > ( ch->level * 1.75 ) && IS_AWAKE( victim ) )
{
send_to_char( "You missed!\n\r", ch );
set_fighting( ch, victim );
return;
}
}
dam = dice( 3, ch->level );
damage( ch, victim, dam, gsn_vampiric_bite, WEAR_NONE );
/* Lets see if we can get some food from this attack */
if( !IS_NPC( ch )
&& number_percent( ) < ( 34 - victim->level + ch->level ) )
{
/* If not hungry, thirsty or damaged, then continue */
if( ch->pcdata->condition[COND_FULL] >
race_table[ch->race].hunger_mod * 40 / 5
&& ch->pcdata->condition[COND_THIRST]
> race_table[ch->race].thirst_mod * 40 / 5
&& ( ch->hit * 100 / ch->max_hit > 75 ) )
{
return;
}
else
{
send_to_char( "Ahh! Blood! Food! Drink!\n\r", ch );
heal = number_range( 1, dam ) / 2;
ch->hit = UMIN( ch->max_hit, ch->hit + heal );
/* Get full as per drinking blood */
gain_condition( ch, COND_FULL, heal * 25 );
/* Quench thirst as per drinking blood absolute value */
gain_condition( ch, COND_THIRST, heal * 12 );
}
}
/* Ok now we see if we can infect the victim */
/* if( IS_NPC( victim ) ) --This might turn out to be fun :)
return; */
if( victim->level < 11 || get_age( victim ) < 21 )
return;
if( saves_spell( ch->level, victim, ch, gsn_vampiric_bite )
|| number_bits( 1 ) == 0 )
return;
if( ( obj = get_eq_char( victim, ITEM_HOLD ) ) )
{
if( IS_OBJ_STAT( obj, ITEM_VAMPIRE_BANE ) && ch->level < 21 )
return;
else if( IS_OBJ_STAT( obj, ITEM_HOLY ) )
{
if( ch->level < 32 )
return;
else if( victim->level > ch->level )
return;
}
}
af.type = gsn_vampiric_bite;
af.duration = UMAX( 5, 30 - ch->level );
af.location = APPLY_NONE;
af.modifier = 0;
vset( af.bitvector, AFF_VAMP_BITE );
affect_join( victim, &af );
send_to_char( "Ahh! Taste the power!\n\r", ch );
send_to_char( "Your blood begins to burn!\n\r", victim );
return;
}
void do_stake( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
OBJ_DATA *obj;
bool found = FALSE;
int chance;
if( !( victim = find_target( ch, argument, "Stake" ) ) )
return;
if( IS_NPC( victim ) )
{
send_to_char( "You may not stake NPC's.\n\r", ch );
return;
}
/* Check here to see if they have a stake in hand.
* Changed slightly to allow any wooden weapon that is wielded
* and can stab or pierce. --Symposium
*/
for( obj = ch->carrying; obj; obj = obj->next_content )
{
if( obj->item_type == ITEM_WEAPON
&& ( obj->value[3] == 2 || obj->value[3] == 11 )
&& ( obj->wear_loc == WEAR_WIELD_R
|| obj->wear_loc == WEAR_WIELD_L
|| obj->wear_loc == WEAR_WIELD_DOUBLE )
&& !str_cmp( flag_string( material_flags,
&obj->pIndexData->material ), "wood" ) )
{
found = TRUE;
break;
}
}
if( !found )
{
send_to_char( "You lack a wielded stake to stake.\n\r", ch );
act( "$n screams and lunges at $N then realizes $e doesnt have a stake",
ch, NULL, victim, TO_ROOM );
multi_hit( ch, victim, TYPE_UNDEFINED );
return;
}
act( "$n screams and lunges at $N with $p.", ch, obj, victim, TO_ALL );
/* Calculate chances -> autokill the vampire. */
chance = IS_NPC( ch ) ? UMIN( 60, ch->level )
: ch->pcdata->learned[gsn_stake];
chance = chance - victim->level + ch->level;
if( number_percent( ) < chance
|| !IS_AWAKE( victim )
|| str_cmp( race_table[ch->race].name, "Vampire" ) )
{
if( !str_cmp( race_table[victim->race].name, "Vampire" ) )
{
/* remove the curse, this isn't done when they are killed */
affect_strip( victim, gsn_vampiric_bite );
victim->hit = 1;
damage( ch, victim, 4, gsn_stake, WEAR_NONE );
}
else
multi_hit( ch, victim, TYPE_UNDEFINED );
}
else /* vampire staking another vampire, strange?, feed instead. */
do_feed( victim, ch->name );
return;
}
void do_impale( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
OBJ_DATA *obj;
if( !can_use( ch, gsn_impale ) )
{
send_to_char( "Learn how to do this first please.\n\r", ch );
return;
}
if( !( victim = find_target( ch, argument, "Impale" ) ) )
return;
if( ( !( obj = get_eq_char( ch, WEAR_WIELD_R ) )
&& !( obj = get_eq_char( ch, WEAR_WIELD_DOUBLE ) ) )
|| obj->value[3] != 11 )
{
send_to_char( "You need to wield a piercing weapon.\n\r", ch );
return;
}
if( ch->level + get_success( ch, gsn_impale, 500 ) + get_curr_str( ch )
> number_percent( ) + victim->level + get_curr_str( victim ) )
{
act( "You pull back then shove your weapon into $N's chest!", ch, NULL, victim, TO_CHAR );
act( "$n drives $s weapon straight into you!.", ch, NULL, victim, TO_VICT );
act( "$n impales $N on $s weapon!", ch, NULL, victim, TO_NOTVICT );
one_hit( ch, victim, gsn_impale, obj->wear_loc );
WAIT_STATE( victim, 2 * PULSE_VIOLENCE );
if( IS_NPC( victim ) )
create_char_event( victim, evn_stand_up, 2 * PULSE_VIOLENCE );
}
else
{
act( "You try to impale $N but $E manages to avoid you.", ch, NULL, victim, TO_CHAR );
act( "$n tries to impale you but you manage to avoid $m.", ch, NULL, victim, TO_VICT );
act( "$n barely misses impaling $N.", ch, NULL, victim, TO_NOTVICT );
damage( ch, victim, 0, gsn_impale, obj->wear_loc );
}
WAIT_STATE( ch, skill_table[gsn_impale].beats );
return;
}
void do_headbutt( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
OBJ_DATA *helmet;
AFFECT_DATA af;
int hps, num, move = 25;
/* Don't allow charmed mobs to do this, check player's level */
if( !can_use( ch, gsn_headbutt ) )
{
send_to_char(
"You'd better leave the power fighting to fighters.\n\r", ch );
return;
}
if( !( victim = find_target( ch, argument, "Headbutt" ) ) )
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;
helmet = get_eq_char( ch, WEAR_HEAD );
hps = victim->hit;
WAIT_STATE( ch, skill_table[gsn_headbutt].beats );
if( ( num = get_success( ch, gsn_headbutt, 100 ) ) )
{
one_hit( ch, victim, gsn_headbutt, WEAR_WIELD_R );
}
else
{
damage( ch, victim, 0, gsn_headbutt, WEAR_NONE );
one_hit( ch, ch, gsn_headbutt, WEAR_NONE );
if( !helmet || number_percent( ) > ch->pcdata->learned[gsn_headbutt] / 3 )
victim = ch;
}
if( victim == ch->fighting && hps > victim->hit &&
( ( ch != victim && number_percent( ) < num / 7 )
|| ( ch == victim && number_percent( ) > num / 2 ) ) )
{
af.type = skill_lookup( "sleep" );
af.duration = number_range( 0, 2 );
af.location = APPLY_NONE;
af.modifier = 0;
vset( af.bitvector, AFF_SLEEP );
act( "$o eyes glaze over and $e crumple$% to the ground.",
victim, NULL, NULL, TO_ALL );
stop_fighting( victim, TRUE );
do_sleep( victim, "" );
}
return;
}
void do_smash( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
if( !can_use( ch, gsn_smash ) )
{
send_to_char( "You should learn how to use the skill first.\n\r",
ch );
return;
}
if( !( victim = find_target( ch, argument, "Smash" ) ) )
return;
WAIT_STATE( ch, skill_table[gsn_smash].beats );
if( get_success( ch, gsn_smash, 90 ) )
one_hit( ch, victim, gsn_smash, WEAR_NONE );
else
damage( ch, victim, 0, gsn_smash, WEAR_NONE );
}
void do_ram( CHAR_DATA *ch, const char *argument )
{
int success, wait;
CHAR_DATA *victim;
if( !can_use( ch, gsn_ram ) )
{
send_to_char( "You should learn how to use the skill first.\n\r",
ch );
return;
}
if( !get_eq_char( ch, WEAR_SHIELD ) )
{
send_to_char( "I would advise wearing a shield first.\n\r", ch );
return;
}
if( !( victim = find_target( ch, argument, "Ram" ) ) )
return;
success = ch->level - victim->level;
success *= 3;
success += ( get_size( ch ) - get_size( victim ) ) / 3;
if( !IS_NPC_CLASS( ch ) )
success += get_success( ch, gsn_ram, 500 );
else
success += UMIN( ch->level, 90 );
success += get_curr_str( ch ) - 30;
if( victim->position <= POS_SMASHED )
success /= 2;
success -= number_percent( );
if( success > 0 )
{
if( victim->position <= POS_SMASHED )
{
send_to_char( "Let them get up first.\n\r", ch );
return;
}
act( "$n ram$% into $N sending $M sprawling.",
ch, NULL, victim, TO_ALL );
stop_juggling( victim );
victim->position = POS_SMASHED;
damage( ch, victim, number_range( ch->level / 2, ch->level * 3 / 2 ),
gsn_ram, WEAR_NONE );
wait = skill_table[gsn_ram].beats
+ UMIN( success, 4 * skill_table[gsn_ram].beats );
WAIT_STATE( victim, wait );
if( IS_NPC( victim ) )
create_char_event( victim, evn_stand_up, wait );
WAIT_STATE( ch, skill_table[gsn_ram].beats );
}
else
{
act( "You try to ram into $N but you fall over.",
ch, NULL, victim, TO_CHAR );
act( "$n trie$% to ram into $N but $e fall$% over.",
ch, NULL, victim, TO_ROOM );
ch->position = POS_SMASHED;
if( !victim->fighting )
multi_hit( victim, ch, TYPE_UNDEFINED );
WAIT_STATE( ch, 2 * skill_table[gsn_ram].beats );
}
return;
}
/*
* Slit throat, specialised backstab.
* More damage, better maximum damage etc...
*/
void do_slit_throat( CHAR_DATA *ch, const char *argument )
{
OBJ_DATA *obj;
CHAR_DATA *victim;
if( !IS_NPC_CLASS( ch ) && !can_use( ch, gsn_slit_throat ) )
{
send_to_char(
"You better leave the assassin trade to thieves.\n\r", ch );
return;
}
if( !( victim = find_target( ch, argument, "Slit the throat of" ) ) )
return;
if( victim == ch )
{
send_to_char( "How can you sneak up on yourself?\n\r", ch );
return;
}
if( !( obj = get_eq_char( ch, WEAR_WIELD_R ) )
|| ( obj->value[3] != 1 && obj->value[3] != 3 ) )
{
send_to_char( "You need to wield a slicing or slashing weapon.\n\r",
ch );
return;
}
WAIT_STATE( ch, skill_table[gsn_slit_throat].beats );
act( "You slit $N a nice new smile.", ch, NULL, victim, TO_CHAR );
act( "$n sneaks up on $N and slashes $S throat!",
ch, NULL, victim, TO_NOTVICT );
if( !IS_AWAKE( victim )
|| get_success( ch, gsn_slit_throat, 100 ) )
{
multi_hit( ch, victim, gsn_slit_throat );
xSET_BIT( victim->affected_by, AFF_BLEEDING );
}
else
damage( ch, victim, 0, gsn_slit_throat, WEAR_WIELD_R );
return;
}
void do_tend( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
OBJ_DATA *band;
if( !( *argument ) )
victim = ch;
else
victim = get_char_room( ch, argument );
if( !( victim ) )
{
send_to_char( "Tend whom?\n\r", ch );
return;
}
if( !IS_AFFECTED( victim, AFF_BLEEDING )
&& !victim->damaged_parts )
{
send_to_char( "They have no need of your assistance.\n\r", ch );
return;
}
if( ( !IS_NPC( victim ) || ch != victim )
&& ( victim->damaged_parts & victim->body_parts ) )
{
if( can_use( ch, gsn_field_dressing ) )
{
WAIT_STATE( ch, skill_table[gsn_field_dressing].beats );
if( !get_success( ch, gsn_field_dressing, 100 ) )
{
act( "$n tries to use $s field dressing techniques on $N, but fails.",
ch, NULL, victim, TO_ROOM );
act( "You fail to properly use your field dressing techniques.",
ch, NULL, victim, TO_CHAR );
return;
}
act( "$n use$% field dressing techniques to repair $O wounds.",
ch, NULL, victim, TO_ALL );
}
else /* can't use field dressing */
{
for( band = ch->carrying; band; band = band->next_content )
if( band->pIndexData->vnum == OBJ_VNUM_BANDAGES )
break;
if( !band )
{
send_to_char(
"You can't repair their wounds without bandages.\n\r",
ch );
return;
}
if( ch == victim )
{
act( "$n wrap$% $s wounds with $p.", ch, band, NULL, TO_ALL );
}
else
{
act( "$n wraps $O wounds with $p.", ch, band, victim, TO_ALL );
}
extract_obj( band );
WAIT_STATE( ch, PULSE_VIOLENCE * 2 );
}
victim->damaged_parts = 0;
}
xREMOVE_BIT( victim->affected_by, AFF_BLEEDING );
if( ch != victim )
{
act( "$n tend$% $O wounds.", ch, NULL, victim, TO_ALL );
}
else
{
act( "$n tend$% $s own wounds.", ch, NULL, NULL, TO_ALL );
}
WAIT_STATE( ch, PULSE_VIOLENCE );
return;
}
void do_stomp( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
if( !can_use( ch, gsn_stomp ) )
{
bad_command( ch );
return;
}
if( !( victim = find_target( ch, argument, "Stomp on" ) ) )
return;
if( victim->position >= POS_FIGHTING )
{
send_to_char( "They must be on the ground before you can stomp on them.\n\r", ch );
return;
}
if( ch->level + get_success( ch, gsn_stomp, 500 ) + get_curr_str( ch )
> number_percent( ) + victim->level + get_curr_str( victim ) )
{
act( "$n stomp$% down on $N's head with a sickening crunching sound!",
ch, NULL, victim, TO_ALL );
one_hit( ch, victim, gsn_stomp, WEAR_WIELD_L );
WAIT_STATE( victim, PULSE_VIOLENCE );
if( IS_NPC( victim ) )
create_char_event( victim, evn_stand_up, PULSE_VIOLENCE );
}
else
{
act( "You try to stomp on $N but $E rolls out of the way.", ch, NULL, victim, TO_CHAR );
act( "$n tries to stomp on you but you manage to avoid $m.", ch, NULL, victim, TO_VICT );
act( "$n barely misses stomping on $N.", ch, NULL, victim, TO_NOTVICT );
damage( ch, victim, 0, gsn_stomp, WEAR_NONE );
}
WAIT_STATE( ch, 3 * PULSE_VIOLENCE );
return;
}
void do_strangle( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
AFFECT_DATA af;
if( IS_NPC( ch ) || !can_use( ch, gsn_strangle ) )
{
send_to_char( "You don't know how to strangle yet.\n\r", ch );
return;
}
if( !( victim = find_target( ch, argument, "Strangle" ) ) )
return;
if( victim->fighting != ch )
{
victim->fighting = ch;
if( victim->position != POS_SMASHED )
victim->position = POS_FIGHTING;
}
ch->fighting = victim;
WAIT_STATE( ch, 3 * PULSE_VIOLENCE );
if( !get_success( ch, gsn_strangle, 100 ) )
{
send_to_char( "You fail to get a good grip.\n\r", ch );
return;
}
af.type = gsn_strangle;
af.level = LEVEL_HERO;
af.location = APPLY_NONE;
af.modifier = 0;
af.duration = ch->level;
vset( af.bitvector, AFF_HOLD );
affect_to_char( victim, &af, NULL );
act( "$n grab$% hold of $N and start$% throttling $M!", ch, NULL, victim, TO_ALL );
SET_BIT( ch->pcdata->pc_bits, PC_BIT_STRANGLE );
if( get_time_left( ch->in_room->events, evn_room_violence ) < 0 )
create_room_event( ch->in_room, evn_room_violence,
PULSE_VIOLENCE );
return;
}
/*
* for those strangling
*/
void strangle_hit( CHAR_DATA *ch )
{
int pwr;
int dam;
if( IS_NPC( ch ) || !ch->fighting )
return;
pwr = ch->pcdata->pc_bits / PC_BIT_STRANGLE;
dam = number_range( ch->level / 2, ch->level );
dam += get_damroll( ch );
if( IS_SET( ch->pcdata->pc_bits, PC_BIT_HANDOFKAZ ) )
{
dam += get_curr_int( ch ) * 2;
dam = power( dam, get_success( ch, gsn_hand_of_kaz, 250 ), pwr );
ch->pcdata->pc_bits += PC_BIT_STRANGLE;
damage( ch, ch->fighting, dam, gsn_hand_of_kaz, WEAR_NONE );
}
else
{
dam += get_curr_dex( ch ) * 2;
dam = power( dam, get_success( ch, gsn_strangle, 250 ), pwr );
ch->pcdata->pc_bits += PC_BIT_STRANGLE;
damage( ch, ch->fighting, dam, gsn_strangle, WEAR_NONE );
}
return;
}
/*
* for those being strangled
*/
void strangle_struggle( CHAR_DATA *ch )
{
int chance;
if( !ch->fighting || IS_NPC( ch->fighting ) )
return;
if( IS_SET( ch->fighting->pcdata->pc_bits, PC_BIT_HANDOFKAZ ) )
{
chance = get_curr_int( ch ) - get_curr_int( ch->fighting );
chance -= ch->fighting->pcdata->learned[gsn_hand_of_kaz] / 2;
chance += ch->level - ch->fighting->level;
if( chance + 75 > number_percent( ) )
{
act( "$n wrenches free of $O death grip.",
ch, NULL, ch->fighting, TO_ALL );
ch->fighting->pcdata->pc_bits %= PC_BIT_STRANGLE;
REMOVE_BIT( ch->fighting->pcdata->pc_bits, PC_BIT_HANDOFKAZ );
/*
* Optional -- Symposium
* multi_hit( ch, ch->fighting, TYPE_UNDEFINED );
*/
}
else
{
act( "You strain to free yourself of $N's death grip",
ch, NULL, ch->fighting, TO_CHAR );
act( "$n is straining to free $mself from $N's death grip.",
ch, NULL, ch->fighting, TO_NOTVICT );
act( "You feel $n's heart beat weakly in your fist.",
ch, NULL, ch->fighting, TO_VICT );
}
}
else
{
chance = get_curr_dex( ch ) - get_curr_dex( ch->fighting );
chance -= ch->fighting->pcdata->learned[gsn_strangle] / 2;
chance += ch->level - ch->fighting->level;
if( chance + 75 > number_percent( ) )
{
act( "You struggle free of $N's stranglehold.",
ch, NULL, ch->fighting, TO_CHAR );
act( "$n frees $mself from $N's stranglehold.",
ch, NULL, ch->fighting, TO_NOTVICT );
act( "$n slips from your grasp.",
ch, NULL, ch->fighting, TO_VICT );
ch->fighting->pcdata->pc_bits %= PC_BIT_STRANGLE;
/*
* Optional -- Symposium
* multi_hit( ch, ch->fighting, TYPE_UNDEFINED );
*/
}
else
{
act( "You struggle to free yourself of $N's stranglehold.",
ch, NULL, ch->fighting, TO_CHAR );
act( "$n is struggling to free $mself from $N's stranglehold.",
ch, NULL, ch->fighting, TO_NOTVICT );
act( "$n is struggling but you hold firm.",
ch, NULL, ch->fighting, TO_VICT );
}
}
return;
}
void do_trip( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
if( !IS_NPC_CLASS( ch ) && !can_use( ch, gsn_trip ) )
{
send_to_char( "You can't use that yet.\n\r", ch );
return;
}
if( !( victim = find_target( ch, argument, "Trip" ) ) )
return;
if( !ch->fighting )
set_fighting( ch, victim );
if( IS_SET( victim->body_parts, BODY_PART_WINGS )
|| xIS_SET( victim->affected_by, AFF_FLYING ) )
{
act( "You watch as your leg sweeps underneath $N.",
ch, NULL, victim, TO_CHAR );
act( "$n try to trip you but $s leg passes under you.",
ch, NULL, victim, TO_VICT );
act( "$n tries to trip $N but $s leg passes under $E.",
ch, NULL, victim, TO_NOTVICT );
WAIT_STATE( ch, PULSE_VIOLENCE * 2 );
if( !victim->fighting )
set_fighting( victim, ch );
return;
}
if( !IS_NPC( ch )
&& get_success( ch, gsn_trip, 200 )
+ 2 * ( get_curr_dex( ch ) + ch->level - victim->level )
- 45 < number_percent( ) )
{
act( "You try to trip $N and you stumble.",
ch, NULL, victim, TO_CHAR );
act( "$n trie$% to trip $N and $e stumble$%.",
ch, NULL, victim, TO_ROOM );
WAIT_STATE( ch, 2 * PULSE_VIOLENCE );
if( !victim->fighting )
set_fighting( victim, ch );
return;
}
WAIT_STATE( ch, PULSE_VIOLENCE );
if( victim->position < POS_FIGHTING )
{
send_to_char( "Let them get up first, eh?\n\r", ch );
return;
}
if( !IS_NPC( ch ) || victim->wait == 0 )
{
int wait;
victim->fighting = NULL;
act( "You trip $N and $N goes down!", ch, NULL, victim, TO_CHAR );
act( "$n trips you and you go down!", ch, NULL, victim, TO_VICT );
act( "$n trips $N and $N goes down!", ch, NULL, victim, TO_NOTVICT );
wait = number_range( 3 * PULSE_VIOLENCE, 5 * PULSE_VIOLENCE );
WAIT_STATE( victim, wait );
if( IS_NPC( victim ) )
create_char_event( victim, evn_stand_up, wait );
stop_juggling( victim );
victim->position = POS_SLEEPING;
}
return;
}
bool throw( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
if( !( victim = find_target( ch, argument, "Throw" ) ) )
return FALSE;
if( !IS_NPC_CLASS( ch ) && !can_use( ch, gsn_throw ) )
{
send_to_char( "Maybe you should learn the proper technique "
"before trying to throw people.\n\r", ch );
return TRUE;
}
if( !ch->fighting )
set_fighting( ch, victim );
if( !IS_NPC_CLASS( ch )
&& get_success( ch, gsn_throw, 200 ) + get_curr_str( ch )
+ get_curr_dex( ch ) + 2 * ( ch->level - victim->level )
- 45 < number_percent( ) )
{
act( "You try to throw $N but $E slips from your grasp.",
ch, NULL, victim, TO_CHAR );
act( "$n tries to throw you but you manage to slip $s grasp.",
ch, NULL, victim, TO_VICT );
act( "$n tries to throw $N but $E slips out of $s grasp.",
ch, NULL, victim, TO_NOTVICT );
WAIT_STATE( ch, 3 * PULSE_VIOLENCE );
}
else if( !IS_NPC_CLASS( ch ) || victim->wait == 0 )
{
int wait;
victim->fighting = NULL;
act( "$n grab$% $N throw$% $M to the ground!",
ch, NULL, victim, TO_ALL );
WAIT_STATE( ch, PULSE_VIOLENCE );
wait = number_range( 3 * PULSE_VIOLENCE, 5 * PULSE_VIOLENCE );
WAIT_STATE( victim, wait );
if( IS_NPC( victim ) )
create_char_event( victim, evn_stand_up, wait );
stop_juggling( victim );
victim->position = POS_SLEEPING;
}
return TRUE;
}
void do_whirlwind( CHAR_DATA *ch, const char *argument )
{
CHAR_DATA *victim;
CHAR_DATA *next;
OBJ_DATA *obj;
int move = 100;
if( !can_use( ch, gsn_whirlwind ) )
{
send_to_char( "Maybe you should learn how first.\n\r", ch );
return;
}
if( !( obj = get_eq_char( ch, WEAR_WIELD_R ) )
&& !( obj = get_eq_char( ch, WEAR_WIELD_DOUBLE ) )
&& !( obj = get_eq_char( ch, WEAR_WIELD_L ) ) )
{
send_to_char( "You should be wearing a weapon.\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;
send_to_char( "You sweep your weapon around viciously.\n\r", ch );
act( "$n sweeps $s weapon around the room!", ch, NULL, NULL, TO_ROOM );
if( !get_success( ch, gsn_whirlwind, 100 ) )
return;
WAIT_STATE( ch, skill_table[gsn_whirlwind].beats );
for( victim = ch->in_room->people; victim; victim = next )
{
next = victim->next_in_room;
if( !IS_NPC( ch ) && !IS_NPC( victim ) &&
!xIS_SET( ch->act, PLR_BATTLE ) &&
!xIS_SET( victim->act, PLR_BATTLE ) &&
!IS_SET( ch->in_room->room_flags, ROOM_ARENA ) )
continue;
if( IS_NPC( ch ) && IS_NPC( victim ) )
continue;
if( !IS_NPC( ch ) && is_affected( victim, AFF_CHARM ) )
continue;
one_hit( ch, victim, gsn_whirlwind, obj->wear_loc );
}
return;
}
#define MAX_COMBO 5
void do_combo( CHAR_DATA *ch, const char *argument )
{
static const int type_hit = TYPE_HIT;
const struct combo_type
{
const char *name;
const int * hit_gsn[MAX_COMBO];
}
combo_table[] =
{
{ "eagle combo",
{ &gsn_jab, &type_hit, &gsn_jab, &gsn_backhand }
},
{ "pummel combo",
{ &gsn_jab, &gsn_jab, &gsn_backhand, &gsn_uppercut }
},
{ "bull combo",
{ &gsn_backhand, &gsn_knee, &gsn_uppercut }
},
{ "viper combo",
{ &gsn_backhand, &gsn_knee, &gsn_elbow,
&gsn_uppercut, &gsn_roundhouse }
},
{ "dragon combo",
{ &gsn_elbow, &gsn_knee, &gsn_uppercut,
&gsn_roundhouse, &gsn_uppercut }
},
{ NULL, { 0 } }
};
CHAR_DATA *victim;
int typ, sn, i, savehit;
if( IS_NPC( ch ) )
return;
if( !( victim = ch->fighting ) )
{
send_to_char( "You should be fighting first.\n\r", ch );
return;
}
if( argument[0] == '\0' )
{
send_to_char( "Which combo?\n\r", ch );
return;
}
if( get_eq_char( ch, WEAR_WIELD_DOUBLE ) || get_eq_char( ch, WEAR_WIELD_R )
|| get_eq_char( ch, WEAR_WIELD_L ) || get_eq_char( ch, WEAR_SHIELD )
|| get_eq_char( ch, WEAR_HOLD_L ) || get_eq_char( ch, WEAR_HOLD_R ) )
{
send_to_char( "Are you joking? Your gear gets in the way!\n\r", ch );
return;
}
for( typ = 0; combo_table[typ].name; typ++ )
{
if( !str_prefix( argument, combo_table[typ].name ) )
break;
}
if( !combo_table[typ].name )
{
send_to_char( "That combination is not possible.\n\r", ch );
return;
}
sn = skill_lookup( combo_table[typ].name );
if( sn <= 0 || !can_use( ch, sn ) )
{
send_to_char( "You wave your hands about and"
" succeed in making an idiot of yourself.\n\r", ch );
return;
}
WAIT_STATE( ch, skill_table[sn].beats );
if( !get_success( ch, sn, 100 ) )
{
send_to_char( "You wave your hands about and"
" succeed in making an idiot of yourself.\n\r", ch );
return;
}
i = 0;
savehit = victim->hit;
one_hit( ch, victim, TYPE_HIT, WEAR_WIELD_R );
while( i < MAX_COMBO && *combo_table[typ].hit_gsn[i] > 0 )
{
if( victim->deleted || victim != ch->fighting
|| victim->hit >= savehit )
return;
if( *combo_table[typ].hit_gsn[i] == TYPE_HIT
|| get_success( ch, *combo_table[typ].hit_gsn[i], 100 ) )
{
savehit = victim->hit;
one_hit( ch, victim, *combo_table[typ].hit_gsn[i], WEAR_WIELD_R );
++i;
continue;
}
damage( ch, victim, 0, *combo_table[typ].hit_gsn[i], WEAR_WIELD_R );
return;
}
return;
}
void do_blink( CHAR_DATA *ch, const char *argument )
{
if( IS_NPC( ch ) || !can_prac( ch, gsn_blink ) )
{
send_to_char( "You can't use this skill.\n\r", ch );
return;
}
if( argument[0] == '\0' )
{
if( ch->pcdata->blink > 0 )
charprintf( ch, "You are blinking at %d%%.\n\r",
ch->pcdata->blink );
else if( ch->pcdata->blink == 0 )
send_to_char( "You aren't blinking incoming attacks.\n\r", ch );
else
charprintf( ch, "If you were blinking you would be at %d%%.\n\r",
ch->pcdata->blink * -1 );
return;
}
if( !str_cmp( argument, "on" ) )
{
if( ch->pcdata->blink >= 0 )
{
send_to_char( "Please specify the rate of blinking.\n\r", ch );
return;
}
ch->pcdata->blink = URANGE( 0, ch->pcdata->blink * -1, 50 );
charprintf( ch, "You will attempt to blink at a rate of %d.\n\r",
ch->pcdata->blink );
return;
}
if( !str_cmp( argument, "off" ) )
{
if( ch->pcdata->blink <= 0 )
{
send_to_char( "You weren't blinking attacks.\n\r", ch );
return;
}
ch->pcdata->blink *= -1;
send_to_char( "You wont attempt to blink incoming attacks.\n\r", ch );
return;
}
if( !is_number( argument ) )
{
send_to_char( "Please specify a rate of blinking, 'on' or 'off'.\n\r",
ch );
return;
}
ch->pcdata->blink = URANGE( 0, atoi( argument ), 50 );
charprintf(
ch, "You will attempt to blink incoming attacks %d%% of the time.\n\r",
ch->pcdata->blink );
return;
}