/****************************************************************************
* _______ _ ______ _______ _______ ______ *
* ( ____ \( \ ( __ \ |\ /|( ___ )( )|\ /|( __ \ *
* | ( \/| ( | ( \ )| ) ( || ( ) || () () || ) ( || ( \ ) *
* | (__ | | | | ) || (___) || (___) || || || || | | || | ) | *
* | __) | | | | | || ___ || ___ || |(_)| || | | || | | | *
* | ( | | | | ) || ( ) || ( ) || | | || | | || | ) | *
* | (____/\| (____/\| (__/ )| ) ( || ) ( || ) ( || (___) || (__/ ) *
* (_______/(_______/(______/ |/ \||/ \||/ \|(_______)(______/ *
* +-+-+-+ +-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+ *
* |T|h|e| |O|a|k|l|a|n|d| |C|h|r|o|n|i|c|l|e|s| *
* +-+-+-+ +-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+ *
* ------------------------------------------------------------------------- *
* EldhaMUD code (C) 2003-2005 by Robert Powell (Tommi) *
* EldhaMUD Team: Celest, Altere and Krelowyn *
* ------------------------------------------------------------------------- *
* *
****************************************************************************/
/****************************************************************************
* [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// *
* -----------------------------------------------------------| (0...0) *
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( *
* -----------------------------------------------------------| {o o} *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ *
* Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~*
* Tricops and Fireblade | *
* ------------------------------------------------------------------------ *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* ------------------------------------------------------------------------ *
* Battle & death module *
****************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "./Headers/mud.h"
extern char lastplayercmd[MAX_INPUT_LENGTH];
extern CHAR_DATA *gch_prev;
OBJ_DATA *used_weapon; /* Used to figure out which weapon later */
/*
* Local functions.
*/
void new_dam_message args( ( CHAR_DATA * ch, CHAR_DATA * victim, int dam, int dt, OBJ_DATA * obj ) );
void group_gain args( ( CHAR_DATA * ch, CHAR_DATA * victim ) );
int xp_compute args( ( CHAR_DATA * gch, CHAR_DATA * victim ) );
int align_compute args( ( CHAR_DATA * gch, CHAR_DATA * victim ) );
ch_ret one_hit args( ( CHAR_DATA * ch, CHAR_DATA * victim, int dt ) );
int obj_hitroll args( ( OBJ_DATA * obj ) );
void show_condition args( ( CHAR_DATA * ch, CHAR_DATA * victim ) );
/*
* Check to see if player's attacks are (still?) suppressed
* #ifdef TRI
*/
bool is_attack_supressed( CHAR_DATA * ch )
{
TIMER *timer;
if( IS_NPC( ch ) )
return FALSE;
timer = get_timerptr( ch, TIMER_ASUPRESSED );
if( !timer )
return FALSE;
/*
* perma-supression -- bard? (can be reset at end of fight, or spell, etc)
*/
if( timer->value == -1 )
return TRUE;
/*
* this is for timed supressions
*/
if( timer->count >= 1 )
return TRUE;
return FALSE;
}
/*
* Check to see if weapon is poisoned.
*/
bool is_wielding_poisoned( CHAR_DATA * ch )
{
OBJ_DATA *obj;
if( !used_weapon )
return FALSE;
if( ( obj = get_eq_char( ch, WEAR_WIELD ) ) != NULL && used_weapon == obj && IS_OBJ_STAT( obj, ITEM_POISONED ) )
return TRUE;
if( ( obj = get_eq_char( ch, WEAR_DUAL_WIELD ) ) != NULL && used_weapon == obj && IS_OBJ_STAT( obj, ITEM_POISONED ) )
return TRUE;
return FALSE;
}
/*
* hunting, hating and fearing code -Thoric
*/
bool is_hunting( CHAR_DATA * ch, CHAR_DATA * victim )
{
if( !ch->hunting || ch->hunting->who != victim )
return FALSE;
return TRUE;
}
bool is_hating( CHAR_DATA * ch, CHAR_DATA * victim )
{
if( !ch->hating || ch->hating->who != victim )
return FALSE;
return TRUE;
}
bool is_fearing( CHAR_DATA * ch, CHAR_DATA * victim )
{
if( !ch->fearing || ch->fearing->who != victim )
return FALSE;
return TRUE;
}
void stop_hunting( CHAR_DATA * ch )
{
if( ch->hunting )
{
STRFREE( ch->hunting->name );
DISPOSE( ch->hunting );
ch->hunting = NULL;
}
return;
}
void stop_hating( CHAR_DATA * ch )
{
if( ch->hating )
{
STRFREE( ch->hating->name );
DISPOSE( ch->hating );
ch->hating = NULL;
}
return;
}
void stop_fearing( CHAR_DATA * ch )
{
if( ch->fearing )
{
STRFREE( ch->fearing->name );
DISPOSE( ch->fearing );
ch->fearing = NULL;
}
return;
}
void start_hunting( CHAR_DATA * ch, CHAR_DATA * victim )
{
if( ch->hunting )
stop_hunting( ch );
CREATE( ch->hunting, HHF_DATA, 1 );
ch->hunting->name = QUICKLINK( victim->name );
ch->hunting->who = victim;
return;
}
void start_hating( CHAR_DATA * ch, CHAR_DATA * victim )
{
if( ch->hating )
stop_hating( ch );
CREATE( ch->hating, HHF_DATA, 1 );
ch->hating->name = QUICKLINK( victim->name );
ch->hating->who = victim;
return;
}
void start_fearing( CHAR_DATA * ch, CHAR_DATA * victim )
{
if( ch->fearing )
stop_fearing( ch );
CREATE( ch->fearing, HHF_DATA, 1 );
ch->fearing->name = QUICKLINK( victim->name );
ch->fearing->who = victim;
return;
}
/*
* Get the current armor class for a vampire based on time of day
*/
short VAMP_AC( CHAR_DATA * ch )
{
if( IS_VAMPIRE( ch ) && xIS_OUTSIDE( ch ) )
{
switch ( time_info.sunlight )
{
case SUN_DARK:
return -10;
case SUN_RISE:
return 5;
case SUN_LIGHT:
return 10;
case SUN_SET:
return 2;
default:
return 0;
}
}
else
return 0;
}
int max_fight( CHAR_DATA * ch )
{
return 8;
}
/*
* Control the fights going on.
* Called periodically by update_handler.
* Many hours spent fixing bugs in here by Thoric, as noted by residual
* debugging checks. If you never get any of these error messages again
* in your logs... then you can comment out some of the checks without
* worry.
*
* Note: This function also handles some non-violence updates.
*/
void violence_update( void )
{
char buf[MAX_STRING_LENGTH];
CHAR_DATA *ch;
CHAR_DATA *lst_ch;
CHAR_DATA *victim;
CHAR_DATA *rch, *rch_next;
AFFECT_DATA *paf, *paf_next;
TIMER *timer, *timer_next;
ch_ret retcode;
int attacktype, cnt;
SKILLTYPE *skill;
static int pulse = 0;
short random_number;
lst_ch = NULL;
pulse = ( pulse + 1 ) % 100;
for( ch = last_char; ch; lst_ch = ch, ch = gch_prev )
{
set_cur_char( ch );
if( ch == first_char && ch->prev )
{
bug( "ERROR: first_char->prev != NULL, fixing...", 0 );
ch->prev = NULL;
}
gch_prev = ch->prev;
if( gch_prev && gch_prev->next != ch )
{
sprintf( buf, "FATAL: violence_update: %s->prev->next doesn't point to ch.", ch->name );
bug( buf, 0 );
bug( "Short-cutting here", 0 );
ch->prev = NULL;
gch_prev = NULL;
do_shout( ch, "Thoric says, 'Prepare for the worst!'" );
}
/*
* See if we got a pointer to someone who recently died...
* if so, either the pointer is bad... or it's a player who
* "died", and is back at the healer...
* Since he/she's in the char_list, it's likely to be the later...
* and should not already be in another fight already
*/
if( char_died( ch ) )
continue;
/*
* See if we got a pointer to some bad looking data...
*/
if( !ch->in_room || !ch->name )
{
log_string( "violence_update: bad ch record! (Shortcutting.)" );
sprintf( buf, "ch: %d ch->in_room: %d ch->prev: %d ch->next: %d",
( int )ch, ( int )ch->in_room, ( int )ch->prev, ( int )ch->next );
log_string( buf );
log_string( lastplayercmd );
if( lst_ch )
sprintf( buf, "lst_ch: %d lst_ch->prev: %d lst_ch->next: %d",
( int )lst_ch, ( int )lst_ch->prev, ( int )lst_ch->next );
else
strcpy( buf, "lst_ch: NULL" );
log_string( buf );
gch_prev = NULL;
continue;
}
/*
* Experience gained during battle deceases as battle drags on
*/
if( ch->fighting )
if( ( ++ch->fighting->duration % 24 ) == 0 )
ch->fighting->xp = ( ( ch->fighting->xp * 9 ) / 10 );
for( timer = ch->first_timer; timer; timer = timer_next )
{
timer_next = timer->next;
if( --timer->count <= 0 )
{
if( timer->type == TIMER_ASUPRESSED )
{
if( timer->value == -1 )
{
timer->count = 1000;
continue;
}
}
if( timer->type == TIMER_NUISANCE )
{
DISPOSE( ch->pcdata->nuisance );
}
if( timer->type == TIMER_DO_FUN )
{
int tempsub;
tempsub = ch->substate;
ch->substate = timer->value;
( timer->do_fun ) ( ch, "" );
if( char_died( ch ) )
break;
ch->substate = tempsub;
}
extract_timer( ch, timer );
}
}
if( char_died( ch ) )
continue;
/*
* We need spells that have shorter durations than an hour.
* So a melee round sounds good to me... -Thoric
*/
for( paf = ch->first_affect; paf; paf = paf_next )
{
paf_next = paf->next;
if( paf->duration > 0 )
paf->duration--;
else if( paf->duration < 0 )
;
else
{
if( !paf_next || paf_next->type != paf->type || paf_next->duration > 0 )
{
skill = get_skilltype( paf->type );
if( paf->type > 0 && skill && skill->msg_off )
{
set_char_color( AT_WEAROFF, ch );
send_to_char( skill->msg_off, ch );
send_to_char( "\n\r", ch );
}
}
if( paf->type == gsn_possess )
{
ch->desc->character = ch->desc->original;
ch->desc->original = NULL;
ch->desc->character->desc = ch->desc;
ch->desc->character->switched = NULL;
ch->desc = NULL;
}
affect_remove( ch, paf );
}
}
if( char_died( ch ) )
continue;
/*
* check for exits moving players around
*/
if( ( retcode = pullcheck( ch, pulse ) ) == rCHAR_DIED || char_died( ch ) )
continue;
/*
* Let the battle begin!
*/
if( ( victim = who_fighting( ch ) ) == NULL || IS_AFFECTED( ch, AFF_PARALYSIS ) )
continue;
retcode = rNONE;
if( xIS_SET( ch->in_room->room_flags, ROOM_SAFE ) )
{
sprintf( buf, "violence_update: %s fighting %s in a SAFE room.", ch->name, victim->name );
log_string( buf );
stop_fighting( ch, TRUE );
}
else if( IS_AWAKE( ch ) && ch->in_room == victim->in_room )
retcode = multi_hit( ch, victim, TYPE_UNDEFINED );
else
stop_fighting( ch, FALSE );
if( char_died( ch ) )
continue;
if( retcode == rCHAR_DIED || ( victim = who_fighting( ch ) ) == NULL )
continue;
/*
* Mob triggers
* -- Added some victim death checks, because it IS possible.. -- Alty
*/
rprog_rfight_trigger( ch );
if( char_died( ch ) || char_died( victim ) )
continue;
mprog_hitprcnt_trigger( ch, victim );
if( char_died( ch ) || char_died( victim ) )
continue;
mprog_fight_trigger( ch, victim );
if( char_died( ch ) || char_died( victim ) )
continue;
/*
* NPC special attack flags -Thoric
*/
if( IS_NPC( ch ) )
{
if( !xIS_EMPTY( ch->attacks ) )
{
attacktype = -1;
if( 30 + ( ch->level / 4 ) >= number_percent( ) )
{
cnt = 0;
for( ;; )
{
if( cnt++ > 10 )
{
attacktype = -1;
break;
}
attacktype = number_range( 7, MAX_ATTACK_TYPE - 1 );
if( xIS_SET( ch->attacks, attacktype ) )
break;
}
switch ( attacktype )
{
case ATCK_BASH:
do_bash( ch, "" );
retcode = global_retcode;
break;
case ATCK_DRAIN:
retcode = spell_energy_drain( skill_lookup( "energy drain" ), ch->level, ch, victim );
break;
case ATCK_FIREBREATH:
retcode = spell_fire_breath( skill_lookup( "fire breath" ), ch->level, ch, victim );
break;
case ATCK_FROSTBREATH:
retcode = spell_frost_breath( skill_lookup( "frost breath" ), ch->level, ch, victim );
break;
case ATCK_ACIDBREATH:
retcode = spell_acid_breath( skill_lookup( "acid breath" ), ch->level, ch, victim );
break;
case ATCK_LIGHTNBREATH:
retcode = spell_lightning_breath( skill_lookup( "lightning breath" ), ch->level, ch, victim );
break;
case ATCK_GASBREATH:
retcode = spell_gas_breath( skill_lookup( "gas breath" ), ch->level, ch, victim );
break;
case ATCK_POISON:
retcode = spell_poison( gsn_poison, ch->level, ch, victim );
break;
case ATCK_BLINDNESS:
retcode = spell_blindness( gsn_blindness, ch->level, ch, victim );
break;
case ATCK_CURSE:
retcode = spell_curse( skill_lookup( "curse" ), ch->level, ch, victim );
break;
case ATCK_FIREBALL:
retcode = spell_fireball( skill_lookup( "fireball" ), ch->level, ch, victim );
break;
case ATCK_FFIRE:
retcode = spell_faerie_fire( skill_lookup( "faerie fire" ), ch->level, ch, victim );
break;
case ATCK_FFOG:
retcode = spell_faerie_fog( skill_lookup( "faerie fog" ), ch->level, ch, victim );
break;
}
if( attacktype != -1 && ( retcode == rCHAR_DIED || char_died( ch ) ) )
continue;
}
}
/*
* NPC special defense flags -Thoric
*/
if( !xIS_EMPTY( ch->defenses ) )
{
attacktype = -1;
if( 50 + ( ch->level / 4 ) > number_percent( ) )
{
cnt = 0;
for( ;; )
{
if( cnt++ > 10 )
{
attacktype = -1;
break;
}
attacktype = number_range( 2, MAX_DEFENSE_TYPE - 1 );
if( xIS_SET( ch->defenses, attacktype ) )
break;
}
switch ( attacktype )
{
case DFND_HEAL:
if( ch->hit < ch->max_hit )
{
act( AT_MAGIC, "$n mutters a few incantations...and looks much healthier.", ch, NULL, NULL,
TO_ROOM );
retcode = spell_smaug( skill_lookup( "heal" ), ch->level, ch, ch );
}
break;
case DFND_DISPELMAGIC:
if( victim->first_affect )
{
act( AT_MAGIC, "$n utters an incantation...", ch, NULL, NULL, TO_ROOM );
random_number = number_range( 0, 9 );
if( random_number == 5 )
{
retcode = spell_dispel_magic( skill_lookup( "dispel magic" ), ch->level, ch, victim );
}
else
{
act( AT_MAGIC, "$n fails in its attempt to dispel your magic...", ch, NULL, NULL, TO_ROOM );
}
}
break;
case DFND_TELEPORT:
retcode = spell_teleport( skill_lookup( "teleport" ), ch->level, ch, ch );
break;
case DFND_TRUESIGHT:
if( !IS_AFFECTED( ch, AFF_TRUESIGHT ) )
retcode = spell_smaug( skill_lookup( "true" ), ch->level, ch, ch );
else
retcode = rNONE;
break;
}
if( attacktype != -1 && ( retcode == rCHAR_DIED || char_died( ch ) ) )
continue;
}
}
}
/*
* Fun for the whole family!
*/
for( rch = ch->in_room->first_person; rch; rch = rch_next )
{
rch_next = rch->next_in_room;
/*
* Group Fighting Styles Support:
* If ch is tanking
* If rch is using a more aggressive style than ch
* Then rch is the new tank -h
*/
/*
* &&( is_same_group(ch, rch) )
*/
if( ( !IS_NPC( ch ) && !IS_NPC( rch ) )
&& ( rch != ch )
&& ( rch->fighting )
&& ( who_fighting( rch->fighting->who ) == ch )
&& ( !xIS_SET( rch->fighting->who->act, ACT_AUTONOMOUS ) ) && ( rch->style < ch->style ) )
{
rch->fighting->who->fighting->who = rch;
}
if( IS_AWAKE( rch ) && !rch->fighting )
{
/*
* PC's auto-assist others in their group.
*/
if( !IS_NPC( ch ) || IS_AFFECTED( ch, AFF_CHARM ) )
{
if( ( ( !IS_NPC( rch ) && rch->desc )
|| IS_AFFECTED( rch, AFF_CHARM ) ) && is_same_group( ch, rch ) && !is_safe( rch, victim, TRUE ) )
multi_hit( rch, victim, TYPE_UNDEFINED );
continue;
}
/*
* NPC's assist NPC's of same type or 12.5% chance regardless.
*/
if( IS_NPC( rch ) && !IS_AFFECTED( rch, AFF_CHARM ) && !xIS_SET( rch->act, ACT_NOASSIST )
&& !xIS_SET( rch->act, ACT_PET ) )
{
if( char_died( ch ) )
break;
if( rch->pIndexData == ch->pIndexData || number_bits( 3 ) == 0 )
{
CHAR_DATA *vch;
CHAR_DATA *target;
int number;
target = NULL;
number = 0;
for( vch = ch->in_room->first_person; vch; vch = vch->next_in_room )
{
if( can_see( rch, vch, FALSE ) && is_same_group( vch, victim ) && number_range( 0, number ) == 0 )
{
if( vch->mount && vch->mount == rch )
target = NULL;
else
{
target = vch;
number++;
}
}
}
if( target )
multi_hit( rch, target, TYPE_UNDEFINED );
}
}
}
}
}
return;
}
/*
* Do one group of attacks.
*/
ch_ret multi_hit( CHAR_DATA * ch, CHAR_DATA * victim, int dt )
{
int schance;
int dual_bonus;
ch_ret retcode;
/*
* add timer to pkillers
*/
if( !IS_NPC( ch ) && !IS_NPC( victim ) )
{
if( xIS_SET( ch->act, PLR_NICE ) )
return rNONE;
add_timer( ch, TIMER_RECENTFIGHT, 11, NULL, 0 );
add_timer( victim, TIMER_RECENTFIGHT, 11, NULL, 0 );
}
if( is_attack_supressed( ch ) )
return rNONE;
if( IS_NPC( ch ) && xIS_SET( ch->act, ACT_NOATTACK ) )
return rNONE;
if( ( retcode = one_hit( ch, victim, dt ) ) != rNONE )
return retcode;
if( who_fighting( ch ) != victim || dt == gsn_backstab || dt == gsn_circle )
return rNONE;
/*
* Very high chance of hitting compared to chance of going berserk
*/
/*
* 40% or higher is always hit.. don't learn anything here though.
*/
/*
* -- Altrag
*/
schance = IS_NPC( ch ) ? 100 : ( LEARNED( ch, gsn_berserk ) * 5 / 2 );
if( IS_AFFECTED( ch, AFF_BERSERK ) && number_percent( ) < schance )
if( ( retcode = one_hit( ch, victim, dt ) ) != rNONE || who_fighting( ch ) != victim )
return retcode;
if( get_eq_char( ch, WEAR_DUAL_WIELD ) )
{
dual_bonus = IS_NPC( ch ) ? ( ch->level / 10 ) : ( LEARNED( ch, gsn_dual_wield ) / 10 );
schance = IS_NPC( ch ) ? ch->level : LEARNED( ch, gsn_dual_wield );
if( number_percent( ) < schance )
{
learn_from_success( ch, gsn_dual_wield );
retcode = one_hit( ch, victim, dt );
if( retcode != rNONE || who_fighting( ch ) != victim )
return retcode;
}
else
learn_from_failure( ch, gsn_dual_wield );
}
else
dual_bonus = 0;
if( ch->move < 10 )
dual_bonus = -20;
/*
* NPC predetermined number of attacks -Thoric
*/
if( IS_NPC( ch ) && ch->numattacks > 0 )
{
for( schance = 0; schance < ch->numattacks; schance++ )
{
retcode = one_hit( ch, victim, dt );
if( retcode != rNONE || who_fighting( ch ) != victim )
return retcode;
}
return retcode;
}
schance = IS_NPC( ch ) ? ch->level : ( int )( ( LEARNED( ch, gsn_second_attack ) + dual_bonus ) / 1.5 );
if( number_percent( ) < schance )
{
learn_from_success( ch, gsn_second_attack );
retcode = one_hit( ch, victim, dt );
if( retcode != rNONE || who_fighting( ch ) != victim )
return retcode;
}
else
learn_from_failure( ch, gsn_second_attack );
schance = IS_NPC( ch ) ? ch->level : ( int )( ( LEARNED( ch, gsn_third_attack ) + ( dual_bonus * 1.5 ) ) / 2 );
if( number_percent( ) < schance )
{
learn_from_success( ch, gsn_third_attack );
retcode = one_hit( ch, victim, dt );
if( retcode != rNONE || who_fighting( ch ) != victim )
return retcode;
}
else
learn_from_failure( ch, gsn_third_attack );
schance = IS_NPC( ch ) ? ch->level : ( int )( ( LEARNED( ch, gsn_fourth_attack ) + ( dual_bonus * 2 ) ) / 3 );
if( number_percent( ) < schance )
{
learn_from_success( ch, gsn_fourth_attack );
retcode = one_hit( ch, victim, dt );
if( retcode != rNONE || who_fighting( ch ) != victim )
return retcode;
}
else
learn_from_failure( ch, gsn_fourth_attack );
schance = IS_NPC( ch ) ? ch->level : ( int )( ( LEARNED( ch, gsn_fifth_attack ) + ( dual_bonus * 3 ) ) / 4 );
if( number_percent( ) < schance )
{
learn_from_success( ch, gsn_fifth_attack );
retcode = one_hit( ch, victim, dt );
if( retcode != rNONE || who_fighting( ch ) != victim )
return retcode;
}
else
learn_from_failure( ch, gsn_fifth_attack );
schance = IS_NPC( ch ) ? ch->level : ( int )( ( LEARNED( ch, gsn_sixth_attack ) + dual_bonus ) / 1.5 );
if( number_percent( ) < schance )
{
learn_from_success( ch, gsn_sixth_attack );
retcode = one_hit( ch, victim, dt );
if( retcode != rNONE || who_fighting( ch ) != victim )
return retcode;
}
else
learn_from_failure( ch, gsn_sixth_attack );
schance = IS_NPC( ch ) ? ch->level : ( int )( ( LEARNED( ch, gsn_seventh_attack ) + dual_bonus ) / 1.5 );
if( number_percent( ) < schance )
{
learn_from_success( ch, gsn_seventh_attack );
retcode = one_hit( ch, victim, dt );
if( retcode != rNONE || who_fighting( ch ) != victim )
return retcode;
}
else
learn_from_failure( ch, gsn_seventh_attack );
schance = IS_NPC( ch ) ? ch->level : ( int )( ( LEARNED( ch, gsn_eighth_attack ) + dual_bonus ) / 1.5 );
if( number_percent( ) < schance )
{
learn_from_success( ch, gsn_eighth_attack );
retcode = one_hit( ch, victim, dt );
if( retcode != rNONE || who_fighting( ch ) != victim )
return retcode;
}
else
learn_from_failure( ch, gsn_eighth_attack );
retcode = rNONE;
schance = IS_NPC( ch ) ? ( int )( ch->level / 2 ) : 0;
if( number_percent( ) < schance )
retcode = one_hit( ch, victim, dt );
if( retcode == rNONE )
{
int move;
if( !IS_AFFECTED( ch, AFF_FLYING ) && !IS_AFFECTED( ch, AFF_FLOATING ) )
move = encumbrance( ch, movement_loss[UMIN( SECT_MAX - 1, ch->in_room->sector_type )] );
else
move = encumbrance( ch, 1 );
if( ch->move )
ch->move = UMAX( 0, ch->move - move );
}
return retcode;
}
/*
* Weapon types, haus
*/
int weapon_prof_bonus_check( CHAR_DATA * ch, OBJ_DATA * wield, int *gsn_ptr )
{
int bonus;
bonus = 0;
*gsn_ptr = gsn_pugilism; /* Change back to -1 if this fails horribly */
if( !IS_NPC( ch ) && wield )
{
switch ( wield->value[4] )
{
/*
* Restructured weapon system - Samson 11-20-99
*/
default:
*gsn_ptr = -1;
break;
case WEP_BAREHAND:
*gsn_ptr = gsn_pugilism;
break;
case WEP_SWORD:
*gsn_ptr = gsn_swords;
break;
case WEP_DAGGER:
*gsn_ptr = gsn_daggers;
break;
case WEP_WHIP:
*gsn_ptr = gsn_whips;
break;
case WEP_TALON:
*gsn_ptr = gsn_talonous_arms;
break;
case WEP_MACE:
*gsn_ptr = gsn_maces_hammers;
break;
case WEP_ARCHERY:
*gsn_ptr = gsn_archery;
break;
case WEP_BLOWGUN:
*gsn_ptr = gsn_blowguns;
break;
case WEP_SLING:
*gsn_ptr = gsn_slings;
break;
case WEP_AXE:
*gsn_ptr = gsn_axes;
break;
case WEP_SPEAR:
*gsn_ptr = gsn_spears;
break;
case WEP_STAFF:
*gsn_ptr = gsn_staves;
break;
case WEP_POLEARM:
*gsn_ptr = gsn_polearm;
break;
}
if( *gsn_ptr != -1 )
bonus = ( int )( ( LEARNED( ch, *gsn_ptr ) - 50 ) / 10 );
/*
* Reduce weapon bonuses for misaligned clannies.
* if ( IS_CLANNED(ch) )
* {
* bonus = bonus /
* ( 1 + abs( ch->alignment - ch->pcdata->clan->alignment ) / 1000 );
* }
*/
if( IS_DEVOTED( ch ) )
bonus -= ch->pcdata->favor / -400;
}
return bonus;
}
/*
* Calculate the tohit bonus on the object and return RIS values.
* -- Altrag
*/
int obj_hitroll( OBJ_DATA * obj )
{
int tohit = 0;
AFFECT_DATA *paf;
for( paf = obj->pIndexData->first_affect; paf; paf = paf->next )
if( paf->location == APPLY_HITROLL )
tohit += paf->modifier;
for( paf = obj->first_affect; paf; paf = paf->next )
if( paf->location == APPLY_HITROLL )
tohit += paf->modifier;
return tohit;
}
/*
* Offensive shield level modifier
*/
short off_shld_lvl( CHAR_DATA * ch, CHAR_DATA * victim )
{
short lvl;
if( !IS_NPC( ch ) ) /* players get much less effect */
{
lvl = UMAX( 1, ( ch->level - 10 ) / 2 );
if( number_percent( ) + ( victim->level - lvl ) < 40 )
{
if( CAN_PKILL( ch ) && CAN_PKILL( victim ) )
return ch->level;
else
return lvl;
}
else
return 0;
}
else
{
lvl = ch->level / 2;
if( number_percent( ) + ( victim->level - lvl ) < 70 )
return lvl;
else
return 0;
}
}
/*
* Hit one guy once.
*/
ch_ret one_hit( CHAR_DATA * ch, CHAR_DATA * victim, int dt )
{
OBJ_DATA *wield;
int victim_ac;
int thac0;
int thac0_00;
int thac0_32;
int plusris;
int dam;
int diceroll;
int attacktype, cnt;
int prof_bonus;
int prof_gsn = -1;
ch_ret retcode = rNONE;
static bool dual_flip = FALSE;
short random_number;
/*
* Can't beat a dead char!
* Guard against weird room-leavings.
*/
if( victim->position == POS_DEAD || ch->in_room != victim->in_room )
return rVICT_DIED;
used_weapon = NULL;
/*
* Figure out the weapon doing the damage -Thoric
* Dual wield support -- switch weapons each attack
*/
if( ( wield = get_eq_char( ch, WEAR_DUAL_WIELD ) ) != NULL )
{
if( dual_flip == FALSE )
{
dual_flip = TRUE;
wield = get_eq_char( ch, WEAR_WIELD );
}
else
dual_flip = FALSE;
}
else
wield = get_eq_char( ch, WEAR_WIELD );
used_weapon = wield;
if( wield )
prof_bonus = weapon_prof_bonus_check( ch, wield, &prof_gsn );
else
prof_bonus = 0;
if( ch->fighting /* make sure fight is already started */
&& dt == TYPE_UNDEFINED && IS_NPC( ch ) && !xIS_EMPTY( ch->attacks ) )
{
cnt = 0;
for( ;; )
{
attacktype = number_range( 0, 6 );
if( xIS_SET( ch->attacks, attacktype ) )
break;
if( cnt++ > 16 )
{
attacktype = -1;
break;
}
}
if( attacktype == ATCK_BACKSTAB )
attacktype = -1;
if( wield && number_percent( ) > 25 )
attacktype = -1;
if( !wield && number_percent( ) > 50 )
attacktype = -1;
switch ( attacktype )
{
default:
break;
case ATCK_PUNCH:
do_punch( ch, "" );
retcode = global_retcode;
break;
case ATCK_KICK:
do_kick( ch, "" );
retcode = global_retcode;
break;
case ATCK_HEADBUTT:
do_headbutt( ch, "" );
retcode = global_retcode;
break;
case ATCK_ROUNDHOUSE:
do_roundhouse( ch, "" );
retcode = global_retcode;
break;
case ATCK_TRIP:
attacktype = 0;
break;
}
if( attacktype >= 0 )
return retcode;
}
if( dt == TYPE_UNDEFINED )
{
dt = TYPE_HIT;
if( wield && wield->item_type == ITEM_WEAPON )
dt += wield->value[3];
}
/*
* Calculate to-hit-armor-class-0 versus armor.
*/
if( IS_NPC( ch ) )
{
thac0_00 = ch->mobthac0;
thac0_32 = 0;
}
else
{
thac0_00 = class_table[ch->class]->thac0_00;
thac0_32 = class_table[ch->class]->thac0_32;
}
thac0 = interpolate( ch->level, thac0_00, thac0_32 ) - GET_HITROLL( ch );
victim_ac = UMAX( -19, ( int )( GET_AC( victim ) / 10 ) );
/*
* if you can't see what's coming...
*/
if( wield && !can_see_obj( victim, wield ) )
victim_ac += 1;
if( !can_see( ch, victim, FALSE ) )
victim_ac -= 4;
/*
* "learning" between combatants. Takes the intelligence difference,
* and multiplies by the times killed to make up a learning bonus
* given to whoever is more intelligent -Thoric
* (basically the more intelligent one "learns" the other's fighting style)
*/
if( ch->fighting && ch->fighting->who == victim )
{
short times = ch->fighting->timeskilled;
if( times )
{
short intdiff = get_curr_int( ch ) - get_curr_int( victim );
if( intdiff != 0 )
victim_ac += ( intdiff * times ) / 10;
}
}
/*
* Weapon proficiency bonus
*/
victim_ac += prof_bonus;
/*
* The moment of excitement!
*/
while( ( diceroll = number_bits( 5 ) ) >= 20 )
;
if( diceroll == 0 )
{
/*
* Physical hit with no damage (hit natural AC) -Seven
*/
if( diceroll < thac0 - victim_ac
&& diceroll >=
thac0 - ( 10 + ( dex_app[get_curr_dex( ch )].defensive / 10 ) + ( race_table[victim->race]->ac_plus / 10 ) )
&& diceroll != 19 && diceroll != 0 )
{
if( prof_gsn != -1 )
learn_from_failure( ch, prof_gsn );
act( AT_PLAIN, "Your attack is deflected by $N's armor.", ch, NULL, victim, TO_CHAR );
act( AT_PLAIN, "Your armor deflects $n's attack.", ch, NULL, victim, TO_VICT );
if( !victim->fighting && victim->in_room == ch->in_room )
set_fighting( victim, ch );
tail_chain( );
return rNONE;
}
else
{
/*
* Miss.
*/
if( prof_gsn != -1 )
learn_from_failure( ch, prof_gsn );
damage( ch, victim, 0, dt );
tail_chain( );
return rNONE;
}
}
/*
* Hit.
* Calc damage.
*/
if( !wield ) /* bare hand dice formula fixed by Thoric */
/*
* Fixed again by korbillian@mud.tka.com 4000 (Cold Fusion Mud)
*/
dam = number_range( ch->barenumdie, ch->baresizedie * ch->barenumdie ) + ch->damplus;
else
dam = number_range( wield->value[1], wield->value[2] );
/*
* Critical Hit -- Add onto by randomizing the critical hit and damage...
* By: Josh Jenks [Haelyn]...snippet for SMAUG 1.4a
* Added in and changed by Odis
*/
if( diceroll >= 19 )
{
int place;
place = number_range( 1, 4 );
if( place == 1 )
{
act( AT_FIRE, "You hit $N's hand!", ch, NULL, victim, TO_CHAR );
act( AT_FIRE, "$n hits your hand!", ch, NULL, victim, TO_VICT );
act( AT_FIRE, "$n hits $N's!", ch, NULL, victim, TO_NOTVICT );
dam *= 1.5;
}
else if( place == 2 )
{
act( AT_FIRE, "You critically hit $N in the chest!", ch, NULL, victim, TO_CHAR );
act( AT_FIRE, "$n critically hits you in the chest!", ch, NULL, victim, TO_VICT );
act( AT_FIRE, "$n critically hits $N in the chest!", ch, NULL, victim, TO_NOTVICT );
dam *= 2;
}
else if( place == 3 )
{
act( AT_FIRE, "You bash $N's head!", ch, NULL, victim, TO_CHAR );
act( AT_FIRE, "$n bashes your head!", ch, NULL, victim, TO_VICT );
act( AT_FIRE, "$n bashes $N's head!", ch, NULL, victim, TO_NOTVICT );
dam *= 3;
}
else if( place == 4 )
{
act( AT_FIRE, "You mutilate $N's groin!", ch, NULL, victim, TO_CHAR );
act( AT_FIRE, "$n mutilates you in the groin!", ch, NULL, victim, TO_VICT );
act( AT_FIRE, "$n mutilates $N's groin!", ch, NULL, victim, TO_NOTVICT );
dam *= 2;
}
}
/*
* Bonuses.
*/
dam += GET_DAMROLL( ch );
if( prof_bonus )
dam += prof_bonus / 4;
/*
* Calculate Damage Modifiers from Victim's Fighting Style
*/
if( victim->position == POS_BERSERK )
dam = 1.2 * dam;
else if( victim->position == POS_AGGRESSIVE )
dam = 1.1 * dam;
else if( victim->position == POS_DEFENSIVE )
dam = .85 * dam;
else if( victim->position == POS_EVASIVE )
dam = .8 * dam;
/* Auto increase styles and modify damage based on character's fighting style
code cut from smaugfuss boards, by Remcon
*/
switch( ch->style )
{
default:
case STYLE_FIGHTING:
if( !IS_NPC( ch ) && ch->pcdata->learned[gsn_style_standard] > -1 )
learn_from_success( ch, gsn_style_standard );
break;
case STYLE_DEFENSIVE:
if( !IS_NPC( ch ) && ch->pcdata->learned[gsn_style_defensive] > -1 )
learn_from_success( ch, gsn_style_defensive );
dam = ( int )( .85 * dam );
break;
case STYLE_EVASIVE:
if( !IS_NPC( ch ) && ch->pcdata->learned[gsn_style_evasive] > -1 )
learn_from_success( ch, gsn_style_evasive );
dam = ( int )( .8 * dam );
break;
case STYLE_AGGRESSIVE:
if( !IS_NPC( ch ) && ch->pcdata->learned[gsn_style_aggressive] > -1 )
learn_from_success( ch, gsn_style_aggressive );
dam = ( int )( 1.1 * dam );
break;
case STYLE_BERSERK:
if( !IS_NPC( ch ) && ch->pcdata->learned[gsn_style_berserk] > -1 )
learn_from_success( ch, gsn_style_berserk );
dam = ( int )( 1.2 * dam );
break;
}
if( !IS_NPC( ch ) && ch->pcdata->learned[gsn_enhanced_damage] > 0 )
{
dam += ( int )( dam * LEARNED( ch, gsn_enhanced_damage ) / 120 );
learn_from_success( ch, gsn_enhanced_damage );
}
if( !IS_AWAKE( victim ) )
dam *= 2;
if( dt == gsn_backstab )
{
if( !IS_NPC( victim ) )
{
dam *= ( 2 + URANGE( 2, ch->level - ( victim->level / 8 ), 30 ) / 16 );
}
else
{
dam *= ( 2 + URANGE( 2, ch->level - ( victim->level / 4 ), 30 ) / 8 );
}
}
if( dt == gsn_circle )
{
if( !IS_NPC( victim ) )
{
dam *= ( 2 + URANGE( 2, ch->level - ( victim->level / 8 ), 30 ) / 20 );
}
else
dam *= ( 2 + URANGE( 2, ch->level - ( victim->level / 4 ), 30 ) / 16 );
}
if( dam <= 0 )
dam = 1;
plusris = 0;
if( wield )
{
if( IS_OBJ_STAT( wield, ITEM_MAGIC ) )
dam = ris_damage( victim, dam, RIS_MAGIC );
else
dam = ris_damage( victim, dam, RIS_NONMAGIC );
/*
* Handle PLUS1 - PLUS6 ris bits vs. weapon hitroll -Thoric
*/
plusris = obj_hitroll( wield );
}
else
dam = ris_damage( victim, dam, RIS_NONMAGIC );
/*
* check for RIS_PLUSx -Thoric
*/
if( dam )
{
int x, res, imm, sus, mod;
if( plusris )
plusris = RIS_PLUS1 << UMIN( plusris, 7 );
/*
* initialize values to handle a zero plusris
*/
imm = res = -1;
sus = 1;
/*
* find high ris
*/
for( x = RIS_PLUS1; x <= RIS_PLUS6; x <<= 1 )
{
if( IS_SET( victim->immune, x ) )
imm = x;
if( IS_SET( victim->resistant, x ) )
res = x;
if( IS_SET( victim->susceptible, x ) )
sus = x;
}
mod = 10;
if( imm >= plusris )
mod -= 10;
if( res >= plusris )
mod -= 2;
if( sus <= plusris )
mod += 2;
/*
* check if immune
*/
if( mod <= 0 )
dam = -1;
if( mod != 10 )
dam = ( dam * mod ) / 10;
}
if( prof_gsn != -1 )
{
if( dam > 0 )
learn_from_success( ch, prof_gsn );
else
learn_from_failure( ch, prof_gsn );
}
/*
* immune to damage
*/
if( dam == -1 )
{
if( dt >= 0 && dt < top_sn )
{
SKILLTYPE *skill = skill_table[dt];
bool found = FALSE;
if( skill->imm_char && skill->imm_char[0] != '\0' )
{
act( AT_HIT, skill->imm_char, ch, NULL, victim, TO_CHAR );
found = TRUE;
}
if( skill->imm_vict && skill->imm_vict[0] != '\0' )
{
act( AT_HITME, skill->imm_vict, ch, NULL, victim, TO_VICT );
found = TRUE;
}
if( skill->imm_room && skill->imm_room[0] != '\0' )
{
act( AT_ACTION, skill->imm_room, ch, NULL, victim, TO_NOTVICT );
found = TRUE;
}
if( found )
return rNONE;
}
dam = 0;
}
if( ( retcode = damage( ch, victim, dam, dt ) ) != rNONE )
return retcode;
if( char_died( ch ) )
return rCHAR_DIED;
if( char_died( victim ) )
return rVICT_DIED;
retcode = rNONE;
if( dam == 0 )
return retcode;
/*
* Weapon spell support -Thoric
Modified by Tommi, to hit only 1 in 6 Sept 2005
*/
random_number = number_range( 0, 5 );
if( random_number == 1 )
{
if( wield && !IS_SET( victim->immune, RIS_MAGIC ) && !xIS_SET( victim->in_room->room_flags, ROOM_NO_MAGIC ) )
{
AFFECT_DATA *aff;
for( aff = wield->pIndexData->first_affect; aff; aff = aff->next )
if( aff->location == APPLY_WEAPONSPELL && IS_VALID_SN( aff->modifier ) && skill_table[aff->modifier]->spell_fun )
retcode = ( *skill_table[aff->modifier]->spell_fun ) ( aff->modifier, ( wield->level + 3 ) / 2, ch, victim );
if( retcode != rNONE || char_died( ch ) || char_died( victim ) )
return retcode;
for( aff = wield->first_affect; aff; aff = aff->next )
if( aff->location == APPLY_WEAPONSPELL && IS_VALID_SN( aff->modifier ) && skill_table[aff->modifier]->spell_fun )
retcode = ( *skill_table[aff->modifier]->spell_fun ) ( aff->modifier, ( wield->level + 3 ) / 2, ch, victim );
if( retcode != rNONE || char_died( ch ) || char_died( victim ) )
return retcode;
}
}
/*
* magic shields that retaliate -Thoric
* Modified by tommi, to not use spells, and to roll for success Aug 2005
*/
random_number = number_range( 0, 12 );
if( random_number == 5 )
{
if( IS_AFFECTED( victim, AFF_FIRESHIELD ) && !IS_AFFECTED( ch, AFF_FIRESHIELD ) )
{
act( AT_MAGIC, "Flames leap off of $N shield of flames and hit you.", ch, NULL, victim, TO_CHAR );
act( AT_MAGIC, "Flames leap off of $n's fireshield hitting $N.", ch, NULL, victim, TO_NOTVICT );
}
else if( IS_AFFECTED( victim, AFF_ICESHIELD ) && !IS_AFFECTED( ch, AFF_ICESHIELD ) )
{
act( AT_MAGIC, "Shards of ice leap off of $N iceshield and hit you.", ch, NULL, victim, TO_CHAR );
act( AT_MAGIC, "Ice shards leap off of $n's iceshield hitting $N.", ch, NULL, victim, TO_NOTVICT );
}
else if( IS_AFFECTED( victim, AFF_SHOCKSHIELD ) && !IS_AFFECTED( ch, AFF_SHOCKSHIELD ) )
{
act( AT_MAGIC, "Shockwaves leap off of $N shockshield and hit you.", ch, NULL, victim, TO_CHAR );
act( AT_MAGIC, "Shockwaves leap off of $n's fireshield hitting $N.", ch, NULL, victim, TO_NOTVICT );
}
else if( IS_AFFECTED( victim, AFF_ACIDMIST ) && !IS_AFFECTED( ch, AFF_ACIDMIST ) )
{
act( AT_MAGIC, "Drops of acid leap off of $N shield of acid and hit you.", ch, NULL, victim, TO_CHAR );
act( AT_MAGIC, "Drops of acid leap off of $n's fireshield hitting $N.", ch, NULL, victim, TO_NOTVICT );
}
else if( IS_AFFECTED( victim, AFF_VENOMSHIELD ) && !IS_AFFECTED( ch, AFF_VENOMSHIELD ) )
{
act( AT_MAGIC, "Flames leap off of $N shield of flames and hit you.", ch, NULL, victim, TO_CHAR );
act( AT_MAGIC, "Flames off of $n's fireshield hitting $N.", ch, NULL, victim, TO_NOTVICT );
}
dam = dice( 4, ( ch->level / 3 ) );
retcode = damage( ch, victim, dam, DAM_MAGIC );
if( retcode != rNONE || char_died( ch ) || char_died( victim ) )
return retcode;
}
tail_chain( );
return retcode;
}
/*
* Calculate damage based on resistances, immunities and suceptibilities
* -Thoric
*/
short ris_damage( CHAR_DATA * ch, short dam, int ris )
{
short modifier;
modifier = 10;
if( IS_SET( ch->immune, ris ) && !IS_SET( ch->no_immune, ris ) )
modifier -= 10;
if( IS_SET( ch->resistant, ris ) && !IS_SET( ch->no_resistant, ris ) )
modifier -= 2;
if( IS_SET( ch->susceptible, ris ) && !IS_SET( ch->no_susceptible, ris ) )
{
if( IS_NPC( ch ) && IS_SET( ch->immune, ris ) )
modifier += 0;
else
modifier += 2;
}
if( modifier <= 0 )
return -1;
if( modifier == 10 )
return dam;
return ( dam * modifier ) / 10;
}
/*
* Inflict damage from a hit. This is one damn big function.
*/
ch_ret damage( CHAR_DATA * ch, CHAR_DATA * victim, int dam, int dt )
{
char buf[MAX_STRING_LENGTH];
char buf1[MAX_STRING_LENGTH];
char filename[256];
short dameq;
short maxdam;
bool npcvict;
bool loot;
OBJ_DATA *damobj;
ch_ret retcode;
short dampmod;
CHAR_DATA *gch /*, *lch */ ;
int init_gold, new_gold, gold_diff;
short anopc = 0; /* # of (non-pkill) pc in a (ch) */
short bnopc = 0; /* # of (non-pkill) pc in b (victim) */
retcode = rNONE;
if( !ch )
{
bug( "Damage: null ch!", 0 );
return rERROR;
}
if( !victim )
{
bug( "Damage: null victim!", 0 );
return rVICT_DIED;
}
if( victim->position == POS_DEAD )
return rVICT_DIED;
npcvict = IS_NPC( victim );
/*
* Check damage types for RIS -Thoric
*/
if( dam && dt != TYPE_UNDEFINED )
{
if( IS_FIRE( dt ) )
dam = ris_damage( victim, dam, RIS_FIRE );
else if( IS_COLD( dt ) )
dam = ris_damage( victim, dam, RIS_COLD );
else if( IS_ACID( dt ) )
dam = ris_damage( victim, dam, RIS_ACID );
else if( IS_ELECTRICITY( dt ) )
dam = ris_damage( victim, dam, RIS_ELECTRICITY );
else if( IS_ENERGY( dt ) )
dam = ris_damage( victim, dam, RIS_ENERGY );
else if( IS_DRAIN( dt ) )
dam = ris_damage( victim, dam, RIS_DRAIN );
else if( dt == gsn_poison || IS_POISON( dt ) )
dam = ris_damage( victim, dam, RIS_POISON );
else
/*
* Added checks for the 3 new dam types, and removed DAM_PEA - Grimm
* Removed excess duplication, added hack and lash RIS types - Samson 1-9-00
*/
if( dt == ( TYPE_HIT + DAM_CRUSH ) )
dam = ris_damage( victim, dam, RIS_BLUNT );
else if( dt == ( TYPE_HIT + DAM_STAB ) || dt == ( TYPE_HIT + DAM_PIERCE ) || dt == ( TYPE_HIT + DAM_THRUST ) )
dam = ris_damage( victim, dam, RIS_PIERCE );
else if( dt == ( TYPE_HIT + DAM_SLASH ) )
dam = ris_damage( victim, dam, RIS_SLASH );
else if( dt == ( TYPE_HIT + DAM_HACK ) )
dam = ris_damage( victim, dam, RIS_HACK );
else if( dt == ( TYPE_HIT + DAM_LASH ) )
dam = ris_damage( victim, dam, RIS_LASH );
if( dam == -1 )
{
if( dt >= 0 && dt < top_sn )
{
bool found = FALSE;
SKILLTYPE *skill = skill_table[dt];
if( skill->imm_char && skill->imm_char[0] != '\0' )
{
act( AT_HIT, skill->imm_char, ch, NULL, victim, TO_CHAR );
found = TRUE;
}
if( skill->imm_vict && skill->imm_vict[0] != '\0' )
{
act( AT_HITME, skill->imm_vict, ch, NULL, victim, TO_VICT );
found = TRUE;
}
if( skill->imm_room && skill->imm_room[0] != '\0' )
{
act( AT_ACTION, skill->imm_room, ch, NULL, victim, TO_NOTVICT );
found = TRUE;
}
if( found )
return rNONE;
}
dam = 0;
}
}
/*
* Precautionary step mainly to prevent people in Hell from finding
* a way out. --Shaddai
*/
if( xIS_SET( victim->in_room->room_flags, ROOM_SAFE ) )
dam = 0;
if( dam && npcvict && ch != victim )
{
if( !xIS_SET( victim->act, ACT_SENTINEL ) )
{
if( victim->hunting )
{
if( victim->hunting->who != ch )
{
STRFREE( victim->hunting->name );
victim->hunting->name = QUICKLINK( ch->name );
victim->hunting->who = ch;
}
}
else if( !xIS_SET( victim->act, ACT_PACIFIST ) ) /* Gorog */
start_hunting( victim, ch );
}
if( victim->hating )
{
if( victim->hating->who != ch )
{
STRFREE( victim->hating->name );
victim->hating->name = QUICKLINK( ch->name );
victim->hating->who = ch;
}
}
else if( !xIS_SET( victim->act, ACT_PACIFIST ) ) /* Gorog */
start_hating( victim, ch );
}
/*
* Stop up any residual loopholes.
*/
if( dt == gsn_backstab )
maxdam = ch->level * 80;
else
maxdam = ch->level * 40;
if( dam > maxdam )
{
sprintf( buf, "Damage: %d more than %d points!", dam, maxdam );
bug( buf, dam );
sprintf( buf, "** %s (lvl %d) -> %s **", ch->name, ch->level, victim->name );
bug( buf, 0 );
dam = maxdam;
}
if( victim != ch )
{
/*
* Certain attacks are forbidden.
* Most other attacks are returned.
*/
if( is_safe( ch, victim, TRUE ) )
return rNONE;
check_attacker( ch, victim );
if( victim->position > POS_STUNNED )
{
if( !victim->fighting && victim->in_room == ch->in_room )
set_fighting( victim, ch );
/*
* vwas: victim->position = POS_FIGHTING;
*/
if( IS_NPC( victim ) && victim->fighting )
victim->position = POS_FIGHTING;
else if( victim->fighting )
{
switch ( victim->style )
{
case ( STYLE_EVASIVE ):
victim->position = POS_EVASIVE;
break;
case ( STYLE_DEFENSIVE ):
victim->position = POS_DEFENSIVE;
break;
case ( STYLE_AGGRESSIVE ):
victim->position = POS_AGGRESSIVE;
break;
case ( STYLE_BERSERK ):
victim->position = POS_BERSERK;
break;
default:
victim->position = POS_FIGHTING;
}
}
}
if( victim->position > POS_STUNNED )
{
if( !ch->fighting && victim->in_room == ch->in_room )
set_fighting( ch, victim );
/*
* If victim is charmed, ch might attack victim's master.
*/
if( IS_NPC( ch )
&& npcvict
&& IS_AFFECTED( victim, AFF_CHARM )
&& victim->master && victim->master->in_room == ch->in_room && number_bits( 3 ) == 0 )
{
stop_fighting( ch, FALSE );
retcode = multi_hit( ch, victim->master, TYPE_UNDEFINED );
return retcode;
}
}
/*
* More charm stuff.
*/
if( victim->master == ch )
stop_follower( victim );
/*
* Pkill stuff. If a deadly attacks another deadly or is attacked by
* one, then ungroup any nondealies. Disabled untill I can figure out
* the right way to do it.
*/
/*
* count the # of non-pkill pc in a ( not including == ch )
*/
for( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
if( is_same_group( ch, gch ) && !IS_NPC( gch ) && !IS_PKILL( gch ) && ( ch != gch ) )
anopc++;
/*
* count the # of non-pkill pc in b ( not including == victim )
*/
for( gch = victim->in_room->first_person; gch; gch = gch->next_in_room )
if( is_same_group( victim, gch ) && !IS_NPC( gch ) && !IS_PKILL( gch ) && ( victim != gch ) )
bnopc++;
/*
* only consider disbanding if both groups have 1(+) non-pk pc,
* or when one participant is pc, and the other group has 1(+)
* pk pc's (in the case that participant is only pk pc in group)
*/
if( ( bnopc > 0 && anopc > 0 ) || ( bnopc > 0 && !IS_NPC( ch ) ) || ( anopc > 0 && !IS_NPC( victim ) ) )
{
/*
* Disband from same group first
*/
if( is_same_group( ch, victim ) )
{
/*
* Messages to char and master handled in stop_follower
*/
act( AT_ACTION, "$n disbands from $N's group.",
( ch->leader == victim ) ? victim : ch, NULL,
( ch->leader == victim ) ? victim->master : ch->master, TO_NOTVICT );
if( ch->leader == victim )
stop_follower( victim );
else
stop_follower( ch );
}
/*
* if leader isnt pkill, leave the group and disband ch
*/
if( ch->leader != NULL && !IS_NPC( ch->leader ) && !IS_PKILL( ch->leader ) )
{
act( AT_ACTION, "$n disbands from $N's group.", ch, NULL, ch->master, TO_NOTVICT );
stop_follower( ch );
}
else
{
for( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
if( is_same_group( gch, ch ) && !IS_NPC( gch ) && !IS_PKILL( gch ) && gch != ch )
{
act( AT_ACTION, "$n disbands from $N's group.", ch, NULL, gch->master, TO_NOTVICT );
stop_follower( gch );
}
}
/*
* if leader isnt pkill, leave the group and disband victim
*/
if( victim->leader != NULL && !IS_NPC( victim->leader ) && !IS_PKILL( victim->leader ) )
{
act( AT_ACTION, "$n disbands from $N's group.", victim, NULL, victim->master, TO_NOTVICT );
stop_follower( victim );
}
else
{
for( gch = victim->in_room->first_person; gch; gch = gch->next_in_room )
if( is_same_group( gch, victim ) && !IS_NPC( gch ) && !IS_PKILL( gch ) && gch != victim )
{
act( AT_ACTION, "$n disbands from $N's group.", gch, NULL, gch->master, TO_NOTVICT );
stop_follower( gch );
}
}
}
/*
* Inviso attacks ... not.
*/
if( IS_AFFECTED( ch, AFF_INVISIBLE ) )
{
affect_strip( ch, gsn_invis );
affect_strip( ch, gsn_mass_invis );
xREMOVE_BIT( ch->affected_by, AFF_INVISIBLE );
act( AT_MAGIC, "$n fades into existence.", ch, NULL, NULL, TO_ROOM );
}
/*
* Take away Hide
*/
if( IS_AFFECTED( ch, AFF_HIDE ) )
xREMOVE_BIT( ch->affected_by, AFF_HIDE );
/*
* Damage modifiers.
*/
if( IS_AFFECTED( victim, AFF_SANCTUARY ) )
dam /= 2;
if( IS_AFFECTED( victim, AFF_PROTECT ) && IS_EVIL( ch ) )
dam -= ( int )( dam / 4 );
if( dam < 0 )
dam = 0;
if( quad_damage == TRUE )
{
if( !IS_NPC( ch ) )
dam = dam * 4;
}
/*
* Check for disarm, trip, parry, dodge and tumble.
*/
if( dt >= TYPE_HIT && ch->in_room == victim->in_room )
{
if( IS_NPC( ch ) && xIS_SET( ch->defenses, DFND_DISARM ) && ch->level > 9 && number_percent( ) < ch->level / 3 ) /* Was 2 try this --Shaddai */
disarm( ch, victim );
if( IS_NPC( ch ) && xIS_SET( ch->attacks, ATCK_TRIP ) && ch->level > 5 && number_percent( ) < ch->level / 2 )
trip( ch, victim );
if( check_parry( ch, victim ) )
return rNONE;
if( check_dodge( ch, victim ) )
return rNONE;
if( check_tumble( ch, victim ) )
return rNONE;
}
/*
* Check control panel settings and modify damage
*/
if( IS_NPC( ch ) )
{
if( npcvict )
dampmod = sysdata.dam_mob_vs_mob;
else
dampmod = sysdata.dam_mob_vs_plr;
}
else
{
if( npcvict )
dampmod = sysdata.dam_plr_vs_mob;
else
dampmod = sysdata.dam_plr_vs_plr;
}
if( dampmod > 0 )
dam = ( dam * dampmod ) / 100;
dam_message( ch, victim, dam, dt );
}
/*
* Code to handle equipment getting damaged, and also support -Thoric
* bonuses/penalties for having or not having equipment where hit
*/
if( dam > 50 && dt != TYPE_UNDEFINED )
{
/*
* get a random body eq part
*/
dameq = number_range( WEAR_LIGHT, WEAR_ANKLE_R );
damobj = get_eq_char( victim, dameq );
if( damobj )
{
if( dam > get_obj_resistance( damobj ) && number_bits( 1 ) == 0 )
{
set_cur_obj( damobj );
damage_obj( damobj );
}
dam -= 10; /* add a bonus for having something to block the blow */
}
else
dam += 10; /* add penalty for bare skin! */
}
/*
* Hurt the victim.
* Inform the victim of his new state.
*/
victim->hit -= dam;
/*
* Make sure newbies dont die
*/
if( !IS_NPC( victim ) && NOT_AUTHED( victim ) && victim->hit < 1 )
victim->hit = 1;
if( dam > 0 && dt > TYPE_HIT
&& !IS_AFFECTED( victim, AFF_POISON )
&& is_wielding_poisoned( ch ) && !IS_SET( victim->immune, RIS_POISON ) && !saves_poison_death( ch->level, victim ) )
{
AFFECT_DATA af;
af.type = gsn_poison;
af.duration = 20;
af.location = APPLY_STR;
af.modifier = -2;
af.bitvector = meb( AFF_POISON );
affect_join( victim, &af );
victim->mental_state = URANGE( 20, victim->mental_state + ( IS_PKILL( victim ) ? 1 : 2 ), 100 );
}
/*
* Vampire self preservation -Thoric
*/
if( IS_VAMPIRE( victim ) )
{
if( dam >= ( victim->max_hit / 10 ) ) /* get hit hard, lose blood */
gain_condition( victim, COND_BLOODTHIRST, -1 - ( victim->level / 20 ) );
if( victim->hit <= ( victim->max_hit / 8 ) && victim->pcdata->condition[COND_BLOODTHIRST] > 5 )
{
gain_condition( victim, COND_BLOODTHIRST, -URANGE( 3, victim->level / 10, 8 ) );
victim->hit += URANGE( 4, ( victim->max_hit / 30 ), 15 );
set_char_color( AT_BLOOD, victim );
send_to_char( "You howl with rage as the beast within stirs!\n\r", victim );
}
}
if( !npcvict && get_trust( victim ) >= LEVEL_IMMORTAL && get_trust( ch ) >= LEVEL_IMMORTAL && victim->hit < 1 )
victim->hit = 1;
update_pos( victim );
switch ( victim->position )
{
case POS_MORTAL:
act( AT_DYING, "$n is mortally wounded, and will die soon, if not aided.", victim, NULL, NULL, TO_ROOM );
act( AT_DANGER, "You are mortally wounded, and will die soon, if not aided.", victim, NULL, NULL, TO_CHAR );
break;
case POS_INCAP:
act( AT_DYING, "$n is incapacitated and will slowly die, if not aided.", victim, NULL, NULL, TO_ROOM );
act( AT_DANGER, "You are incapacitated and will slowly die, if not aided.", victim, NULL, NULL, TO_CHAR );
break;
case POS_STUNNED:
if( !IS_AFFECTED( victim, AFF_PARALYSIS ) )
{
act( AT_ACTION, "$n is stunned, but will probably recover.", victim, NULL, NULL, TO_ROOM );
act( AT_HURT, "You are stunned, but will probably recover.", victim, NULL, NULL, TO_CHAR );
}
break;
case POS_DEAD:
if( dt >= 0 && dt < top_sn )
{
SKILLTYPE *skill = skill_table[dt];
if( skill->die_char && skill->die_char[0] != '\0' )
act( AT_DEAD, skill->die_char, ch, NULL, victim, TO_CHAR );
if( skill->die_vict && skill->die_vict[0] != '\0' )
act( AT_DEAD, skill->die_vict, ch, NULL, victim, TO_VICT );
if( skill->die_room && skill->die_room[0] != '\0' )
act( AT_DEAD, skill->die_room, ch, NULL, victim, TO_NOTVICT );
}
act( AT_DEAD, "$n is DEAD!!", victim, 0, 0, TO_ROOM );
act( AT_DEAD, "You have been KILLED!!\n\r", victim, 0, 0, TO_CHAR );
break;
default:
/*
* Victim mentalstate affected, not attacker -- oops ;)
* Thanks to gfinello@mail.karmanet.it for finding this bug
*/
if( dam > victim->max_hit / 4 )
{
act( AT_HURT, "That really did HURT!", victim, 0, 0, TO_CHAR );
if( number_bits( 3 ) == 0 )
worsen_mental_state( victim, 1 );
}
if( victim->hit < victim->max_hit / 4 )
{
act( AT_DANGER, "You wish that your wounds would stop BLEEDING so much!", victim, 0, 0, TO_CHAR );
if( number_bits( 2 ) == 0 )
worsen_mental_state( victim, 1 );
}
break;
}
/*
* Sleep spells and extremely wounded folks.
*/
if( !IS_AWAKE( victim ) /* lets make NPC's not slaughter PC's */
&& !IS_AFFECTED( victim, AFF_PARALYSIS ) )
{
if( victim->fighting && victim->fighting->who->hunting && victim->fighting->who->hunting->who == victim )
stop_hunting( victim->fighting->who );
if( victim->fighting && victim->fighting->who->hating && victim->fighting->who->hating->who == victim )
stop_hating( victim->fighting->who );
if( !npcvict && IS_NPC( ch ) )
stop_fighting( victim, TRUE );
else
stop_fighting( victim, FALSE );
}
/*
* Payoff for killing things.
*/
if( victim->position == POS_DEAD )
{
group_gain( ch, victim );
if( !npcvict )
{
sprintf( log_buf, "%s (%d) killed by %s at %d",
victim->name, victim->level, ( IS_NPC( ch ) ? ch->short_descr : ch->name ), victim->in_room->vnum );
log_string( log_buf );
to_channel( log_buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL );
if( !IS_NPC( ch ) && !IS_IMMORTAL( ch ) && ch->pcdata->clan
&& ch->pcdata->clan->clan_type != CLAN_ORDER && ch->pcdata->clan->clan_type != CLAN_GUILD && victim != ch )
{
sprintf( filename, "%s%s.record", CLAN_DIR, ch->pcdata->clan->name );
sprintf( log_buf, "&P(%2d) %-12s &wvs &P(%2d) %s &P%s ... &w%s",
ch->level,
ch->name,
victim->level,
!CAN_PKILL( victim ) ? "&W<Peaceful>" :
victim->pcdata->clan ? victim->pcdata->clan->badge :
"&P(&WUnclanned&P)", victim->name, ch->in_room->area->name );
if( victim->pcdata->clan && victim->pcdata->clan->name == ch->pcdata->clan->name )
;
else
append_to_file( filename, log_buf );
}
/*
* Dying penalty:
* Loss of quater your exp! :)
*/
if( victim->exp > 0 )
gain_exp( victim, 0 - ( victim->exp / 4 ) );
/*
* New penalty... go back to the beginning of current level.
victim->exp = 0;
*/
}
else if( !IS_NPC( ch ) ) /* keep track of mob vnum killed */
add_kill( ch, victim );
check_killer( ch, victim );
if( ch->in_room == victim->in_room )
loot = legal_loot( ch, victim );
else
loot = FALSE;
set_cur_char( victim );
raw_kill( ch, victim );
victim = NULL;
if( !IS_NPC( ch ) && loot )
{
/*
* Autogold by Scryn 8/12
*/
if( xIS_SET( ch->act, PLR_AUTOGOLD ) )
{
init_gold = ch->gold;
do_get( ch, "coins corpse" );
new_gold = ch->gold;
gold_diff = ( new_gold - init_gold );
if( gold_diff > 0 )
{
sprintf( buf1, "%d", gold_diff );
do_split( ch, buf1 );
}
}
if( xIS_SET( ch->act, PLR_AUTOLOOT ) && victim != ch ) /* prevent nasty obj problems -- Blodkai */
do_get( ch, "all corpse" );
else
do_look( ch, "in corpse" );
if( xIS_SET( ch->act, PLR_AUTOSAC ) )
do_sacrifice( ch, "corpse" );
}
if( IS_SET( sysdata.save_flags, SV_KILL ) )
save_char_obj( ch );
return rVICT_DIED;
}
if( victim == ch )
return rNONE;
/*
* Take care of link dead people.
*/
if( !npcvict && !victim->desc && !IS_SET( victim->pcdata->flags, PCFLAG_NORECALL ) )
{
if( number_range( 0, victim->wait ) == 0 )
{
do_recall( victim, "" );
return rNONE;
}
}
/*
* Wimp out?
*/
if( npcvict && dam > 0 )
{
if( ( xIS_SET( victim->act, ACT_WIMPY ) && number_bits( 1 ) == 0
&& victim->hit < victim->max_hit / 2 )
|| ( IS_AFFECTED( victim, AFF_CHARM ) && victim->master && victim->master->in_room != victim->in_room ) )
{
start_fearing( victim, ch );
stop_hunting( victim );
do_flee( victim, "" );
}
}
if( !npcvict && victim->hit > 0 && victim->hit <= victim->wimpy && victim->wait == 0 )
do_flee( victim, "" );
else if( !npcvict && xIS_SET( victim->act, PLR_FLEE ) )
do_flee( victim, "" );
tail_chain( );
return rNONE;
}
/*
* Changed is_safe to have the show_messg boolian. This is so if you don't
* want to show why you can't kill someone you can't turn it off. This is
* useful for things like area attacks. --Shaddai
*/
bool is_safe( CHAR_DATA * ch, CHAR_DATA * victim, bool show_messg )
{
if( char_died( victim ) || char_died( ch ) )
return TRUE;
/*
* Thx Josh!
*/
if( who_fighting( ch ) == ch )
return FALSE;
if( !victim ) /*Gonna find this is_safe crash bug -Blod */
{
bug( "Is_safe: %s opponent does not exist!", ch->name );
return TRUE;
}
if( !victim->in_room )
{
bug( "Is_safe: %s has no physical location!", victim->name );
return TRUE;
}
if( xIS_SET( victim->in_room->room_flags, ROOM_SAFE ) )
{
if( show_messg )
{
set_char_color( AT_MAGIC, ch );
send_to_char( "A magical force prevents you from attacking.\n\r", ch );
}
return TRUE;
}
if( ( IS_PACIFIST( ch ) ) && !IN_ARENA( ch ) ) /* Fireblade */
{
if( show_messg )
{
set_char_color( AT_MAGIC, ch );
ch_printf( ch, "You are a pacifist and will not fight.\n\r" );
}
return TRUE;
}
if( ( IS_PACIFIST( ch ) ) && !IN_ARENA( ch ) ) /* Gorog */
{
char buf[MAX_STRING_LENGTH];
if( show_messg )
{
sprintf( buf, "%s is a pacifist and will not fight.\n\r", capitalize( victim->short_descr ) );
set_char_color( AT_MAGIC, ch );
send_to_char( buf, ch );
}
return TRUE;
}
if( !IS_NPC( ch ) && ch->level >= LEVEL_IMMORTAL )
return FALSE;
if( !IS_NPC( ch ) && !IS_NPC( victim ) && ch != victim && IS_SET( victim->in_room->area->flags, AFLAG_NOPKILL ) )
{
if( show_messg )
{
set_char_color( AT_IMMORT, ch );
send_to_char( "The gods have forbidden player killing in this area.\n\r", ch );
}
return TRUE;
}
if( IS_NPC( ch ) || IS_NPC( victim ) )
return FALSE;
if( ( get_age( ch ) < 17 || ch->level < 5 ) && !IN_ARENA( ch ) )
{
if( show_messg )
{
set_char_color( AT_WHITE, ch );
send_to_char( "You are not yet ready, needing age or experience, if not both. \n\r", ch );
}
return TRUE;
}
if( ( get_age( victim ) < 17 || victim->level < 5 ) && !IN_ARENA( victim ) )
{
if( show_messg )
{
set_char_color( AT_WHITE, ch );
send_to_char( "They are yet too young to die.\n\r", ch );
}
return TRUE;
}
if( ( ch->level - victim->level > 15 || victim->level - ch->level > 15 ) && !IN_ARENA( ch ) )
{
if( show_messg )
{
set_char_color( AT_IMMORT, ch );
send_to_char( "The gods do not allow murder when there is such a difference in level.\n\r", ch );
}
return TRUE;
}
if( ( get_timer( victim, TIMER_PKILLED ) > 0 ) && !IN_ARENA( ch ) )
{
if( show_messg )
{
set_char_color( AT_GREEN, ch );
send_to_char( "That character has died within the last 5 minutes.\n\r", ch );
}
return TRUE;
}
if( ( get_timer( ch, TIMER_PKILLED ) > 0 ) && !IN_ARENA( ch ) )
{
if( show_messg )
{
set_char_color( AT_GREEN, ch );
send_to_char( "You have been killed within the last 5 minutes.\n\r", ch );
}
return TRUE;
}
return FALSE;
}
/*
* just verify that a corpse looting is legal
*/
bool legal_loot( CHAR_DATA * ch, CHAR_DATA * victim )
{
/*
* anyone can loot mobs
*/
if( IS_NPC( victim ) )
return TRUE;
/*
* non-charmed mobs can loot anything
*/
if( IS_NPC( ch ) && !ch->master )
return TRUE;
/*
* members of different clans can loot too! -Thoric
*/
if( !IS_NPC( ch ) && !IS_NPC( victim )
&& IS_SET( ch->pcdata->flags, PCFLAG_DEADLY ) && IS_SET( victim->pcdata->flags, PCFLAG_DEADLY ) )
return TRUE;
return FALSE;
}
/*
* See if an attack justifies a KILLER flag.
*/
void check_killer( CHAR_DATA * ch, CHAR_DATA * victim )
{
/*
* NPC's are fair game.
*/
if( IS_NPC( victim ) )
{
if( !IS_NPC( ch ) )
{
int level_ratio;
/*
* Fix for crashes when killing mobs of level 0
* * by Joe Fabiano -rinthos@yahoo.com
* * on 03-16-03.
*/
if( victim->level < 1 )
level_ratio = URANGE( 1, ch->level, MAX_LEVEL );
else
level_ratio = URANGE( 1, ch->level / victim->level, MAX_LEVEL );
if( ch->pcdata->clan )
ch->pcdata->clan->mkills++;
ch->pcdata->mkills++;
ch->in_room->area->mkills++;
if( ch->pcdata->deity )
{
if( victim->race == ch->pcdata->deity->npcrace )
adjust_favor( ch, 3, level_ratio );
else if( victim->race == ch->pcdata->deity->npcfoe )
adjust_favor( ch, 17, level_ratio );
else
adjust_favor( ch, 2, level_ratio );
}
}
return;
}
/*
* If you kill yourself nothing happens.
*/
if( ch == victim || ch->level >= LEVEL_IMMORTAL )
return;
/*
* Any character in the arena is ok to kill.
* Added pdeath and pkills here
*/
if( in_arena( ch ) )
{
if( !IS_NPC( ch ) && !IS_NPC( victim ) )
{
ch->pcdata->pkills++;
victim->pcdata->pdeaths++;
}
return;
}
/*
* So are killers and thieves.
*/
if( xIS_SET( victim->act, PLR_KILLER ) || xIS_SET( victim->act, PLR_THIEF ) )
{
if( !IS_NPC( ch ) )
{
if( ch->pcdata->clan )
{
if( victim->level < 10 )
ch->pcdata->clan->pkills[0]++;
else if( victim->level < 15 )
ch->pcdata->clan->pkills[1]++;
else if( victim->level < 20 )
ch->pcdata->clan->pkills[2]++;
else if( victim->level < 30 )
ch->pcdata->clan->pkills[3]++;
else if( victim->level < 40 )
ch->pcdata->clan->pkills[4]++;
else if( victim->level < 50 )
ch->pcdata->clan->pkills[5]++;
else
ch->pcdata->clan->pkills[6]++;
}
ch->pcdata->pkills++;
ch->in_room->area->pkills++;
}
return;
}
/*
* clan checks -Thoric
*/
if( !IS_NPC( ch ) && !IS_NPC( victim )
&& IS_SET( ch->pcdata->flags, PCFLAG_DEADLY ) && IS_SET( victim->pcdata->flags, PCFLAG_DEADLY ) )
{
/*
* not of same clan? Go ahead and kill!!!
*/
if( !ch->pcdata->clan
|| !victim->pcdata->clan
|| ( ch->pcdata->clan->clan_type != CLAN_NOKILL
&& victim->pcdata->clan->clan_type != CLAN_NOKILL && ch->pcdata->clan != victim->pcdata->clan ) )
{
if( ch->pcdata->clan )
{
if( victim->level < 10 )
ch->pcdata->clan->pkills[0]++;
else if( victim->level < 15 )
ch->pcdata->clan->pkills[1]++;
else if( victim->level < 20 )
ch->pcdata->clan->pkills[2]++;
else if( victim->level < 30 )
ch->pcdata->clan->pkills[3]++;
else if( victim->level < 40 )
ch->pcdata->clan->pkills[4]++;
else if( victim->level < 50 )
ch->pcdata->clan->pkills[5]++;
else
ch->pcdata->clan->pkills[6]++;
}
ch->pcdata->pkills++;
ch->hit = ch->max_hit;
ch->mana = ch->max_mana;
ch->move = ch->max_move;
if( ch->pcdata )
ch->pcdata->condition[COND_BLOODTHIRST] = ( 10 + ch->level );
update_pos( victim );
if( victim != ch )
{
act( AT_MAGIC, "Bolts of blue energy rise from the corpse, seeping into $n.", ch, victim->name, NULL, TO_ROOM );
act( AT_MAGIC, "Bolts of blue energy rise from the corpse, seeping into you.", ch, victim->name, NULL, TO_CHAR );
}
if( victim->pcdata->clan )
{
if( ch->level < 10 )
victim->pcdata->clan->pdeaths[0]++;
else if( ch->level < 15 )
victim->pcdata->clan->pdeaths[1]++;
else if( ch->level < 20 )
victim->pcdata->clan->pdeaths[2]++;
else if( ch->level < 30 )
victim->pcdata->clan->pdeaths[3]++;
else if( ch->level < 40 )
victim->pcdata->clan->pdeaths[4]++;
else if( ch->level < 50 )
victim->pcdata->clan->pdeaths[5]++;
else
victim->pcdata->clan->pdeaths[6]++;
}
victim->pcdata->pdeaths++;
adjust_favor( victim, 11, 1 );
adjust_favor( ch, 2, 1 );
add_timer( victim, TIMER_PKILLED, 115, NULL, 0 );
WAIT_STATE( victim, 3 * PULSE_VIOLENCE );
/*
* xSET_BIT(victim->act, PLR_PK);
*/
return;
}
}
/*
* Charm-o-rama.
*/
if( IS_AFFECTED( ch, AFF_CHARM ) )
{
if( !ch->master )
{
char buf[MAX_STRING_LENGTH];
sprintf( buf, "Check_killer: %s bad AFF_CHARM", IS_NPC( ch ) ? ch->short_descr : ch->name );
bug( buf, 0 );
affect_strip( ch, gsn_charm_person );
xREMOVE_BIT( ch->affected_by, AFF_CHARM );
return;
}
/*
* stop_follower( ch );
*/
if( ch->master )
check_killer( ch->master, victim );
return;
}
/*
* NPC's are cool of course (as long as not charmed).
* Hitting yourself is cool too (bleeding).
* So is being immortal (Alander's idea).
* And current killers stay as they are.
*/
if( IS_NPC( ch ) )
{
if( !IS_NPC( victim ) )
{
int level_ratio;
if( victim->pcdata->clan )
victim->pcdata->clan->mdeaths++;
victim->pcdata->mdeaths++;
victim->in_room->area->mdeaths++;
level_ratio = URANGE( 1, ch->level / victim->level, LEVEL_AVATAR );
if( victim->pcdata->deity )
{
if( ch->race == victim->pcdata->deity->npcrace )
adjust_favor( victim, 12, level_ratio );
else if( ch->race == victim->pcdata->deity->npcfoe )
adjust_favor( victim, 15, level_ratio );
else
adjust_favor( victim, 11, level_ratio );
}
}
return;
}
if( !IS_NPC( ch ) )
{
if( ch->pcdata->clan )
ch->pcdata->clan->illegal_pk++;
ch->pcdata->illegal_pk++;
ch->in_room->area->illegal_pk++;
}
if( !IS_NPC( victim ) )
{
if( victim->pcdata->clan )
{
if( ch->level < 10 )
victim->pcdata->clan->pdeaths[0]++;
else if( ch->level < 15 )
victim->pcdata->clan->pdeaths[1]++;
else if( ch->level < 20 )
victim->pcdata->clan->pdeaths[2]++;
else if( ch->level < 30 )
victim->pcdata->clan->pdeaths[3]++;
else if( ch->level < 40 )
victim->pcdata->clan->pdeaths[4]++;
else if( ch->level < 50 )
victim->pcdata->clan->pdeaths[5]++;
else
victim->pcdata->clan->pdeaths[6]++;
}
victim->pcdata->pdeaths++;
victim->in_room->area->pdeaths++;
}
if( xIS_SET( ch->act, PLR_KILLER ) )
return;
set_char_color( AT_WHITE, ch );
send_to_char( "A strange feeling grows deep inside you, and a tingle goes up your spine...\n\r", ch );
set_char_color( AT_IMMORT, ch );
send_to_char( "A deep voice booms inside your head, 'Thou shall now be known as a deadly murderer!!!'\n\r", ch );
set_char_color( AT_WHITE, ch );
send_to_char( "You feel as if your soul has been revealed for all to see.\n\r", ch );
xSET_BIT( ch->act, PLR_KILLER );
if( xIS_SET( ch->act, PLR_ATTACKER ) )
xREMOVE_BIT( ch->act, PLR_ATTACKER );
save_char_obj( ch );
return;
}
/*
* See if an attack justifies a ATTACKER flag.
*/
void check_attacker( CHAR_DATA * ch, CHAR_DATA * victim )
{
/*
* Made some changes to this function Apr 6/96 to reduce the prolifiration
* of attacker flags in the realms. -Narn
*/
/*
* NPC's are fair game.
* So are killers and thieves.
*/
if( IS_NPC( victim ) || xIS_SET( victim->act, PLR_KILLER ) || xIS_SET( victim->act, PLR_THIEF ) )
return;
/*
* deadly char check
*/
if( !IS_NPC( ch ) && !IS_NPC( victim ) && CAN_PKILL( ch ) && CAN_PKILL( victim ) )
return;
/*
* Pkiller versus pkiller will no longer ever make an attacker flag
* { if ( !(ch->pcdata->clan && victim->pcdata->clan
* && ch->pcdata->clan == victim->pcdata->clan ) ) return; }
*/
/*
* Charm-o-rama.
*/
if( IS_AFFECTED( ch, AFF_CHARM ) )
{
if( !ch->master )
{
char buf[MAX_STRING_LENGTH];
sprintf( buf, "Check_attacker: %s bad AFF_CHARM", IS_NPC( ch ) ? ch->short_descr : ch->name );
bug( buf, 0 );
affect_strip( ch, gsn_charm_person );
xREMOVE_BIT( ch->affected_by, AFF_CHARM );
return;
}
/*
* Won't have charmed mobs fighting give the master an attacker
* flag. The killer flag stays in, and I'll put something in
* do_murder. -Narn
*/
/*
* xSET_BIT(ch->master->act, PLR_ATTACKER);
*/
/*
* stop_follower( ch );
*/
return;
}
/*
* NPC's are cool of course (as long as not charmed).
* Hitting yourself is cool too (bleeding).
* So is being immortal (Alander's idea).
* And current killers stay as they are.
*/
if( IS_NPC( ch )
|| ch == victim
|| ch->level >= LEVEL_IMMORTAL
|| xIS_SET( ch->act, PLR_ATTACKER ) || xIS_SET( ch->act, PLR_KILLER ) || IN_ARENA( ch ) )
return;
xSET_BIT( ch->act, PLR_ATTACKER );
save_char_obj( ch );
return;
}
/*
* Set position of a victim.
*/
void update_pos( CHAR_DATA * victim )
{
if( !victim )
{
bug( "update_pos: null victim", 0 );
return;
}
if( victim->hit > 0 )
{
if( victim->position <= POS_STUNNED )
victim->position = POS_STANDING;
if( IS_AFFECTED( victim, AFF_PARALYSIS ) )
victim->position = POS_STUNNED;
return;
}
if( IS_NPC( victim ) || victim->hit <= -11 )
{
if( victim->mount )
{
act( AT_ACTION, "$n falls from $N.", victim, NULL, victim->mount, TO_ROOM );
xREMOVE_BIT( victim->mount->act, ACT_MOUNTED );
victim->mount = NULL;
}
victim->position = POS_DEAD;
return;
}
if( victim->hit <= 0 )
victim->position = POS_DEAD;
if( victim->mount )
{
act( AT_ACTION, "$n falls unconscious from $N.", victim, NULL, victim->mount, TO_ROOM );
xREMOVE_BIT( victim->mount->act, ACT_MOUNTED );
victim->mount = NULL;
}
return;
}
/*
* Start fights.
*/
void set_fighting( CHAR_DATA * ch, CHAR_DATA * victim )
{
FIGHT_DATA *fight;
if( ch->fighting )
{
char buf[MAX_STRING_LENGTH];
sprintf( buf, "Set_fighting: %s -> %s (already fighting %s)", ch->name, victim->name, ch->fighting->who->name );
bug( buf, 0 );
return;
}
if( IS_AFFECTED( ch, AFF_SLEEP ) )
affect_strip( ch, gsn_sleep );
/*
* Limit attackers -Thoric
*/
if( victim->num_fighting > max_fight( victim ) )
{
send_to_char( "There are too many people fighting for you to join in.\n\r", ch );
return;
}
CREATE( fight, FIGHT_DATA, 1 );
fight->who = victim;
fight->xp = ( int )xp_compute( ch, victim ) * 0.85;
fight->align = align_compute( ch, victim );
if( !IS_NPC( ch ) && IS_NPC( victim ) )
fight->timeskilled = times_killed( ch, victim );
ch->num_fighting = 1;
ch->fighting = fight;
/*
* ch->position = POS_FIGHTING;
*/
if( IS_NPC( ch ) )
ch->position = POS_FIGHTING;
else
switch ( ch->style )
{
case ( STYLE_EVASIVE ):
ch->position = POS_EVASIVE;
break;
case ( STYLE_DEFENSIVE ):
ch->position = POS_DEFENSIVE;
break;
case ( STYLE_AGGRESSIVE ):
ch->position = POS_AGGRESSIVE;
break;
case ( STYLE_BERSERK ):
ch->position = POS_BERSERK;
break;
default:
ch->position = POS_FIGHTING;
}
victim->num_fighting++;
if( victim->switched && IS_AFFECTED( victim->switched, AFF_POSSESS ) )
{
send_to_char( "You are disturbed!\n\r", victim->switched );
do_return( victim->switched, "" );
}
return;
}
CHAR_DATA *who_fighting( CHAR_DATA * ch )
{
if( !ch )
{
bug( "who_fighting: null ch", 0 );
return NULL;
}
if( !ch->fighting )
return NULL;
return ch->fighting->who;
}
void free_fight( CHAR_DATA * ch )
{
if( !ch )
{
bug( "Free_fight: null ch!", 0 );
return;
}
if( ch->fighting )
{
if( !char_died( ch->fighting->who ) )
--ch->fighting->who->num_fighting;
DISPOSE( ch->fighting );
}
ch->fighting = NULL;
if( ch->mount )
ch->position = POS_MOUNTED;
else
ch->position = POS_STANDING;
/*
* Berserk wears off after combat. -- Altrag
*/
if( IS_AFFECTED( ch, AFF_BERSERK ) )
{
affect_strip( ch, gsn_berserk );
set_char_color( AT_WEAROFF, ch );
send_to_char( skill_table[gsn_berserk]->msg_off, ch );
send_to_char( "\n\r", ch );
}
return;
}
/*
* Stop fights.
*/
void stop_fighting( CHAR_DATA * ch, bool fBoth )
{
CHAR_DATA *fch;
free_fight( ch );
update_pos( ch );
send_mip_attacker( ch );
if( !fBoth ) /* major short cut here by Thoric */
return;
for( fch = first_char; fch; fch = fch->next )
{
if( who_fighting( fch ) == ch )
{
free_fight( fch );
update_pos( fch );
send_mip_attacker( ch );
}
}
return;
}
/* Vnums for the various bodyparts */
int part_vnums[] = { 12, /* Head */
14, /* arms */
15, /* legs */
13, /* heart */
44, /* brains */
16, /* guts */
45, /* hands */
46, /* feet */
47, /* fingers */
48, /* ear */
49, /* eye */
50, /* long_tongue */
51, /* eyestalks */
52, /* tentacles */
53, /* fins */
54, /* wings */
55, /* tail */
56, /* scales */
59, /* claws */
87, /* fangs */
58, /* horns */
57, /* tusks */
55, /* tailattack */
85, /* sharpscales */
84, /* beak */
86, /* haunches */
83, /* hooves */
82, /* paws */
81, /* forelegs */
80, /* feathers */
0, /* r1 */
0 /* r2 */
};
/* Messages for flinging off the various bodyparts */
char *part_messages[] = {
"$n's severed head plops from its neck.",
"$n's arm is sliced from $s dead body.",
"$n's leg is sliced from $s dead body.",
"$n's heart is torn from $s chest.",
"$n's brains spill grotesquely from $s head.",
"$n's guts spill grotesquely from $s torso.",
"$n's hand is sliced from $s dead body.",
"$n's foot is sliced from $s dead body.",
"A finger is sliced from $n's dead body.",
"$n's ear is sliced from $s dead body.",
"$n's eye is gouged from its socket.",
"$n's tongue is torn from $s mouth.",
"An eyestalk is sliced from $n's dead body.",
"A tentacle is severed from $n's dead body.",
"A fin is sliced from $n's dead body.",
"A wing is severed from $n's dead body.",
"$n's tail is sliced from $s dead body.",
"A scale falls from the body of $n.",
"A claw is torn from $n's dead body.",
"$n's fangs are torn from $s mouth.",
"A horn is wrenched from the body of $n.",
"$n's tusk is torn from $s dead body.",
"$n's tail is sliced from $s dead body.",
"A ridged scale falls from the body of $n.",
"$n's beak is sliced from $s dead body.",
"$n's haunches are sliced from $s dead body.",
"A hoof is sliced from $n's dead body.",
"A paw is sliced from $n's dead body.",
"$n's foreleg is sliced from $s dead body.",
"Some feathers fall from $n's dead body.",
"r1 message.",
"r2 message."
};
/*
* Improved Death_cry contributed by Diavolo.
* Additional improvement by Thoric (and removal of turds... sheesh!)
* Support for additional bodyparts by Fireblade
*/
void death_cry( CHAR_DATA * ch )
{
ROOM_INDEX_DATA *was_in_room;
char *msg;
EXIT_DATA *pexit;
int vnum, shift, cindex, i;
if( !ch )
{
bug( "DEATH_CRY: null ch!", 0 );
return;
}
vnum = 0;
msg = NULL;
switch ( number_range( 0, 5 ) )
{
default:
msg = "You hear $n's death cry.";
break;
case 0:
msg = "$n screams furiously as $e falls to the ground in a heap!";
break;
case 1:
msg = "$n hits the ground ... DEAD.";
break;
case 2:
msg = "$n catches $s guts in $s hands as they pour through $s fatal" " wound!";
break;
case 3:
msg = "$n splatters blood on your armor.";
break;
case 4:
msg = "$n gasps $s last breath and blood spurts out of $s " "mouth and ears.";
break;
case 5:
shift = number_range( 0, 31 );
cindex = 1 << shift;
for( i = 0; i < 32 && ch->xflags; i++ )
{
if( HAS_BODYPART( ch, cindex ) )
{
msg = part_messages[shift];
vnum = part_vnums[shift];
break;
}
else
{
shift = number_range( 0, 31 );
cindex = 1 << shift;
}
}
if( !msg )
msg = "You hear $n's death cry.";
break;
}
act( AT_CARNAGE, msg, ch, NULL, NULL, TO_ROOM );
if( vnum )
{
char buf[MAX_STRING_LENGTH];
OBJ_DATA *obj;
char *name;
if( !get_obj_index( vnum ) )
{
bug( "death_cry: invalid vnum", 0 );
return;
}
name = IS_NPC( ch ) ? ch->short_descr : ch->name;
obj = create_object( get_obj_index( vnum ), 0 );
obj->timer = number_range( 4, 7 );
if( IS_AFFECTED( ch, AFF_POISON ) )
obj->value[3] = 10;
sprintf( buf, obj->short_descr, name );
STRFREE( obj->short_descr );
obj->short_descr = STRALLOC( buf );
sprintf( buf, obj->description, name );
STRFREE( obj->description );
obj->description = STRALLOC( buf );
obj = obj_to_room( obj, ch->in_room, ch );
}
if( IS_NPC( ch ) )
msg = "You hear something's death cry.";
else
msg = "You hear someone's death cry.";
was_in_room = ch->in_room;
for( pexit = was_in_room->first_exit; pexit; pexit = pexit->next )
{
if( pexit->to_room && pexit->to_room != was_in_room )
{
ch->in_room = pexit->to_room;
act( AT_CARNAGE, msg, ch, NULL, NULL, TO_ROOM );
}
}
ch->in_room = was_in_room;
return;
}
void raw_kill( CHAR_DATA * ch, CHAR_DATA * victim )
{
int wear_loc;
OBJ_DATA *obj;
if( !victim )
{
bug( "raw_kill: null victim!", 0 );
return;
}
/*
* backup in case hp goes below 1
*/
if( NOT_AUTHED( victim ) )
{
bug( "raw_kill: killing unauthed", 0 );
return;
}
stop_fighting( victim, TRUE );
/*
* Take care of morphed characters
*/
if( victim->morph )
{
do_unmorph_char( victim );
raw_kill( ch, victim );
return;
}
mprog_death_trigger( ch, victim );
if( char_died( victim ) )
return;
/*
* death_cry( victim );
*/
rprog_death_trigger( ch, victim );
if( char_died( victim ) )
return;
make_corpse( victim, ch );
if( victim->in_room->sector_type == SECT_OCEANFLOOR
|| victim->in_room->sector_type == SECT_UNDERWATER
|| victim->in_room->sector_type == SECT_WATER_SWIM || victim->in_room->sector_type == SECT_WATER_NOSWIM )
act( AT_BLOOD, "$n's blood slowly clouds the surrounding water.", victim, NULL, NULL, TO_ROOM );
else if( victim->in_room->sector_type == SECT_AIR )
act( AT_BLOOD, "$n's blood sprays wildly through the air.", victim, NULL, NULL, TO_ROOM );
else
make_blood( victim );
if( IS_NPC( victim ) )
{
victim->pIndexData->killed++;
extract_char( victim, TRUE );
victim = NULL;
return;
}
set_char_color( AT_DIEMSG, victim );
if( victim->pcdata->mdeaths + victim->pcdata->pdeaths < 3 )
do_help( victim, "new_death" );
else
do_help( victim, "_DIEMSG_" );
extract_char( victim, FALSE );
if( !victim )
{
bug( "oops! raw_kill: extract_char destroyed pc char", 0 );
return;
}
for( wear_loc = WEAR_LIGHT; wear_loc <= MAX_WEAR; wear_loc++ )
{
if( ( obj = get_eq_char( victim, wear_loc ) ) == NULL )
continue;
unequip_char( victim, obj );
}
while( victim->first_affect )
affect_remove( victim, victim->first_affect );
victim->affected_by = race_table[victim->race]->affected;
victim->resistant = 0;
victim->susceptible = 0;
victim->immune = 0;
victim->carry_weight = 0;
victim->armor = 100;
victim->armor += race_table[victim->race]->ac_plus;
victim->attacks = race_table[victim->race]->attacks;
victim->defenses = race_table[victim->race]->defenses;
victim->mod_str = 0;
victim->mod_dex = 0;
victim->mod_wis = 0;
victim->mod_int = 0;
victim->mod_con = 0;
victim->mod_cha = 0;
victim->mod_lck = 0;
victim->damroll = 0;
victim->hitroll = 0;
victim->mental_state = -10;
victim->alignment = URANGE( -1000, victim->alignment, 1000 );
/*
* victim->alignment = race_table[victim->race]->alignment;
* -- switched lines just for now to prevent mortals from building up
* days of bellyaching about their angelic or satanic humans becoming
* neutral when they die given the difficulting of changing align
*/
victim->saving_poison_death = race_table[victim->race]->saving_poison_death;
victim->saving_wand = race_table[victim->race]->saving_wand;
victim->saving_para_petri = race_table[victim->race]->saving_para_petri;
victim->saving_breath = race_table[victim->race]->saving_breath;
victim->saving_spell_staff = race_table[victim->race]->saving_spell_staff;
victim->position = POS_RESTING;
victim->hit = UMAX( 1, victim->hit );
/*
* Shut down some of those naked spammer killers - Blodkai
*/
if( victim->level < LEVEL_AVATAR )
victim->mana = UMAX( 1, victim->mana );
else
victim->mana = 1;
victim->move = UMAX( 1, victim->move );
/*
* time to add back tattos information
*/
if( IS_SET( victim->tattoo, TATTOO_WOLF ) )
{
xSET_BIT( victim->affected_by, AFF_SNEAK );
victim->armor -= 10;
}
if( IS_SET( victim->tattoo, TATTOO_BULL ) )
{
}
if( IS_SET( victim->tattoo, TATTOO_PANTHER ) )
{
xSET_BIT( victim->affected_by, AFF_HIDE );
}
if( IS_SET( victim->tattoo, TATTOO_BEAR ) )
{
SET_BIT( victim->immune, RIS_SLEEP );
SET_BIT( victim->resistant, RIS_NONMAGIC );
victim->damroll += 20;
}
if( IS_SET( victim->tattoo, TATTOO_RABBIT ) )
{
victim->armor -= 10;
}
if( IS_SET( victim->tattoo, TATTOO_DRAGON ) )
{
victim->hitroll += 25;
victim->damroll += 25;
victim->armor -= 50;
xSET_BIT( victim->affected_by, AFF_FLYING );
SET_BIT( victim->resistant, RIS_MAGIC );
}
if( IS_SET( victim->tattoo, TATTOO_MOON ) )
{
xSET_BIT( victim->affected_by, AFF_TRUESIGHT );
SET_BIT( victim->resistant, RIS_DRAIN );
victim->perm_int += 2;
}
/*
* Pardon crimes... -Thoric
*/
if( xIS_SET( victim->act, PLR_KILLER ) )
{
xREMOVE_BIT( victim->act, PLR_KILLER );
send_to_char( "The gods have pardoned you for your murderous acts.\n\r", victim );
}
if( xIS_SET( victim->act, PLR_THIEF ) )
{
xREMOVE_BIT( victim->act, PLR_THIEF );
send_to_char( "The gods have pardoned you for your thievery.\n\r", victim );
}
victim->pcdata->condition[COND_FULL] = 12;
victim->pcdata->condition[COND_THIRST] = 12;
if( IS_VAMPIRE( victim ) )
victim->pcdata->condition[COND_BLOODTHIRST] = ( victim->level / 2 );
if( IS_SET( sysdata.save_flags, SV_DEATH ) )
save_char_obj( victim );
return;
}
void group_gain( CHAR_DATA * ch, CHAR_DATA * victim )
{
char buf[MAX_STRING_LENGTH];
CHAR_DATA *gch, *gch_next;
CHAR_DATA *lch;
int xp;
int members;
/*
* Monsters don't get kill xp's or alignment changes.
* Dying of mortal wounds or poison doesn't give xp to anyone!
*/
if( IS_NPC( ch ) || victim == ch )
return;
if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_QUESTOR ) && IS_NPC( victim ) )
{
if( ch->pcdata->questmob == victim->pIndexData->vnum )
{
send_to_char( "You have completed your quest!\n\r", ch );
send_to_char( "Return to the questmaster to recieve your reward before your time runs out!\n\r", ch );
ch->pcdata->questmob = -1;
}
}
members = 0;
for( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
{
if( is_same_group( gch, ch ) )
members++;
}
if( members == 0 )
{
bug( "%s: members %d", __FUNCTION__, members );
members = 1;
}
lch = ch->leader ? ch->leader : ch;
for( gch = ch->in_room->first_person; gch; gch = gch_next )
{
OBJ_DATA *obj;
OBJ_DATA *obj_next;
gch_next = gch->next_in_room;
if( !is_same_group( gch, ch ) )
continue;
if( gch->level - lch->level > 15 )
{
send_to_char( "You are too high for this group.\n\r", gch );
continue;
}
if( gch->level - lch->level < -15 )
{
send_to_char( "You are too low for this group.\n\r", gch );
continue;
}
xp = ( int )( xp_compute( gch, victim ) * 0.1765 ) / members;
if( !gch->fighting )
xp /= 2;
if( double_exp == TRUE )
{
xp = xp * 2;
}
if( ch->level < 100 && xp < 100 )
xp = 100;
gch->alignment = align_compute( gch, victim );
sprintf( buf, "You receive %d experience points.\n\r", xp );
send_to_char( buf, gch );
gain_exp( gch, xp );
for( obj = gch->first_carrying; obj; obj = obj_next )
{
obj_next = obj->next_content;
if( obj->wear_loc == WEAR_NONE )
continue;
if( ( IS_OBJ_STAT( obj, ITEM_ANTI_EVIL ) && IS_EVIL( gch ) ) ||
( IS_OBJ_STAT( obj, ITEM_ANTI_GOOD ) && IS_GOOD( gch ) ) ||
( IS_OBJ_STAT( obj, ITEM_ANTI_NEUTRAL ) && IS_NEUTRAL( gch ) ) )
{
act( AT_MAGIC, "You are zapped by $p.", gch, obj, NULL, TO_CHAR );
act( AT_MAGIC, "$n is zapped by $p.", gch, obj, NULL, TO_ROOM );
obj_from_char( obj );
obj = obj_to_room( obj, gch->in_room, ch );
oprog_zap_trigger( gch, obj ); /* mudprogs */
if( char_died( gch ) )
break;
}
}
}
return;
}
/*
* New alignment shift computation ported from Sillymud code.
* Samson 3-13-98
*/
int align_compute( CHAR_DATA * gch, CHAR_DATA * victim )
{
int change, align;
if( IS_NPC( gch ) )
return gch->alignment;
align = gch->alignment;
if( IS_GOOD( gch ) && IS_GOOD( victim ) )
change = ( victim->alignment / 100 ) * ( UMAX( 1, ( victim->level - gch->level ) ) );
else if( IS_EVIL( gch ) && IS_GOOD( victim ) )
change = ( victim->alignment / 60 ) * ( UMAX( 1, ( victim->level - gch->level ) ) );
else if( IS_EVIL( victim ) && IS_GOOD( gch ) )
change = ( victim->alignment / 60 ) * ( UMAX( 1, ( victim->level - gch->level ) ) );
else if( IS_EVIL( gch ) && IS_EVIL( victim ) )
change = ( ( victim->alignment / 100 ) + 1 ) * ( UMAX( 1, ( victim->level - gch->level ) ) );
else
change = ( victim->alignment / 80 ) * ( UMAX( 1, ( victim->level - gch->level ) ) );
if( change == 0 )
{
if( victim->alignment > 0 )
change = 1;
else if( victim->alignment < 0 )
change = -1;
}
align -= change;
align = UMAX( align, -1000 );
align = UMIN( align, 1000 );
return align;
}
/*
* Calculate how much XP gch should gain for killing victim
* Lots of redesigning for new exp system by Thoric
*/
int xp_compute( CHAR_DATA * gch, CHAR_DATA * victim )
{
int align;
int xp;
int xp_ratio;
int gchlev = gch->level;
xp = ( get_exp_worth( victim ) * URANGE( 0, ( victim->level - gchlev ) + 17, 13 ) ) / 10;
align = gch->alignment - victim->alignment;
/*
* bonus for attacking opposite alignment
*/
if( align > 990 || align < -990 )
xp = ( xp * 5 ) >> 2;
else
/*
* penalty for good attacking same alignment
*/
if( gch->alignment > 300 && align < 250 )
xp = ( xp * 3 ) >> 2;
xp = number_range( ( xp * 3 ) >> 2, ( xp * 5 ) >> 2 );
/*
* get 1/4 exp for players -Thoric
*/
if( !IS_NPC( victim ) )
xp /= 4;
/*
* semi-intelligent experienced player vs. novice player xp gain
* "bell curve"ish xp mod by Thoric
* based on time played vs. level
*/
if( !IS_NPC( gch ) && gchlev > 5 )
{
xp_ratio = ( int )gch->played / gchlev;
if( xp_ratio > 20000 ) /* 5/4 */
xp = ( xp * 5 ) >> 2;
else if( xp_ratio > 16000 ) /* 3/4 */
xp = ( xp * 3 ) >> 2;
else if( xp_ratio > 10000 ) /* 1/2 */
xp >>= 1;
else if( xp_ratio > 5000 ) /* 1/4 */
xp >>= 2;
else if( xp_ratio > 3500 ) /* 1/8 */
xp >>= 3;
else if( xp_ratio > 2000 ) /* 1/16 */
xp >>= 4;
}
/*
* Level based experience gain cap. Cannot get more experience for
* a kill than the amount for your current experience level -Thoric
*/
return URANGE( 0, xp, exp_level( gch, gchlev + 1 ) );
}
/*
* Revamped by Thoric to be more realistic
* Added code to produce different messages based on weapon type - FB
* Added better bug message so you can track down the bad dt's -Shaddai
*/
void new_dam_message( CHAR_DATA * ch, CHAR_DATA * victim, int dam, int dt, OBJ_DATA * obj )
{
char buf1[256], buf2[256], buf3[256];
char bugbuf[MAX_STRING_LENGTH];
const char *vs;
const char *vp;
const char *attack;
char punct;
short dampc;
struct skill_type *skill = NULL;
bool gcflag = FALSE;
bool gvflag = FALSE;
int d_index, w_index;
ROOM_INDEX_DATA *was_in_room;
if( !dam )
dampc = 0;
else
dampc = ( ( dam * 1000 ) / victim->max_hit ) + ( 50 - ( ( victim->hit * 50 ) / victim->max_hit ) );
if( ch->in_room != victim->in_room )
{
was_in_room = ch->in_room;
char_from_room( ch );
char_to_room( ch, victim->in_room );
}
else
was_in_room = NULL;
/*
* Get the weapon index
*/
if( dt > 0 && dt < top_sn )
{
w_index = 0;
}
else if( dt >= TYPE_HIT && dt < TYPE_HIT + sizeof( attack_table ) / sizeof( attack_table[0] ) )
{
w_index = dt - TYPE_HIT;
}
else
{
sprintf( bugbuf, "Dam_message: bad dt %d from %s in %d.", dt, ch->name, ch->in_room->vnum );
bug( bugbuf, 0 );
dt = TYPE_HIT;
w_index = 0;
}
/*
* get the damage index
*/
if( dam == 0 )
d_index = 0;
else if( dampc < 0 )
d_index = 1;
else if( dampc <= 100 )
d_index = 1 + dampc / 10;
else if( dampc <= 200 )
d_index = 11 + ( dampc - 100 ) / 20;
else if( dampc <= 900 )
d_index = 16 + ( dampc - 200 ) / 100;
else
d_index = 23;
/*
* Lookup the damage message
*/
vs = s_message_table[w_index][d_index];
vp = p_message_table[w_index][d_index];
punct = ( dampc <= 30 ) ? '.' : '!';
if( dam == 0 && ( !IS_NPC( ch ) && ( IS_SET( ch->pcdata->flags, PCFLAG_GAG ) ) ) )
gcflag = TRUE;
if( dam == 0 && ( !IS_NPC( victim ) && ( IS_SET( victim->pcdata->flags, PCFLAG_GAG ) ) ) )
gvflag = TRUE;
if( dt >= 0 && dt < top_sn )
skill = skill_table[dt];
if( dt == TYPE_HIT )
{
sprintf( buf1, "$n %s $N%c [%i]", vp, punct, dam );
sprintf( buf2, "You %s $N%c [%i]", vs, punct, dam );
sprintf( buf3, "$n %s you%c [%i]", vp, punct, dam );
}
else if( dt > TYPE_HIT && is_wielding_poisoned( ch ) )
{
if( dt < TYPE_HIT + sizeof( attack_table ) / sizeof( attack_table[0] ) )
attack = attack_table[dt - TYPE_HIT];
else
{
sprintf( bugbuf, "Dam_message: bad dt %d from %s in %d.", dt, ch->name, ch->in_room->vnum );
bug( bugbuf, 0 );
dt = TYPE_HIT;
attack = attack_table[0];
}
sprintf( buf1, "$n's poisoned %s %s $N%c [%i]", attack, vp, punct, dam );
sprintf( buf2, "Your poisoned %s %s $N%c [%i]", attack, vp, punct, dam );
sprintf( buf3, "$n's poisoned %s %s you%c [%i]", attack, vp, punct, dam );
}
else
{
if( skill )
{
attack = skill->noun_damage;
if( dam == 0 )
{
bool found = FALSE;
if( skill->miss_char && skill->miss_char[0] != '\0' )
{
act( AT_HIT, skill->miss_char, ch, NULL, victim, TO_CHAR );
found = TRUE;
}
if( skill->miss_vict && skill->miss_vict[0] != '\0' )
{
act( AT_HITME, skill->miss_vict, ch, NULL, victim, TO_VICT );
found = TRUE;
}
if( skill->miss_room && skill->miss_room[0] != '\0' )
{
if( strcmp( skill->miss_room, "supress" ) )
act( AT_ACTION, skill->miss_room, ch, NULL, victim, TO_NOTVICT );
found = TRUE;
}
if( found ) /* miss message already sent */
{
if( was_in_room )
{
char_from_room( ch );
char_to_room( ch, was_in_room );
}
return;
}
}
else
{
if( skill->hit_char && skill->hit_char[0] != '\0' )
act( AT_HIT, skill->hit_char, ch, NULL, victim, TO_CHAR );
if( skill->hit_vict && skill->hit_vict[0] != '\0' )
act( AT_HITME, skill->hit_vict, ch, NULL, victim, TO_VICT );
if( skill->hit_room && skill->hit_room[0] != '\0' )
act( AT_ACTION, skill->hit_room, ch, NULL, victim, TO_NOTVICT );
}
}
else if( dt >= TYPE_HIT && dt < TYPE_HIT + sizeof( attack_table ) / sizeof( attack_table[0] ) )
{
if( obj )
attack = obj->short_descr;
else
attack = attack_table[dt - TYPE_HIT];
}
else
{
sprintf( bugbuf, "Dam_message: bad dt %d from %s in %d.", dt, ch->name, ch->in_room->vnum );
bug( bugbuf, 0 );
dt = TYPE_HIT;
attack = attack_table[0];
}
sprintf( buf1, "$n %s $N%c [%i]", vp, punct, dam );
sprintf( buf2, "You %s $N%c [%i]", vs, punct, dam );
sprintf( buf3, "$n %s you%c [%i]", vp, punct, dam );
}
act( AT_ACTION, buf1, ch, NULL, victim, TO_NOTVICT );
if( !gcflag )
act( AT_HIT, buf2, ch, NULL, victim, TO_CHAR );
if( !gvflag )
act( AT_HITME, buf3, ch, NULL, victim, TO_VICT );
if( was_in_room )
{
char_from_room( ch );
char_to_room( ch, was_in_room );
}
return;
}
#ifndef dam_message
void dam_message( CHAR_DATA * ch, CHAR_DATA * victim, int dam, int dt )
{
new_dam_message( ch, victim, dam, dt );
}
#endif
void do_kill( CHAR_DATA * ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *victim;
one_argument( argument, arg );
if( arg[0] == '\0' )
{
send_to_char( "Kill whom?\n\r", ch );
return;
}
if( ( victim = get_char_room( ch, arg ) ) == NULL )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
if( IS_NPC( victim ) && victim->morph )
{
send_to_char( "This creature appears strange to you. Look upon it more closely before attempting to kill it.", ch );
return;
}
if( !IS_NPC( victim ) )
{
if( !xIS_SET( victim->act, PLR_KILLER ) || !xIS_SET( victim->act, PLR_THIEF ) )
{
send_to_char( "You must MURDER a player.\n\r", ch );
return;
}
}
/*
*
else
{
if ( IS_AFFECTED(victim, AFF_CHARM) && victim->master != NULL )
{
send_to_char( "You must MURDER a charmed creature.\n\r", ch );
return;
}
}
*
*/
if( victim == ch )
{
send_to_char( "You hit yourself. Ouch!\n\r", ch );
multi_hit( ch, ch, TYPE_UNDEFINED );
return;
}
if( is_safe( ch, victim, TRUE ) )
return;
if( IS_AFFECTED( ch, AFF_CHARM ) && ch->master == victim )
{
act( AT_PLAIN, "$N is your beloved master.", ch, NULL, victim, TO_CHAR );
return;
}
if( ch->position == POS_FIGHTING
|| ch->position == POS_EVASIVE
|| ch->position == POS_DEFENSIVE || ch->position == POS_AGGRESSIVE || ch->position == POS_BERSERK )
{
send_to_char( "You do the best you can!\n\r", ch );
return;
}
WAIT_STATE( ch, 1 * PULSE_VIOLENCE );
check_attacker( ch, victim );
multi_hit( ch, victim, TYPE_UNDEFINED );
return;
}
void do_murde( CHAR_DATA * ch, char *argument )
{
send_to_char( "If you want to MURDER, spell it out.\n\r", ch );
return;
}
void do_murder( CHAR_DATA * ch, char *argument )
{
char buf[MAX_STRING_LENGTH];
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *victim;
one_argument( argument, arg );
if( arg[0] == '\0' )
{
send_to_char( "Murder whom?\n\r", ch );
return;
}
if( ( victim = get_char_room( ch, arg ) ) == NULL )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
if( victim == ch )
{
send_to_char( "Suicide is a mortal sin.\n\r", ch );
return;
}
if( is_safe( ch, victim, TRUE ) )
return;
if( IS_AFFECTED( ch, AFF_CHARM ) )
{
if( ch->master == victim )
{
act( AT_PLAIN, "$N is your beloved master.", ch, NULL, victim, TO_CHAR );
return;
}
else
{
if( ch->master )
xSET_BIT( ch->master->act, PLR_ATTACKER );
}
}
if( ch->position == POS_FIGHTING
|| ch->position == POS_EVASIVE
|| ch->position == POS_DEFENSIVE || ch->position == POS_AGGRESSIVE || ch->position == POS_BERSERK )
{
send_to_char( "You do the best you can!\n\r", ch );
return;
}
if( !IS_NPC( victim ) && xIS_SET( ch->act, PLR_NICE ) )
{
send_to_char( "You feel too nice to do that!\n\r", ch );
return;
}
/*
* if ( !IS_NPC( victim ) && xIS_SET(victim->act, PLR_PK ) )
*/
if( !IS_NPC( victim ) )
{
sprintf( log_buf, "%s: murder %s.", ch->name, victim->name );
log_string_plus( log_buf, LOG_NORMAL, ch->level );
}
WAIT_STATE( ch, 1 * PULSE_VIOLENCE );
sprintf( buf, "Help! I am being attacked by %s!", IS_NPC( ch ) ? ch->short_descr : ch->name );
/*
* if ( IS_PKILL(victim) )
* do_wartalk( victim, buf );
* else
*/
do_yell( victim, buf );
check_illegal_pk( ch, victim );
check_attacker( ch, victim );
multi_hit( ch, victim, TYPE_UNDEFINED );
return;
}
/*
* Check to see if the player is in an "Arena".
*/
bool in_arena( CHAR_DATA * ch )
{
if( xIS_SET( ch->in_room->room_flags, ROOM_ARENA ) )
return TRUE;
if( IS_SET( ch->in_room->area->flags, AFLAG_FREEKILL ) )
return TRUE;
if( ch->in_room->vnum >= 29 && ch->in_room->vnum <= 43 )
return TRUE;
if( !str_cmp( ch->in_room->area->filename, "arena.are" ) )
return TRUE;
return FALSE;
}
bool check_illegal_pk( CHAR_DATA * ch, CHAR_DATA * victim )
{
char buf[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
if( !IS_NPC( victim ) && !IS_NPC( ch ) )
{
if( ( !IS_SET( victim->pcdata->flags, PCFLAG_DEADLY )
|| ch->level - victim->level > 10
|| !IS_SET( ch->pcdata->flags, PCFLAG_DEADLY ) )
&& !in_arena( ch ) && ch != victim && !( IS_IMMORTAL( ch ) && IS_IMMORTAL( victim ) ) )
{
if( IS_NPC( ch ) )
sprintf( buf, " (%s)", ch->name );
if( IS_NPC( victim ) )
sprintf( buf2, " (%s)", victim->name );
sprintf( log_buf, "&p%s on %s%s in &W***&rILLEGAL PKILL&W*** &pattempt at %d",
( lastplayercmd ),
( IS_NPC( victim ) ? victim->short_descr : victim->name ),
( IS_NPC( victim ) ? buf2 : "" ), victim->in_room->vnum );
last_pkroom = victim->in_room->vnum;
log_string( log_buf );
to_channel( log_buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL );
return TRUE;
}
}
return FALSE;
}
void do_flee( CHAR_DATA * ch, char *argument )
{
ROOM_INDEX_DATA *was_in;
ROOM_INDEX_DATA *now_in;
int attempt;
short door;
EXIT_DATA *pexit;
int oldmap = ch->map;
int oldx = ch->x;
int oldy = ch->y;
if( !who_fighting( ch ) )
{
if( ch->position == POS_FIGHTING
|| ch->position == POS_EVASIVE
|| ch->position == POS_DEFENSIVE || ch->position == POS_AGGRESSIVE || ch->position == POS_BERSERK )
{
if( ch->mount )
ch->position = POS_MOUNTED;
else
ch->position = POS_STANDING;
}
send_to_char( "You aren't fighting anyone.\n\r", ch );
return;
}
if( IS_AFFECTED( ch, AFF_BERSERK ) )
{
send_to_char( "Flee while berserking? You aren't thinking very clearly...\n\r", ch );
return;
}
if( ch->move <= 0 )
{
send_to_char( "You're too exhausted to flee from combat!\n\r", ch );
return;
}
/*
* No fleeing while more aggressive than standard or hurt. - Haus
*/
if( !IS_NPC( ch ) && ch->position < POS_FIGHTING )
{
send_to_char( "You can't flee in an aggressive stance...\n\r", ch );
return;
}
if( IS_NPC( ch ) && ch->position <= POS_SLEEPING )
return;
was_in = ch->in_room;
for( attempt = 0; attempt < 8; attempt++ )
{
door = number_door( );
if( ( pexit = get_exit( was_in, door ) ) == NULL
|| !pexit->to_room
|| IS_SET( pexit->exit_info, EX_NOFLEE )
|| ( IS_SET( pexit->exit_info, EX_CLOSED )
&& !IS_AFFECTED( ch, AFF_PASS_DOOR ) )
|| ( IS_NPC( ch ) && xIS_SET( pexit->to_room->room_flags, ROOM_NO_MOB ) ) )
continue;
affect_strip( ch, gsn_sneak );
xREMOVE_BIT( ch->affected_by, AFF_SNEAK );
if( ch->mount && ch->mount->fighting )
stop_fighting( ch->mount, TRUE );
move_char( ch, pexit, 0, door );
if( IS_PLR_FLAG( ch, PLR_ONMAP ) || IS_ACT_FLAG( ch, ACT_ONMAP ) )
{
now_in = ch->in_room;
if( ch->map == oldmap && ch->x == oldx && ch->y == oldy )
continue;
}
else
{
if( ( now_in = ch->in_room ) == was_in )
continue;
}
ch->in_room = was_in;
act( AT_FLEE, "$n flees head over heels!", ch, NULL, NULL, TO_ROOM );
ch->in_room = now_in;
act( AT_FLEE, "$n glances around for signs of pursuit.", ch, NULL, NULL, TO_ROOM );
if( !IS_NPC( ch ) )
{
CHAR_DATA *wf = who_fighting( ch );
act( AT_FLEE, "You flee head over heels from combat!", ch, NULL, NULL, TO_CHAR );
/*
* I dont like to loose just cause i bit off more than i can chew
* los = exp_level( ch, ch->level+1 ) * 0.02;
* if ( ch->level < 50 )
* {
* sprintf( buf, "Curse the gods, you've lost %d experience!", los );
* act( AT_FLEE, buf, ch, NULL, NULL, TO_CHAR );
* gain_exp( ch, 0 - los );
* }
*/
if( wf && ch->pcdata->deity )
{
int level_ratio = URANGE( 1, wf->level / ch->level, 50 );
if( wf && wf->race == ch->pcdata->deity->npcrace )
adjust_favor( ch, 1, level_ratio );
else if( wf && wf->race == ch->pcdata->deity->npcfoe )
adjust_favor( ch, 16, level_ratio );
else
adjust_favor( ch, 0, level_ratio );
}
}
stop_fighting( ch, TRUE );
return;
}
/*
* los = exp_level( ch, ch->level+1 ) * 0.01;
* act( AT_FLEE, "You attempt to flee from combat but can't escape!", ch, NULL, NULL, TO_CHAR );
* if ( ch->level < 50 && number_bits( 3 ) == 1 )
* {
* sprintf( buf, "Curse the gods, you've lost %d experience!\n\r", los );
* act( AT_FLEE, buf, ch, NULL, NULL, TO_CHAR );
* gain_exp( ch, 0 - los );
* }
*/
return;
}
void do_sla( CHAR_DATA * ch, char *argument )
{
send_to_char( "If you want to SLAY, spell it out.\n\r", ch );
return;
}
void do_slay( CHAR_DATA * ch, char *argument )
{
CHAR_DATA *victim;
char arg[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
argument = one_argument( argument, arg );
one_argument( argument, arg2 );
if( arg[0] == '\0' )
{
send_to_char( "Slay whom?\n\r", ch );
return;
}
if( ( victim = get_char_room( ch, arg ) ) == NULL )
{
send_to_char( "They aren't here.\n\r", ch );
return;
}
if( ch == victim )
{
send_to_char( "Suicide is a mortal sin.\n\r", ch );
return;
}
if( !IS_NPC( victim ) && get_trust( victim ) >= get_trust( ch ) )
{
send_to_char( "You failed.\n\r", ch );
return;
}
if( !str_cmp( arg2, "immolate" ) )
{
act( AT_FIRE, "Your fireball turns $N into a blazing inferno.", ch, NULL, victim, TO_CHAR );
act( AT_FIRE, "$n releases a searing fireball in your direction.", ch, NULL, victim, TO_VICT );
act( AT_FIRE, "$n points at $N, who bursts into a flaming inferno.", ch, NULL, victim, TO_NOTVICT );
}
else if( !str_cmp( arg2, "shatter" ) )
{
act( AT_LBLUE, "You freeze $N with a glance and shatter the frozen corpse into tiny shards.", ch, NULL, victim,
TO_CHAR );
act( AT_LBLUE, "$n freezes you with a glance and shatters your frozen body into tiny shards.", ch, NULL, victim,
TO_VICT );
act( AT_LBLUE, "$n freezes $N with a glance and shatters the frozen body into tiny shards.", ch, NULL, victim,
TO_NOTVICT );
}
else if( !str_cmp( arg2, "demon" ) )
{
act( AT_IMMORT, "You gesture, and a slavering demon appears. With a horrible grin, the", ch, NULL, victim, TO_CHAR );
act( AT_IMMORT, "foul creature turns on $N, who screams in panic before being eaten alive.", ch, NULL, victim,
TO_CHAR );
act( AT_IMMORT, "$n gestures, and a slavering demon appears. The foul creature turns on", ch, NULL, victim, TO_VICT );
act( AT_IMMORT, "you with a horrible grin. You scream in panic before being eaten alive.", ch, NULL, victim,
TO_VICT );
act( AT_IMMORT, "$n gestures, and a slavering demon appears. With a horrible grin, the", ch, NULL, victim,
TO_NOTVICT );
act( AT_IMMORT, "foul creature turns on $N, who screams in panic before being eaten alive.", ch, NULL, victim,
TO_NOTVICT );
}
else if( !str_cmp( arg2, "pounce" ) )
{
act( AT_BLOOD, "Leaping upon $N with bared fangs, you tear open $S throat and toss the corpse to the ground...", ch,
NULL, victim, TO_CHAR );
act( AT_BLOOD,
"In a heartbeat, $n rips $s fangs through your throat! Your blood sprays and pours to the ground as your life ends...",
ch, NULL, victim, TO_VICT );
act( AT_BLOOD,
"Leaping suddenly, $n sinks $s fangs into $N's throat. As blood sprays and gushes to the ground, $n tosses $N's dying body away.",
ch, NULL, victim, TO_NOTVICT );
}
else if( !str_cmp( arg2, "slit" ) )
{
act( AT_BLOOD, "You calmly slit $N's throat.", ch, NULL, victim, TO_CHAR );
act( AT_BLOOD, "$n reaches out with a clawed finger and calmly slits your throat.", ch, NULL, victim, TO_VICT );
act( AT_BLOOD, "$n calmly slits $N's throat.", ch, NULL, victim, TO_NOTVICT );
}
else if( !str_cmp( arg2, "dog" ) )
{
act( AT_BLOOD, "You order your dogs to rip $N to shreds.", ch, NULL, victim, TO_CHAR );
act( AT_BLOOD, "$n orders $s dogs to rip you apart.", ch, NULL, victim, TO_VICT );
act( AT_BLOOD, "$n orders $s dogs to rip $N to shreds.", ch, NULL, victim, TO_NOTVICT );
}
else
{
act( AT_IMMORT, "You slay $N in cold blood!", ch, NULL, victim, TO_CHAR );
act( AT_IMMORT, "$n slays you in cold blood!", ch, NULL, victim, TO_VICT );
act( AT_IMMORT, "$n slays $N in cold blood!", ch, NULL, victim, TO_NOTVICT );
}
set_cur_char( victim );
raw_kill( ch, victim );
return;
}