/*--------------------------------------------------------------------------* * ** WolfPaw 3.0 ** * *--------------------------------------------------------------------------* * WolfPaw 3.0 (c) 1997 - 1999 by Dale Corse * *--------------------------------------------------------------------------* * The WolfPaw Coding Team is headed by: Greywolf * * With the Assitance from: Callinon, Dhamon, Sentra, Wyverns, Altrag * * Scryn, Thoric, Justice, Tricops and Brogar. * *--------------------------------------------------------------------------* * Based on SMAUG 1.2a. Copyright 1994 - 1996 by Derek Snider * * SMAUG Coding Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, * * Swordbearer, Gorog, Grishnakh and Tricops. * *--------------------------------------------------------------------------* * Merc 2.1 Diku MUD Improvments (C) 1992 - 1993 by Michael Chastain, * * Michael Quan, and Michael Tse. * * Original Diku MUD (C) 1990 - 1991 by Sebastian Hammer, Michael Seifert, * * Hans Hendrik Strfeldt, Tom Madsen, and Katja Nyboe. * *--------------------------------------------------------------------------* * Battle & death module * ****************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <string.h> #include <time.h> #include "mud.h" extern char lastplayercmd[MAX_INPUT_LENGTH]; extern CHAR_DATA * gch_prev; bool death_handler args( ( CHAR_DATA *ch, CHAR_DATA *victim, bool npcvict ) ); void maim_update( CHAR_DATA *ch, CHAR_DATA *victim ); /* * Local functions. */ void dam_message args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt ) ); void death_cry args( ( CHAR_DATA *ch ) ); 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 ) ); bool remove_obj args( ( CHAR_DATA *ch, int iWear, bool fReplace )); int number_kombat args( ( void ) ); bool dual_flip = FALSE; bool fight_in_progress; /* for pk arena scheduling */ void quest_death_check args( ( CHAR_DATA *ch, CHAR_DATA *victim ) ); void ego_update args( ( CHAR_DATA *ch, CHAR_DATA *victim, bool gain ) ); bool can_flee_dir( CHAR_DATA *ch, int door ); /* * Check to see if weapon is poisoned. */ bool is_wielding_poisoned( CHAR_DATA *ch ) { OBJ_DATA *obj; if ( ( obj = get_eq_char( ch, WEAR_WIELD ) ) && (IS_SET( obj->extra_flags, 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 */ sh_int VAMP_AC( CHAR_DATA * ch ) { if ( IS_VAMPIRE( ch ) || IS_OUTSIDE( ch ) ) { switch(weather_info.sunlight) { case SUN_DARK: return -8; 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. */ 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 x, attacktype=0, cnt; SKILLTYPE *skill; ZONE_DATA *in_zone; lst_ch = NULL; 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; } /* * 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; } for ( timer = ch->first_timer; timer; timer = timer_next ) { timer_next = timer->next; if ( --timer->count <= 0 ) { 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 (( victim = who_fighting( ch ) ) == NULL || IS_AFFECTED( ch, AFF_PARALYSIS ) ) continue; retcode = rNONE; if ( IS_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 */ rprog_rfight_trigger( ch ); if ( char_died(ch) ) continue; mprog_hitprcnt_trigger( ch, victim ); if ( char_died(ch) ) continue; mprog_fight_trigger( ch, victim ); if ( char_died(ch) ) continue; /* * Maimers --GW */ maim_update( ch, victim ); if ( char_died(ch) ) continue; /* * NPC special attack flags -Thoric */ if ( IS_NPC(ch) ) { cnt = 0; if ( ch->attacks ) for ( ;; ) { if ( cnt++ > 10 ) { attacktype = 0; break; } x = number_range( 7, 31 ); attacktype = 1 << x; if ( IS_SET( ch->attacks, attacktype ) ) break; } if ( 30 + (ch->level/4) < number_percent( ) ) attacktype = 0; switch( attacktype ) { case ATCK_BASH: do_bash( ch, "" ); retcode = global_retcode; break; case ATCK_STUN: do_stun( ch, "" ); retcode = global_retcode; break; case ATCK_GOUGE: do_gouge( ch, "" ); retcode = global_retcode; break; case ATCK_FEED: do_feed( 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_SPIRALBLAST: retcode = spell_spiral_blast( skill_lookup( "spiral blast" ), ch->level, ch, victim ); break; case ATCK_POISON: retcode = spell_poison( gsn_poison, ch->level, ch, victim ); break; case ATCK_NASTYPOISON: /* retcode = spell_nasty_poison( skill_lookup( "nasty poison" ), ch->level, ch, victim ); */ break; case ATCK_GAZE: /* retcode = spell_gaze( skill_lookup( "gaze" ), ch->level, ch, victim ); */ break; case ATCK_BLINDNESS: retcode = spell_blindness( gsn_blindness, ch->level, ch, victim ); break; case ATCK_CAUSESERIOUS: retcode = spell_cause_serious( skill_lookup( "cause serious" ), ch->level, ch, victim ); break; case ATCK_EARTHQUAKE: retcode = spell_earthquake( skill_lookup( "earthquake" ), ch->level, ch, victim ); break; case ATCK_CAUSECRITICAL: retcode = spell_cause_critical( skill_lookup( "cause critical" ), ch->level, ch, victim ); break; case ATCK_CURSE: retcode = spell_curse( skill_lookup( "curse" ), ch->level, ch, victim ); break; case ATCK_FLAMESTRIKE: retcode = spell_flamestrike( skill_lookup( "flamestrike" ), ch->level, ch, victim ); break; case ATCK_HARM: retcode = spell_harm( skill_lookup( "harm" ), ch->level, ch, victim ); break; case ATCK_FIREBALL: retcode = spell_fireball( skill_lookup( "fireball" ), ch->level, ch, victim ); break; case ATCK_COLORSPRAY: retcode = spell_colour_spray( skill_lookup( "colour spray" ), ch->level, ch, victim ); break; case ATCK_WEAKEN: retcode = spell_weaken( skill_lookup( "weaken" ), ch->level, ch, victim ); break; } if ( retcode == rCHAR_DIED || (char_died(ch)) ) continue; /* * NPC special defense flags -Thoric */ cnt = 0; if ( ch->defenses ) for ( ;; ) { if ( cnt++ > 10 ) { attacktype = 0; break; } x = number_range( 2, 18 ); attacktype = 1 << x; if ( IS_SET( ch->defenses, attacktype ) ) break; } if ( 50 + (ch->level/4) < number_percent( ) ) attacktype = 0; switch( attacktype ) { case DFND_CURELIGHT: act( AT_MAGIC, "$n mutters a few incantations...and looks a little better.", ch, NULL, NULL, TO_ROOM ); retcode = spell_smaug( skill_lookup( "cure light" ), ch->level, ch, ch ); break; case DFND_CURESERIOUS: act( AT_MAGIC, "$n mutters a few incantations...and looks a bit better.", ch, NULL, NULL, TO_ROOM ); retcode = spell_smaug( skill_lookup( "cure serious" ), ch->level, ch, ch ); break; case DFND_CURECRITICAL: act( AT_MAGIC, "$n mutters a few incantations...and looks a bit healthier.", ch, NULL, NULL, TO_ROOM ); retcode = spell_smaug( skill_lookup( "cure critical" ), ch->level, ch, ch ); break; case DFND_DISPELMAGIC: act( AT_MAGIC, "$n mutters a few incantations...and waves $s arms about.", ch, NULL, NULL, TO_ROOM ); retcode = spell_dispel_magic( skill_lookup( "dispel magic" ), ch->level, ch, victim ); break; case DFND_DISPELEVIL: act( AT_MAGIC, "$n mutters a few incantations...and waves $s arms about.", ch, NULL, NULL, TO_ROOM ); retcode = spell_dispel_evil( skill_lookup( "dispel evil" ), ch->level, ch, victim ); break; case DFND_SANCTUARY: if ( !IS_AFFECTED(victim, AFF_SANCTUARY) ) { act( AT_MAGIC, "$n mutters a few incantations...", ch, NULL, NULL, TO_ROOM ); retcode = spell_smaug( skill_lookup( "sanctuary" ), ch->level, ch, ch ); } else retcode = rNONE; break; } if ( 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; 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) || IS_AFFECTED(rch, AFF_CHARM) ) && is_same_group(ch, rch) ) 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) && !IS_SET(rch->act, ACT_NOASSIST) ) { 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 ) { if ( can_see( rch, vch ) && is_same_group( vch, victim ) && number_range( 0, number ) == 0 ) { target = vch; number++; } } if ( target ) multi_hit( rch, target, TYPE_UNDEFINED ); } } } } } for( in_zone = first_zone; in_zone; in_zone = in_zone->next ) { for ( ch = in_zone->last_mob; ch; lst_ch = ch, ch = gch_prev ) { set_cur_char( ch ); if ( ch == in_zone->first_mob && 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; } /* * 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; } for ( timer = ch->first_timer; timer; timer = timer_next ) { timer_next = timer->next; if ( --timer->count <= 0 ) { 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 (( victim = who_fighting( ch ) ) == NULL || IS_AFFECTED( ch, AFF_PARALYSIS ) ) continue; retcode = rNONE; if ( IS_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; if ( ch->stun_rounds < 1 ) { /* * Mob triggers */ rprog_rfight_trigger( ch ); if ( char_died(ch) ) continue; mprog_hitprcnt_trigger( ch, victim ); if ( char_died(ch) ) continue; mprog_fight_trigger( ch, victim ); if ( char_died(ch) ) continue; /* Smart Mobbies -- YIKES! --GW */ smart_update( ch, victim ); /* * Maimers --GW */ maim_update( ch, victim ); if ( char_died(ch) ) continue; /* * NPC special attack flags -Thoric */ if ( IS_NPC(ch) ) { cnt = 0; if ( ch->attacks ) for ( ;; ) { if ( cnt++ > 10 ) { attacktype = 0; break; } x = number_range( 7, 31 ); attacktype = 1 << x; if ( IS_SET( ch->attacks, attacktype ) ) break; } if ( 30 + (ch->level/4) < number_percent( ) ) attacktype = 0; switch( attacktype ) { case ATCK_BASH: do_bash( ch, "" ); retcode = global_retcode; break; case ATCK_STUN: do_stun( ch, "" ); retcode = global_retcode; break; case ATCK_GOUGE: do_gouge( ch, "" ); retcode = global_retcode; break; case ATCK_FEED: do_feed( 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_SPIRALBLAST: retcode = spell_spiral_blast( skill_lookup( "spiral blast" ), ch->level, ch, victim ); break; case ATCK_POISON: retcode = spell_poison( gsn_poison, ch->level, ch, victim ); break; case ATCK_NASTYPOISON: /* retcode = spell_nasty_poison( skill_lookup( "nasty poison" ), ch->level, ch, victim ); */ break; case ATCK_GAZE: /* retcode = spell_gaze( skill_lookup( "gaze" ), ch->level, ch, victim ); */ break; case ATCK_BLINDNESS: retcode = spell_blindness( gsn_blindness, ch->level, ch, victim ); break; case ATCK_CAUSESERIOUS: retcode = spell_cause_serious( skill_lookup( "cause serious" ), ch->level, ch, victim ); break; case ATCK_EARTHQUAKE: retcode = spell_earthquake( skill_lookup( "earthquake" ), ch->level, ch, victim ); break; case ATCK_CAUSECRITICAL: retcode = spell_cause_critical( skill_lookup( "cause critical" ), ch->level, ch, victim ); break; case ATCK_CURSE: retcode = spell_curse( skill_lookup( "curse" ), ch->level, ch, victim ); break; case ATCK_FLAMESTRIKE: retcode = spell_flamestrike( skill_lookup( "flamestrike" ), ch->level, ch, victim ); break; case ATCK_HARM: retcode = spell_harm( skill_lookup( "harm" ), ch->level, ch, victim ); break; case ATCK_FIREBALL: retcode = spell_fireball( skill_lookup( "fireball" ), ch->level, ch, victim ); break; case ATCK_COLORSPRAY: retcode = spell_colour_spray( skill_lookup( "colour spray" ), ch->level, ch, victim ); break; case ATCK_WEAKEN: retcode = spell_weaken( skill_lookup( "weaken" ), ch->level, ch, victim ); break; } if ( retcode == rCHAR_DIED || (char_died(ch)) ) continue; /* * NPC special defense flags -Thoric */ cnt = 0; if ( ch->defenses ) for ( ;; ) { if ( cnt++ > 10 ) { attacktype = 0; break; } x = number_range( 2, 18 ); attacktype = 1 << x; if ( IS_SET( ch->defenses, attacktype ) ) break; } if ( 50 + (ch->level/4) < number_percent( ) ) attacktype = 0; switch( attacktype ) { case DFND_CURELIGHT: act( AT_MAGIC, "$n mutters a few incantations...and looks a little better.", ch, NULL, NULL, TO_ROOM ); retcode = spell_smaug( skill_lookup( "cure light" ), ch->level, ch, ch ); break; case DFND_CURESERIOUS: act( AT_MAGIC, "$n mutters a few incantations...and looks a bit better.", ch, NULL, NULL, TO_ROOM ); retcode = spell_smaug( skill_lookup( "cure serious" ), ch->level, ch, ch ); break; case DFND_CURECRITICAL: act( AT_MAGIC, "$n mutters a few incantations...and looks a bit healthier.", ch, NULL, NULL, TO_ROOM ); retcode = spell_smaug( skill_lookup( "cure critical" ), ch->level, ch, ch ); break; case DFND_DISPELMAGIC: act( AT_MAGIC, "$n mutters a few incantations...and waves $s arms about.", ch, NULL, NULL, TO_ROOM ); retcode = spell_dispel_magic( skill_lookup( "dispel magic" ), ch->level, ch, victim ); break; case DFND_DISPELEVIL: act( AT_MAGIC, "$n mutters a few incantations...and waves $s arms about.", ch, NULL, NULL, TO_ROOM ); retcode = spell_dispel_evil( skill_lookup( "dispel evil" ), ch->level, ch, victim ); break; case DFND_SANCTUARY: if ( !IS_AFFECTED(victim, AFF_SANCTUARY) ) { act( AT_MAGIC, "$n mutters a few incantations...", ch, NULL, NULL, TO_ROOM ); retcode = spell_smaug( skill_lookup( "sanctuary" ), ch->level, ch, ch ); } else retcode = rNONE; break; } if ( 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; 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) || IS_AFFECTED(rch, AFF_CHARM) ) && is_same_group(ch, rch) ) 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) && !IS_SET(rch->act, ACT_NOASSIST) ) { 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 ) { if ( can_see( rch, vch ) && is_same_group( vch, victim ) && number_range( 0, number ) == 0 ) { 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 chance; int dual_bonus; ch_ret retcode=rNONE; if ( !ch || !victim ) return rNONE; arrest(ch); if ( check_warrents(ch)==TRUE) return rNONE; if ( IS_AFFECTED(victim,AFF_REFLECT_DAMAGE) ) act(AT_RED,"$n's chest glows, as some damage reflects!",victim,NULL,NULL,TO_ROOM); /* add timer if player is attacking another player */ if ( !IS_NPC(ch) && !IS_NPC(victim) ) add_timer( ch, TIMER_RECENTFIGHT, 20, NULL, 0 ); if ( !IS_NPC(ch) && IS_SET( ch->act, PLR_NICE ) && !IS_NPC( victim ) ) return rNONE; if ( ch->stun_rounds > 0 ) { ch->stun_rounds--; return rNONE; } if ( char_died(victim) ) return rCHAR_DIED; if ( ch && victim && ch->in_room && victim->in_room && ( ch->in_room == victim->in_room ) ) { if ( (retcode = one_hit( ch, victim, dt )) != rNONE ) return retcode; } if ( who_fighting( ch ) != victim || dt == gsn_backstab || dt == gsn_circle || dt == gsn_assassinate ) 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 */ chance = IS_NPC(ch) ? 100 : (ch->pcdata->learned[gsn_berserk]*5/2); if ( char_died(victim) ) return rCHAR_DIED; if ( IS_AFFECTED(ch, AFF_BERSERK) && number_percent() < chance ) if ( (retcode = one_hit( ch, victim, dt )) != rNONE || who_fighting( ch ) != victim ) return retcode; if ( char_died(victim) ) return rCHAR_DIED; if ( get_eq_char( ch, WEAR_DUAL_WIELD ) ) { dual_bonus = IS_NPC(ch) ? (ch->level / 10) : (ch->pcdata->learned[gsn_dual_wield] / 10); chance = IS_NPC(ch) ? ch->level : ch->pcdata->learned[gsn_dual_wield]; if ( number_percent( ) < chance ) { 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 ( chance = 0; chance <= ch->numattacks; chance++ ) { if ( char_died(victim) ) return rCHAR_DIED; retcode = one_hit( ch, victim, dt ); if ( retcode != rNONE || who_fighting( ch ) != victim ) return retcode; } return retcode; } chance = IS_NPC(ch) ? ch->level : (int) ((ch->pcdata->learned[gsn_second_attack]+dual_bonus)/1.5); if ( number_percent( ) < chance ) { if ( char_died(victim) ) return rCHAR_DIED; 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 ); chance = IS_NPC(ch) ? ch->level : (int) ((ch->pcdata->learned[gsn_third_attack]+(dual_bonus*1.5))/2); if ( number_percent( ) < chance ) { if ( char_died(victim) ) return rCHAR_DIED; 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 ); chance = IS_NPC(ch) ? ch->level : (int) ((ch->pcdata->learned[gsn_fourth_attack]+(dual_bonus*2))/3); if ( number_percent( ) < chance ) { if ( char_died(victim) ) return rCHAR_DIED; 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 ); chance = IS_NPC(ch) ? ch->level : (int) ((ch->pcdata->learned[gsn_fifth_attack]+(dual_bonus*3))/4); if ( number_percent( ) < chance ) { if ( char_died(victim) ) return rCHAR_DIED; 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 ); chance = IS_NPC(ch) ? ch->level : (int) ((ch->pcdata->learned[gsn_sixth_attack]+(dual_bonus*4))/5); if ( number_percent( ) < chance ) { if ( char_died(victim) ) return rCHAR_DIED; 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 ); chance = IS_NPC(ch) ? ch->level : (int) ((ch->pcdata->learned[gsn_seventh_attack]+(dual_bonus*5))/6); if ( number_percent( ) < chance ) { if ( char_died(victim) ) return rCHAR_DIED; 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 ); retcode = rNONE; if ( char_died(victim) ) return rCHAR_DIED; chance = IS_NPC(ch) ? (int) (ch->level / 2) : 0; if ( number_percent( ) < chance ) 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 = -1; if ( !IS_NPC(ch) && ch->level > 5 && wield ) { switch(wield->value[3]) { default: *gsn_ptr = -1; break; case 0: *gsn_ptr = gsn_pugilism; break; case 1: *gsn_ptr = gsn_long_blades; break; case 2: *gsn_ptr = gsn_short_blades; break; case 3: *gsn_ptr = gsn_short_blades; break; case 4: *gsn_ptr = gsn_flexible_arms; break; case 5: *gsn_ptr = gsn_talonous_arms; break; case 6: *gsn_ptr = gsn_pugilism; break; case 7: *gsn_ptr = gsn_bludgeons; break; case 8: *gsn_ptr = gsn_bludgeons; break; case 10: *gsn_ptr = gsn_short_blades; break; case 11: *gsn_ptr = gsn_short_blades; break; case 12: *gsn_ptr = gsn_bludgeons; break; case 13: case 14: case 15: case 16: case 17: *gsn_ptr = gsn_missile_weapons; break; } if ( *gsn_ptr != -1 ) bonus = (int) ((ch->pcdata->learned[*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 = bonus - abs( ch->pcdata->favor ) / -100 ; } } 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 */ sh_int off_shld_lvl( CHAR_DATA *ch, CHAR_DATA *victim ) { sh_int lvl; if ( !IS_NPC(ch) ) /* players get much less effect */ { lvl = UMAX( 1, (ch->level - 10) / 2 ); if ( number_percent() + (victim->level - lvl) < 35 ) 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; long dam, x; int diceroll; int attacktype, cnt; int prof_bonus; int prof_gsn; ch_ret retcode=rNONE; if ( !ch || !victim ) return rVICT_DIED; if ( char_died(victim) ) return rCHAR_DIED; /* * 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; /* * Rooms seem to get fucked in fights - fix it --GW */ if ( ch->in_room ) ch->was_in_room = ch->in_room; if ( victim->in_room ) victim->was_in_room = victim->in_room; if ( !ch->in_room && ch->was_in_room ) char_to_room(ch,ch->was_in_room); if ( !victim->in_room && victim->was_in_room ) char_to_room(victim,victim->was_in_room); /* * New Stun Code --GW */ if ( ch->stun_rounds > 0 ) return rNONE; /* * Figure out the weapon doing the damage -Thoric */ 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 ); prof_bonus = weapon_prof_bonus_check( ch, wield, &prof_gsn ); if ( ch->fighting /* make sure fight is already started */ && dt == TYPE_UNDEFINED && IS_NPC(ch) && ch->attacks != 0 ) { cnt = 0; for ( ;; ) { x = number_range( 0, 6 ); attacktype = 1 << x; if ( IS_SET( ch->attacks, attacktype ) ) break; if ( cnt++ > 16 ) { attacktype = 0; break; } } if ( attacktype == ATCK_BACKSTAB ) attacktype = 0; if ( wield && number_percent( ) > 25 ) attacktype = 0; switch ( attacktype ) { default: break; case ATCK_BITE: do_bite( ch, "" ); retcode = global_retcode; break; case ATCK_CLAWS: do_claw( ch, "" ); retcode = global_retcode; break; case ATCK_TAIL: do_tail( ch, "" ); retcode = global_retcode; break; case ATCK_STING: do_sting( ch, "" ); retcode = global_retcode; break; case ATCK_PUNCH: do_punch( ch, "" ); retcode = global_retcode; break; case ATCK_KICK: do_kick( ch, "" ); retcode = global_retcode; break; case ATCK_TRIP: attacktype = 0; break; } if ( attacktype ) 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 ( ch->class == -1 ) return 0; 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 ) ) victim_ac -= 4; /* * "learning" between combatients. Takes the intelligence difference, * and multiplies by the times killed to make up a learning bonus * given to whoever is more intelligent -Thoric */ if ( ch->fighting && ch->fighting->who == victim ) { sh_int times = ch->fighting->timeskilled; if ( times ) { sh_int 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 || ( diceroll != 19 && diceroll < thac0 - victim_ac ) ) { /* Miss. */ if ( prof_gsn != -1 ) learn_from_failure( ch, prof_gsn ); damage( ch, victim, 0, dt ); tail_chain( ); return rNONE; } /* * Hit. * Calc damage. */ /* Thoric's Dice job re-fixed by Greywolf, thanks to G. Moody. --GW */ dam = number_range( ch->barenumdie, ch->baresizedie * ch->barenumdie ) + ch->damplus; dam += number_range( ch->perm_str, ( ch->level * 2.4 )); if ( wield ) dam += number_range(wield->value[1],wield->value[2]); /* * Bonuses. */ dam += GET_DAMROLL(ch); if ( prof_bonus ) dam += prof_bonus / 4; if ( !IS_NPC(ch) && ch->pcdata->learned[gsn_enhanced_damage] > 0 ) { dam += (int) (dam * ch->pcdata->learned[gsn_enhanced_damage] / 120); learn_from_success( ch, gsn_enhanced_damage ); } if ( !IS_AWAKE(victim) ) dam *= 2; if ( dt == gsn_backstab ) dam *= (2 + URANGE( 2, ch->level - (victim->level/4), 30 ) / 8); if ( dt == gsn_assassinate ) dam *= (4 + URANGE( 2, ch->level - (victim->level/2), 30) / 4 ); /* This comment-keyword is here for easy jumping -- Cal (CIRCLE) */ /* It's a little silly I know but hey it's original :P */ if ( dt == gsn_circle ) dam *= (2 + URANGE( 2, ch->level - (victim->level/4), 30 ) / 16); plusris = 0; wield = get_eq_char( ch, WEAR_WIELD ); if ( wield && !IS_SET(wield->magic_flags, ITEM_DISSOLVE_IMM) ) { if ( IS_SET( wield->extra_flags, 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 ( (wield && !IS_SET(wield->magic_flags, ITEM_DISSOLVE_IMM)) || !wield ) { 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 */ /* Cackle.. opps.. I guess immune isnt 100% anymore eh... GW */ if ( (x=number_range(1,100)) > 75 ) { 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 ); } if ( (wield && !IS_SET(wield->magic_flags, ITEM_DISSOLVE_IMM) ) || !wield ) { /* 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 ( !ch ) return rNONE; if ( !victim ) return rNONE; /* Damage Cap --GW */ /* Player vs. Player Cap */ if ( !IS_NPC(ch) && !IS_NPC(victim) && dam > 1500 ) dam = 1500; /* Mob vs. Player */ if ( IS_NPC(ch) && !IS_NPC(victim) && dam > 4500 ) dam = 4500; /* Player vs. Mob */ if ( !IS_NPC(ch) && IS_NPC(victim) && dam > 2000 ) dam = 2000; 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 spells -Thoric */ if ( wield && ((x=number_range(1,100))>50) /* 50% fail chance..--GW */ && (!IS_SET(wield->magic_flags, ITEM_DISSOLVE_IMM) && !IS_SET(victim->immune, RIS_MAGIC)) && !IS_SET(victim->in_room->room_flags, ROOM_NO_MAGIC) ) { AFFECT_DATA *aff; if ( retcode != rNONE || char_died(ch) || char_died(victim) ) return rCHAR_DIED; for ( aff = wield->pIndexData->first_affect; aff; aff = aff->next ) if ( aff->location == APPLY_WEAPONSPELL && IS_VALID_SN(aff->modifier) && !char_died(ch) && !char_died(victim) && skill_table[aff->modifier]->spell_fun ) retcode = (*skill_table[aff->modifier]->spell_fun) (aff->modifier, (ch->level+3)/3, 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) && !char_died(ch) && !char_died(victim) && skill_table[aff->modifier]->spell_fun ) retcode = (*skill_table[aff->modifier]->spell_fun) (aff->modifier, (ch->level+3)/3, ch, victim ); if ( retcode != rNONE || char_died(ch) || char_died(victim) ) return retcode; } /* * magic shields that retaliate -Thoric */ if ( IS_AFFECTED( victim, AFF_FIRESHIELD ) && !IS_AFFECTED( ch, AFF_FIRESHIELD ) ) retcode = spell_fireball( gsn_fireball, off_shld_lvl(victim, ch), victim, ch ); if ( retcode != rNONE || char_died(ch) || char_died(victim) ) return retcode; if ( IS_AFFECTED( victim, AFF_ICESHIELD ) && !IS_AFFECTED( ch, AFF_ICESHIELD ) ) retcode = spell_chill_touch( gsn_chill_touch, off_shld_lvl(victim, ch), victim, ch ); if ( retcode != rNONE || char_died(ch) || char_died(victim) ) return retcode; if ( IS_AFFECTED( victim, AFF_SHOCKSHIELD ) && !IS_AFFECTED( ch, AFF_SHOCKSHIELD ) ) retcode = spell_lightning_bolt( gsn_lightning_bolt, off_shld_lvl(victim, ch), victim, ch ); if ( retcode != rNONE || char_died(ch) || char_died(victim) ) return retcode; tail_chain( ); return retcode; } /* * Calculate damage based on resistances, immunities and suceptibilities * -Thoric */ sh_int ris_damage( CHAR_DATA *ch, long dam, int ris ) { sh_int modifier; int rand=0; modifier = 10; if ( IS_SET(ch->immune, ris ) ) modifier -= 10; if ( IS_SET(ch->resistant, ris ) ) modifier -= 2; if ( IS_SET(ch->susceptible, ris ) ) modifier += 2; /* Failure.. it is NOT an Immunity!--GW*/ if ( modifier < 0 && ch->fighting && (rand=number_range(1,100))<(ch->fighting->who->level/4)) return dam; if ( modifier <= 0 ) return -1; if ( modifier == 10 ) return dam; return (dam * modifier) / 10; } /* * Inflict damage from a hit. */ ch_ret damage( CHAR_DATA *ch, CHAR_DATA *victim, long dam, int dt ) { char buf1[MAX_STRING_LENGTH]; sh_int dameq; sh_int maxdam; bool npcvict; bool loot; long xp_gain; OBJ_DATA *damobj; OBJ_DATA *obj; ch_ret retcode; sh_int dampmod; CHAR_DATA *gch; bool death; bool selfdeath; int init_gold, new_gold, gold_diff; extern sh_int dam_no_msg; death = FALSE; selfdeath = FALSE; 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); if ( ch->stun_rounds > 0 ) return rNONE; /* * 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 if ( dt == (TYPE_HIT + 7) || dt == (TYPE_HIT + 8) ) dam = ris_damage(victim, dam, RIS_BLUNT); else if ( dt == (TYPE_HIT + 2) || dt == (TYPE_HIT + 11) || dt == (TYPE_HIT + 10) ) dam = ris_damage(victim, dam, RIS_PIERCE); else if ( dt == (TYPE_HIT + 1) || dt == (TYPE_HIT + 3) || dt == (TYPE_HIT + 4) || dt == (TYPE_HIT + 5) ) dam = ris_damage(victim, dam, RIS_SLASH); 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; } } if ( dam && npcvict && ch != victim ) { if ( !IS_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 start_hunting( victim, ch ); } if ( victim->hating ) { if ( victim->hating->who != ch ) { if (victim && victim->hating && victim->hating->name ) STRFREE( victim->hating->name ); victim->hating->name = QUICKLINK( ch->name ); victim->hating->who = ch; } } else start_hating( victim, ch ); } /* * Stop up any residual loopholes. */ maxdam = ch->level * 30; if ( dt == gsn_backstab ) maxdam = ch->level * 80; if ( dt == gsn_assassinate ) maxdam = ch->level * 80; if ( ( dam > maxdam) &&(ch->level2 != 50 )) dam = maxdam; if ( victim != ch ) { /* * Certain attacks are forbidden. * Most other attacks are returned. */ if ( !ch ) return rNONE; if ( !victim ) return rNONE; if (ch && victim && is_safe( ch, victim ) ) return rNONE; if ( victim->position > POS_STUNNED ) { if ( !victim->fighting ) set_fighting( victim, ch ); if ( victim->fighting ) victim->position = POS_FIGHTING; } if ( victim->position > POS_STUNNED ) { if ( !ch->fighting ) 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 && 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. */ /* { sh_int anopc = 0; * # of (non-pkill) pc in a (ch) * sh_int bnopc = 0; * # of (non-pkill) pc in b (victim) * CHAR_DATA *lch; * leader ch * * 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 * if ( ( bnopc > 0 ) && ( anopc > 0 ) ) { * look at group a through ch's leader first * lch = ch->leader ? ch->leader : ch; if ( lch != ch ) { * stop following leader if it isn't pk * if ( !IS_NPC(lch) && !IS_PKILL( lch ) ) stop_follower( ch ); else { * disband non-pk members from lch's group if it is pk * for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { if ( is_same_group( lch, gch ) && ( lch != gch ) && !IS_NPC(gch) && !IS_PKILL( gch ) ) stop_follower( gch ); } } } else for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { * ch is leader - disband non-pks from group * if ( is_same_group( ch, gch ) && ( ch != gch ) && ( !IS_PKILL( gch ) && !IS_NPC( gch ) ) ) stop_follower( gch ); } * time to look at the victims group through its leader * lch = victim->leader ? victim->leader : victim; if ( lch != victim ) { * if leader isn't deadly, stop following lch * if ( !IS_PKILL( lch ) && !IS_NPC( lch ) ) stop_follower( victim ); else { * lch is pk, disband non-pk's from group * for ( gch = victim->in_room->first_person; gch; gch = gch->next_in_room ) { if ( is_same_group( lch, gch ) && ( lch != gch ) && ( !IS_PKILL( gch ) && !IS_NPC( gch ) ) ) stop_follower( gch ); } } } else { * victim is leader of group - disband non-pks * for ( gch = victim->in_room->first_person; gch; gch = gch->next_in_room ) { if ( is_same_group( victim, gch ) && ( victim != gch ) && !IS_PKILL( gch ) && !IS_NPC( gch ) ) stop_follower( gch ); } } } }*/ { sh_int anopc = 0; /* # of (non-pkill) pc in a (ch) */ sh_int bnopc = 0; /* # of (non-pkill) pc in b (victim) */ /* 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 ); } } } } /* for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { if ( is_same_group( ch, gch ) && ( IS_PKILL( ch ) != IS_PKILL( gch ) ) ) { stop_follower( ch ); stop_follower( gch ); } } for ( gch = victim->in_room->first_person; gch; gch = gch->next_in_room ) { if ( is_same_group( victim, gch ) && ( IS_PKILL( victim ) != IS_PKILL( gch ) ) ) { stop_follower( victim ); stop_follower( gch ); } } */ /* * Inviso attacks ... not. */ if ( IS_AFFECTED(ch, AFF_INVISIBLE) || IS_SET(ch->act, ACT_MOBINVIS) ) { affect_strip( ch, gsn_invis ); affect_strip( ch, gsn_mass_invis ); xREMOVE_BIT( ch->affected_by, AFF_INVISIBLE ); REMOVE_BIT( ch->act, ACT_MOBINVIS ); 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); /* * Check for disarm, trip, parry, and dodge. */ if ( dt >= TYPE_HIT && victim->stun_rounds < 1 ) { if ( IS_NPC(ch) && IS_SET( ch->attacks, DFND_DISARM ) && ch->level > 9 && number_percent( ) < ch->level / 2 ) disarm( ch, victim ); if ( IS_NPC(ch) && IS_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; } /* * 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; /* Make stunned Mobiles/Characters take 1/4 the damage, being thay cannot * defend themselves, and are dying to fast --GW */ if ( victim->stun_rounds > 0 ) dam = dam/4; 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 > 10 && dt != TYPE_UNDEFINED) { /* get a random body eq part */ dameq = number_range(WEAR_LIGHT, WEAR_EYES); damobj = get_eq_char(victim, dameq); if ( damobj ) { if ( dam > get_obj_resistance(damobj) ) { set_cur_obj(damobj); damage_obj(damobj); } dam -= 5; /* add a bonus for having something to block the blow */ } else dam += 5; /* add penalty for bare skin! */ } /* Reflect Damage Stuff --GW */ if ( IS_AFFECTED(victim, AFF_REFLECT_DAMAGE) ) { CHAR_DATA *dam_char, *dam_next; for( dam_char = victim->in_room->first_person; dam_char; dam_char = dam_next ) { dam_next = dam_char->next_in_room; /* Don't hit myself.. */ if ( dam_char == victim || IS_NPC(ch) || dam==0 ) continue; dam_no_msg = 1; /* Inflict 1/4th the damage done on each character (yes it hurts!) */ damage(victim,ch,(dam/4),TYPE_UNDEFINED); dam_no_msg = 0; } dam = dam/4; } /* * Hurt the victim. * Inform the victim of his new state. */ if ( dam > 1500 || dam < 0 ) dam = 1500; URANGE(0,victim->hit -= dam,victim->max_hit+5); /* * Get experience based on % of damage done -Thoric */ if ( dam && ch != victim && !IS_NPC(ch) && ch->fighting && ch->fighting->xp ) { if ( ch->fighting->who == victim ) xp_gain = URANGE(0, (int) (ch->fighting->xp * dam) / victim->max_hit, 2100000000); else xp_gain = URANGE(0, (int) (xp_compute( ch, victim ) * 1.90 * dam) / victim->max_hit, 2100000000); if ( IS_NPC(ch->fighting->who) && IS_SET(ch->fighting->who->act,ACT_CREATE_LIFE_MOB)) xp_gain=0; if ( !IS_NPC(ch) ) ch->pcdata->battle_xp += xp_gain; gain_exp( ch, xp_gain, TRUE ); } if (!IS_NPC(victim) && ( !in_arena(victim) && chaos != 1 ) && !IS_SET(victim->pcdata->flags, PCFLAG_KOMBAT ) && victim->level >= LEVEL_IMMORTAL && victim->hit < 1 ) victim->hit = 1; /* 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 ); ch->mental_state = URANGE( 20, ch->mental_state + 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 ); } stop_fighting(victim,TRUE); if ( !IS_NPC(ch) && IS_SET( ch->pcdata->flags, PCFLAG_OLD_DEATH ) ) grim_reaper(victim,TRUE); else grim_reaper(victim,FALSE); /* if ( !victim->in_room ) { if ( victim->in_room ) char_from_room(victim); char_to_room(victim,victim->was_in_room); } if ( !ch->in_room ) { if ( ch->in_room ) char_from_room(ch); char_to_room(ch,ch->was_in_room); } */ break; default: 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( ch, 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( ch, 1 ); } break; } /* * Sleep spells and extremely wounded folks. */ /*if ( *//*!IS_AWAKE(victim) Nah let them die! --GW */ /*letsmake 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 );*/ /* }*/ /* Added this cause the mobile seems to still be fightin the char and vice versa after the attack is done, for ranged attacks --GW */ if ( ch->in_room != victim->in_room ) stop_fighting(ch,TRUE); /* * Payoff for killing things. * Was to much crap here, in death.c now --GW */ if ( victim->position == POS_DEAD ) { group_gain( ch, victim ); /* * Check to see if thats there Quest Mob! --GW */ quest_death_check(ch,victim); /* * Fix up the killers ego --GW */ ego_update(ch,victim, TRUE); if ( !npcvict ) { if ( ( death_handler( ch, victim, npcvict ))==TRUE ) { return TRUE; } /* * Dying penalty: * 1/2 way back to previous level. */ if ( victim->exp > exp_level(victim, victim->level) ) victim->exp -= (victim->exp/2); do_help(victim,"_DIEMSG_"); /* * New penalty... go back to the beginning of current level. victim->exp = exp_level( victim, victim->level ); */ } else if ( !IS_NPC(ch) ) /* keep track of mob vnum killed */ add_kill( ch, victim ); loot = legal_loot( ch, victim ); set_cur_char(victim); raw_kill( ch, victim ); victim = NULL; if ( !IS_NPC(ch) && loot ) { /* Autogold by Scryn 8/12 */ if ( IS_SET(ch->act, PLR_AUTOGOLD) && npcvict ) { init_gold = ch->gold; do_get( ch, "coins corpse" ); do_get( ch, "pieces 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 ( IS_SET(ch->act, PLR_AUTOLOOT) && npcvict ) do_get( ch, "all corpse" ); else do_look( ch, "in corpse" ); if ( IS_SET(ch->act, PLR_AUTOSAC) && npcvict ) { if ( ms_find_obj(ch) ) return rVICT_DIED; if ( ch->in_room ) { obj = get_obj_list_rev( ch, "corpse", ch->in_room->last_content ); if ( !obj ) { return rVICT_DIED; } if ( obj->item_type == ITEM_CORPSE_NPC ) 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 ( ( IS_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 && IS_SET( victim->act, PLR_FLEE ) ) do_flee( victim, "" ); tail_chain( ); return rNONE; } bool is_safe( CHAR_DATA *ch, CHAR_DATA *victim ) { // int victclan; // int chclan; /* safety checks -- GW */ if ( ch == NULL ) return FALSE; if ( victim == NULL ) return FALSE; /* Thx Josh! */ if ( who_fighting( ch ) == ch ) return FALSE; /* ARENA room checking */ if( in_arena( ch ) && in_arena(victim) ) return FALSE; /*CHAOS On? */ if( chaos == 1) return FALSE; /* In a Club Maze? */ if ( ch->in_room && ch->in_room->area && IS_SET( ch->in_room->area->flags, AFLAG_CLUB_HALL ) ) return FALSE; /* in Kombat? */ if( !IS_NPC(ch) && IS_SET(ch->pcdata->flags,PCFLAG_KOMBAT) && ( ch->in_room->vnum != 21440 )) return FALSE; /* in CTF? */ if( !IS_NPC(ch) && IS_SET(ch->pcdata->flagstwo,MOREPC_CTF) && ( ch->in_room->vnum != 21440 )) return FALSE; /* Dragon? */ if( !IS_NPC(ch) && !IS_NPC(victim) && victim->advclass == 14 ) return FALSE; // victclan = victim->pcdata->clan; // chclan = ch->pcdata->clan; // not no .. but FUCK NO! leave it alone. --GW // if ( victim->pcdata->clan != ch->pcdata->clan ) // return FALSE; if ( !victim->in_room ) char_to_room(victim, ch->in_room); if ( victim && victim->in_room ) { if ( IS_SET( victim->in_room->room_flags, ROOM_SAFE ) ) { set_char_color( AT_MAGIC, ch ); send_to_char( "A magical force prevents you from attacking.\n\r", ch ); return TRUE; } } if ( ch->level > LEVEL_IMMORTAL ) return FALSE; if( !IS_NPC( ch ) && !IS_NPC( victim ) && ch != victim && IS_SET( victim->in_room->area->flags, AFLAG_NOPKILL ) ) { 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 (!IS_NPC(ch)) { if( !IS_NPC(ch) && IS_SET(ch->pcdata->flags, PCFLAG_ASSASSIN)) return FALSE; if( !IS_NPC(ch) && IS_SET(victim->pcdata->flags, PCFLAG_ASSASSIN)) return FALSE; } if ( ch->level < 5 ) { 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 ( victim->level < 5 ) { set_char_color( AT_WHITE, ch ); send_to_char( "They are yet too young to die.\n\r", ch ); return TRUE; } if ( get_timer(victim, TIMER_PKILLED) > 0 ) { 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 ) { 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; level_ratio = URANGE( 1, ch->level / victim->level, 50); 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; } /* * Any character in the arena is ok to kill. */ if ( in_arena( ch ) ) return; /* * Chaos is on, kill away:) */ if ( chaos == 1 ) return; /* * In a club HALL or MAZE? */ if ( ch->in_room && ch->in_room->area && IS_SET( ch->in_room->area->flags, AFLAG_CLUB_HALL ) ) return; /* * Mortal Kombat */ if ( ( !IS_NPC(ch) && !IS_NPC(victim) ) && IS_SET( ch->pcdata->flags, PCFLAG_KOMBAT ) ) return; /* CTF */ if ( ( !IS_NPC(ch) && !IS_NPC(victim) ) && IS_SET( ch->pcdata->flagstwo, MOREPC_CTF ) ) return; /* * Dragons */ if ( !IS_NPC(ch) && !IS_NPC(victim) ) { if ( IS_ADVANCED(ch) && IS_ADVANCED(victim) ) { if ( ch->advclass == 14 && victim->advclass == 14 ) { if( ch->advlevel <= (victim->advlevel+10) ) return; } } } /* * So are killers and thieves. */ if ( IS_SET(victim->act, PLR_KILLER) || IS_SET(victim->pcdata->flags, PCFLAG_ASSASSIN) || IS_SET(victim->act, PLR_THIEF) ) { if ( !IS_NPC( ch ) ) { if ( ch->pcdata->clan ) ch->pcdata->clan->pkills++; ch->in_room->area->pkills++; } return; } if ( ( ch->level > (victim->level+10) ) || !IS_SET( victim->pcdata->flags, PCFLAG_DEADLY) || (IS_ADVANCED(ch) && !IS_ADVANCED(victim)) ) { 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 ); SET_BIT(ch->act, PLR_KILLER); if ( IS_SET( ch->act, PLR_ATTACKER) ) REMOVE_BIT(ch->act, PLR_ATTACKER); save_char_obj( ch ); 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 )) && ( ( ( IS_ADVANCED(ch) && IS_ADVANCED(victim)) && ( ch->advlevel <= (victim->advlevel+10) ) ) || ( ( !IS_ADVANCED(ch) && !IS_ADVANCED(victim) ) && ( ch->level <= (victim->advlevel+10) ) ) ) ) { /* not of same clan? Go ahead and kill!!! */ if (!IS_NPC(ch) && ( 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 ) ch->pcdata->clan->pkills++; ch->hit = ch->max_hit; ch->mana = ch->max_mana; ch->move = ch->max_move; if ( ch->pcdata ) ch->pcdata->condition[COND_BLOODTHIRST] = get_bloodthirst(ch); 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 ) victim->pcdata->clan->pdeaths++; 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 ); /* SET_BIT(victim->act, PLR_PK); */ return; } 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, 50 ); 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 ( ch == victim || ch->level >= LEVEL_IMMORTAL ) 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 ) victim->pcdata->clan->pdeaths++; victim->pcdata->pdeaths++; victim->in_room->area->pdeaths++; } if ( IS_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 ); SET_BIT(ch->act, PLR_KILLER); if ( IS_SET( ch->act, PLR_ATTACKER) ) REMOVE_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) || IS_SET(victim->act, PLR_KILLER) || IS_SET(victim->act, PLR_THIEF) ) return; /* deadly char check */ if ( !IS_NPC(ch) && !IS_NPC(victim) && CAN_PKILL( ch ) && CAN_PKILL( victim ) ) { 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 */ /*SET_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 || IS_SET(ch->act, PLR_ATTACKER) || IS_SET(ch->act, PLR_KILLER) ) return; SET_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 ); REMOVE_BIT( victim->mount->act, ACT_MOUNTED ); victim->mount = NULL; } victim->position = POS_DEAD; return; } if ( victim->hit <= -6 ) victim->position = POS_MORTAL; else if ( victim->hit <= -3 ) victim->position = POS_INCAP; else victim->position = POS_STUNNED; if (( victim->position > POS_STUNNED && ( IS_AFFECTED( victim, AFF_PARALYSIS) ) ) ) victim->position = POS_STUNNED; if ( victim->mount ) { act( AT_ACTION, "$n falls unconscious from $N.", victim, NULL, victim->mount, TO_ROOM ); REMOVE_BIT( victim->mount->act, ACT_MOUNTED ); victim->mount = NULL; } return; } /* * Start fights. */ void set_fighting( CHAR_DATA *ch, CHAR_DATA *victim ) { FIGHT_DATA *fight=NULL; 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; 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 ) { char bug_buf[MAX_STRING_LENGTH]; if ( !ch ) { bug( "who_fighting: null ch", 0 ); return NULL; } if ( !ch->fighting ) return NULL; if ( !ch->fighting->who ) { sprintf(bug_buf,"who_fighting: NULL ch->fighting->who (%s)", ch->name ); 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; ZONE_DATA *in_zone; if( !ch ) return; free_fight( ch ); update_pos( 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 ); } } if ( ch->in_room && ch->in_room->area && ch->in_room->area->zone ) in_zone=find_zone(ch->in_room->area->zone->number); else in_zone = find_zone(1); for ( fch = in_zone->first_mob; fch; fch = fch->next ) { if ( who_fighting( fch ) == ch ) { free_fight( fch ); update_pos( fch ); } } return; } void group_gain( CHAR_DATA *ch, CHAR_DATA *victim ) { char buf[MAX_STRING_LENGTH]; CHAR_DATA *gch; CHAR_DATA *lch; long 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 ( !ch ) return; if ( !victim) return; if ( IS_NPC(ch) || victim == ch || war == 1 || (IS_NPC(ch) && IS_SET(ch->pcdata->flags, PCFLAG_KOMBAT) ) ) return; members = 0; for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { if ( gch && ch && is_same_group( gch, ch ) ) members++; } if ( members == 0 ) { bug( "Group_gain: members.", members ); members = 1; } lch = ch->leader ? ch->leader : ch; for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room ) { /* OBJ_DATA *obj; OBJ_DATA *obj_next; -- used for zap .. no longer used --GW */ if ( !is_same_group( gch, ch ) ) continue; if ( gch->level - lch->level > 10 ) { send_to_char( "You are too high for this group.\n\r", gch ); continue; } if ( gch->level - lch->level < -10 ) { send_to_char( "You are too low for this group.\n\r", gch ); continue; } xp = (int) (xp_compute( gch, victim ) * 0.3 ) / members; if ( !gch->fighting ) xp /= 2; if ( IS_NPC(victim) && IS_SET(victim->acttwo, ACT_CREATE_LIFE_MOB)) xp = 0; gch->alignment = align_compute( gch, victim ); buf[0] = '\0'; sprintf( buf, "You receive %s experience points for the Kill.\n\r", num_comma(xp) ); send_to_char( buf, gch ); /* New 'statistical' display of EXP Gain per kill --GW */ if ( !IS_NPC(ch) ) { sprintf( buf, "You received a total of %s experiance points for Damage Inflicted.\n\r",num_comma(ch->pcdata->battle_xp)); send_to_char( buf, gch ); sprintf( buf, "Total Experiance Gained: %s\n\r",num_comma(ch->pcdata->battle_xp + xp)); send_to_char( buf, gch ); ch->pcdata->battle_xp = 0; } buf[0] = '\0'; gain_exp( gch, xp, TRUE ); /* this sucks .. remove --GW */ /* for ( obj = ch->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(ch) ) || ( IS_OBJ_STAT(obj, ITEM_ANTI_GOOD) && IS_GOOD(ch) ) || ( IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch) ) ) { act( AT_MAGIC, "You are zapped by $p.", ch, obj, NULL, TO_CHAR ); act( AT_MAGIC, "$n is zapped by $p.", ch, obj, NULL, TO_ROOM ); remove_obj ( ch, obj->wear_loc, TRUE ); oprog_zap_trigger(ch, obj); if ( char_died(ch) ) return; } } */ if (!IS_NPC(gch) && IS_SET(gch->pcdata->flags,PCFLAG_QUESTING ) && IS_NPC(victim)) { if (gch->pcdata->questmob == victim->pIndexData->vnum) { send_to_char("You have almost completed your quest!\n\r",gch); send_to_char( "Return to the questmaster before your time runs of time.\n\r",gch); ch->pcdata->questmob = -1; } } } return; } int align_compute( CHAR_DATA *gch, CHAR_DATA *victim ) { int align, newalign; align = gch->alignment - victim->alignment; if ( align > 500 ) newalign = UMIN( gch->alignment + (align-500)/4, 1000 ); else if ( align < -500 ) newalign = UMAX( gch->alignment + (align+500)/4, -1000 ); else newalign = gch->alignment - (int) (gch->alignment / 4); return newalign; } /* * 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) + 25, 13 )) / 5.9; if ( doubleexp == 1) xp = xp*2; 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; else /* reduce exp for killing the same mob repeatedly -Thoric */ if ( !IS_NPC( gch ) ) { int times = times_killed( gch, victim ); if ( times >= 20 ) xp = 0; else if ( times ) { xp = (xp * (20-times)) / 20; if ( times > 15 ) xp /= 3; else if ( times > 10 ) xp >>= 1; } } /* * 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->pcdata->played / gchlev; if ( xp_ratio > 20000 ) xp = (xp*5) >> 2; else if ( xp_ratio < 16000 ) xp = (xp*3) >> 2; else if ( xp_ratio < 10000 ) xp >>= 1; else if ( xp_ratio < 5000 ) xp >>= 2; else if ( xp_ratio < 3500 ) xp >>= 3; else if ( xp_ratio < 2000 ) xp >>= 4; } /* * Level based experience gain cap. Cannot get more experience for * a kill than the amount for your current experience level -Thoric */ /* NO Exp for Ghosts!!!!!! --GW */ if ( IS_AFFECTED( victim, AFF_GHOST ) ) xp = 0; return URANGE(0, xp, exp_level( gch, gchlev )); } /* * Revamped by Thoric to be more realistic */ void dam_message( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt ) { char buf1[256], buf2[256], buf3[256]; char *vs; char *vp; char *attack; char punct; sh_int dampc; struct skill_type *skill = NULL; bool gcflag = FALSE; bool gvflag = FALSE; extern sh_int dam_no_msg; if ( !ch || !victim ) return; vs = NULL; vp = NULL; attack = NULL; if ( dam_no_msg == 1 ) return; if ( ! dam ) dampc = 0; else dampc = URANGE( 0,( (dam * 1000) / victim->max_hit) + ( 50 - ((victim->hit * 50) / victim->max_hit) ),32000); if ( dampc < 0 ) { vs = "HELP"; vp = "HELPS"; } else if ( dam == 0 ) { vs = "miss"; vp = "misses";} else if ( dampc <= 5 ) { vs = "barely hit";vp = "barely hits";} else if ( dampc <= 10 ) { vs = "scratch"; vp = "scratches"; } else if ( dampc <= 20 ) { vs = "scrape"; vp = "scrapes"; } else if ( dampc <= 30 ) { vs = "graze"; vp = "grazes"; } else if ( dampc <= 40 ) { vs = "bruise"; vp = "bruises"; } else if ( dampc <= 50 ) { vs = "hit"; vp = "hits"; } else if ( dampc <= 60 ) { vs = "hurt"; vp = "hurts"; } else if ( dampc <= 75 ) { vs = "wound"; vp = "wounds"; } else if ( dampc <= 80 ) { vs = "lacerate"; vp = "lacerates"; } else if ( dampc <= 90 ) { vs = "harm"; vp = "harms"; } else if ( dampc <= 125 ) { vs = "ravage"; vp = "ravages"; } else if ( dampc <= 150 ) { vs = "demolish"; vp = "demolishes"; } else if ( dampc <= 200 ) { vs = "cripple"; vp = "cripples"; } else if ( dampc <= 300 ) { vs = "MANGLE";vp = "MANGLES"; } else if ( dampc <= 400 ) { vs = "DISMEMBER";vp = "DISMEMBERS"; } else if ( dampc <= 500 ) { vs = "== SLAUGHTER =="; vp = "== SLAUGHTERS =="; } else if ( dampc <= 600 ) { vs = "** LIQUEFY **"; vp = "** LIQUEFIES **"; } else if ( dampc <= 750 ) { vs = "|| DISINTEGRATE ||";vp = "|| DISINTEGRATES ||"; } else if ( dampc <= 990 ) { vs = "<== TERMINATE ==>"; vp = "<== TERMINATES ==>"; } else { vs = "do *** TERRIBLE THINGS *** to"; vp = "does *** TERRIBLE THINGS *** to"; } punct = '\0'; punct = (dampc <= 30) ? '.' : '!'; if ( dam < 0 ) dam = 0; 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 ) { buf1[0] = '\0'; buf2[0] = '\0'; buf3[0] = '\0'; sprintf( buf1, "&G$n &R%s&G $N%c&W", vp, punct ); sprintf( buf2, "&GYou &R%s&G $N%c&W", vs, punct ); sprintf( buf3, "&G$n &R%s&G you%c&W", vp, punct ); } 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 { dt = TYPE_HIT; attack = attack_table[0]; } buf1[0] = '\0'; buf3[0] = '\0'; buf2[0] = '\0'; sprintf( buf1, "&G$n's &Rpoisoned %s&G %s $N%c&W", attack, vp,punct); sprintf( buf2, "&GYour &Rpoisoned %s&G %s $N%c&W", attack, vp,punct); sprintf( buf3, "&G$n's &Rpoisoned %s&G %s you%c&W", attack, vp,punct); } 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' ) { act( AT_ACTION, skill->miss_room, ch, NULL, victim, TO_NOTVICT ); found = TRUE; } if ( found ) /* miss message already sent */ 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]) ) attack = attack_table[dt - TYPE_HIT]; else { dt = TYPE_HIT; attack = attack_table[0]; } buf1[0] = '\0'; buf2[0] = '\0'; buf3[0] = '\0'; sprintf( buf1, "&G$n's %s &R%s&G $N%c&W", attack, vp, punct ); sprintf( buf2, "&GYour %s &R%s&G $N%c&W", attack, vp, punct ); sprintf( buf3, "&G$n's %s &R%s&G you%c&W", attack, vp, punct ); } act( AT_PLAIN, buf1, ch, NULL, victim, TO_NOTVICT ); if (!gcflag) act( AT_PLAIN, buf2, ch, NULL, victim, TO_CHAR ); if (!gvflag) act( AT_PLAIN, buf3, ch, NULL, victim, TO_VICT ); return; } 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 ( ch == NULL ) return; if ( victim == NULL ) return; if ( !IS_NPC(victim) ) { if ( !IS_SET(victim->act, PLR_KILLER) && !IS_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 ) ) 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 ) { send_to_char( "You do the best you can!\n\r", ch ); return; } WAIT_STATE( ch, 1 * PULSE_VIOLENCE ); // check_killer( ch, victim ); // check_attacker( ch, victim ); if ( IS_IMMORTAL(ch) && IS_NPC(victim) && (get_trust(ch) < 56 ) ) { send_to_char("You should not be killing mobiles!\n\r",ch); return; } 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 ) ) 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 ) SET_BIT(ch->master->act, PLR_ATTACKER); } } if ( ch->position == POS_FIGHTING ) { send_to_char( "You do the best you can!\n\r", ch ); return; } if ( !IS_NPC( victim ) && IS_SET( ch->act, PLR_NICE ) ) { send_to_char( "You feel too nice to do that!\n\r", ch ); return; } /* if ( !IS_NPC( victim ) && IS_SET( victim->act, PLR_PK ) ) */ if ( !check_pk_ok(victim,ch)) return; 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 ); /* Replaced these with New check --GW */ // check_killer( ch, victim ); // check_illegal_pk( ch, victim ); // check_attacker( ch, victim ); multi_hit( ch, victim, TYPE_UNDEFINED ); return; } bool in_arena( CHAR_DATA *ch ) { if ( !ch || !ch->in_room ) return FALSE; if ( ch->in_room && ( ch->in_room->vnum < 30 || ch->in_room->vnum > 44 ) ) return FALSE; return TRUE; } bool check_illegal_pk( CHAR_DATA *ch, CHAR_DATA *victim ) { if (!IS_NPC (victim) && !IS_NPC(ch)) { if (ch == victim) return FALSE; if ( !IS_NPC(ch) && IS_ADVANCED(ch) && ch->advclass == 14 && !IS_NPC(victim) && IS_ADVANCED(victim) && victim->advclass == 14 && ch->advlevel <= (victim->advlevel+10) ) return FALSE; if ( IS_SET( victim->pcdata->flags, PCFLAG_DEADLY ) && IS_SET( ch->pcdata->flags, PCFLAG_DEADLY ) && (ch->level > (victim->level+10) ) ) return FALSE; if ( IS_SET( victim->pcdata->flags, PCFLAG_ASSASSIN ) || IS_SET( ch->pcdata->flags, PCFLAG_ASSASSIN) ) return FALSE; if ( in_arena( ch ) && in_arena(victim) ) return FALSE; if (chaos == 1) return FALSE; /* In a Club Maze? */ if ( ch->in_room && ch->in_room->area && IS_SET( ch->in_room->area->flags, AFLAG_CLUB_HALL ) ) return FALSE; if ( IS_SET(ch->pcdata->flags, PCFLAG_KOMBAT ) ) return FALSE; if ( IS_SET(ch->pcdata->flagstwo, MOREPC_CTF ) ) return FALSE; sprintf( log_buf, "%s performing illegal pkill on %s at %d", (IS_NPC(ch) ? ch->short_descr : ch->name), victim->name, ch->in_room->vnum ); log_string( log_buf ); to_channel( log_buf, CHANNEL_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=NULL; char buf[MAX_STRING_LENGTH]; sh_int door; EXIT_DATA *pexit; bool succeded; sh_int attempt; if ( !who_fighting( ch ) ) { if ( ch->position == POS_FIGHTING ) { 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 ( ch->move <= 0 ) { send_to_char( "You're too exhausted to flee from combat!\n\r", ch ); return; } /* No fleeing while stunned. - Narn */ /* Ya .. --GW */ if ( ch->position < POS_FIGHTING || ch->stun_rounds > 0 ) { send_to_char("your to stunned to do that!",ch); return; } succeded = FALSE; was_in = ch->in_room; for ( attempt = 0; attempt < 6; attempt++ ) { door = number_door( ); if ( ( pexit = get_exit(was_in, door) ) == NULL || ( IS_SET(pexit->exit_info, EX_CLOSED) && !IS_AFFECTED( ch, AFF_PASS_DOOR ) ) || ( !IS_NPC(ch) && IS_SET( ch->pcdata->flagstwo, MOREPC_ALIENS ) && IS_SET( pexit->to_room->room_flags, ROOM_DEATH ) ) || ( IS_NPC(ch) && IS_SET(pexit->to_room->room_flags, ROOM_NO_MOB) ) ) continue; if ( !can_flee_dir(ch, door) ) continue; succeded = TRUE; affect_strip ( ch, gsn_sneak ); xREMOVE_BIT( ch->affected_by, AFF_SNEAK ); if ( ch->mount && ch->mount->fighting ) stop_fighting( ch->mount, TRUE ); stop_fighting( ch, TRUE ); move_char( ch, get_exit( ch->in_room, door ), 0, FALSE ); now_in = ch->in_room; break; } if ( succeded == TRUE ) { char_from_room(ch); char_to_room(ch, was_in ); // ch->in_room = was_in; act( AT_FLEE, "$n flees head over heels!", ch, NULL, NULL, TO_ROOM ); char_from_room(ch); char_to_room(ch, now_in); // ch->in_room = now_in; act( AT_FLEE, "$n glances around for signs of pursuit.", ch, NULL, NULL, TO_ROOM ); if ( !IS_NPC(ch) && !in_arena(ch) && (war == 0)) { CHAR_DATA *wf = who_fighting(ch); int level_ratio=0; sprintf(buf, "You flee from combat!"); act( AT_FLEE, buf, ch, NULL, NULL, TO_CHAR ); if ( wf ) level_ratio = URANGE( 1, wf->level / ch->level, 50 ); if ( ch->pcdata->deity ) { 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; } if ( !IS_NPC(ch) && !in_arena(ch) && (war == 0 ) ) { sprintf(buf, "You attempt to flee from combat! And &RFAIL!&w\n\r"); send_to_char( buf, ch ); } else { send_to_char("You Failed to Flee!!\n\r",ch); } 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]; char buf[MAX_STRING_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, "kombat" ) ) { sprintf(buf,"THE SKIES TURN RED AS %s SCREAMS -- MORTAL KOMBAT!!!!! In the distance you hear %s scream in pain, while being burned alive!\n\r", capitalize(ch->name),QUICKLINK(victim->name)); echo_to_all(AT_CARNAGE,buf,ECHOTAR_ALL); } else if ( !str_cmp( arg2, "pinball") && get_trust(ch) >= 58) { sprintf(buf, " \a\aThe sound of pinball machines fills the Realms! %s slowly appears in the center of the Sky, directly above %s, holding a giant Pinball Machine! Suddenly, %s drops the Pinball Machine, you hear a SPLAT as it hits %s at Terminal Volocity!\n\r\n\r You hear the sound of a Free Game in the Distance!\n\r", QUICKLINK(ch->name), QUICKLINK(victim->name), QUICKLINK(ch->name), QUICKLINK(victim->name)); echo_to_all(AT_CARNAGE,buf,ECHOTAR_ALL); } else if ( !str_cmp( arg2, "flush") && get_trust(ch) >= LEVEL_GOD) { sprintf(buf, " \a\aYou hear the slow sound of rushing water, and suddenly see a bolt of entense energy slam into %s, paralyzing them. Then %s creates a giant toilet and drowns %s! You hear %s's helpless gurgles for help.\n\r You hear the faint sound of flushing in the distance...\n\r", QUICKLINK(victim->name), QUICKLINK(ch->name), QUICKLINK(victim->name), QUICKLINK(victim->name)); echo_to_all(AT_CARNAGE,buf,ECHOTAR_ALL); } else if ( !str_cmp( arg2, "squish") && get_trust(ch) >= LEVEL_GOD ) { sprintf(buf, " \a\aSuddenly there is a dull rumble throughout the land. A bright beam of intense light sent by %s encases %s. A giant hand then appears and plummets down to earth squashing %s with a thunderous boom which is hear all over the land . The hills echo with %s's screams of pain.\n\r The hand moves away revealing a smear of blood and flesh.\n\r", QUICKLINK(ch->name), QUICKLINK(victim->name), QUICKLINK(victim->name), QUICKLINK(victim->name)); echo_to_all(AT_CARNAGE,buf,ECHOTAR_ALL); } else if ( !str_cmp( arg2, "soul" ) && get_trust(ch) >= LEVEL_GOD ) { sprintf(buf," \a\aThe earth shakes violently! Suddenly %s raises from the ground up to the center of the sky! In a large ball of flame demons seem to shoot from all directions as %s points at %s and screams -- BANISH!! %s is ripped limb from limb! then suddenly goes limp as the head demon punches its claw through thier chest and rips out thier very SOUL!\n\r %s's lifeless body hits the ground with a bone shattering thud....\n\r", QUICKLINK(victim->name), QUICKLINK(ch->name), QUICKLINK(victim->name), QUICKLINK(victim->name), QUICKLINK(victim->name)); echo_to_all(AT_BLOOD,buf,ECHOTAR_ALL); } else if ( !str_cmp( arg2, "pounce" ) && get_trust(ch) >= LEVEL_FATE ) { 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" ) && get_trust(ch) >= LEVEL_FATE ) { 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 { 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 ); } victim->died_in_room = NULL; victim->died_in_room = victim->in_room; set_cur_char(victim); raw_kill( ch, victim ); return; } /* * Hit one guy with a projectile. * Handles use of missile weapons (wield = missile weapon) * or thrown items/weapons */ ch_ret projectile_hit( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *wield, OBJ_DATA *projectile, sh_int dist ) { int victim_ac; int thac0; int thac0_00; int thac0_32; int plusris; int dam; int diceroll; int prof_bonus; int prof_gsn = -1; int proj_bonus; int dt; ch_ret retcode; if ( !projectile ) return rNONE; if ( projectile->item_type == ITEM_PROJECTILE || projectile->item_type == ITEM_WEAPON ) { dt = TYPE_HIT + projectile->value[3]; proj_bonus = number_range(projectile->value[1], projectile->value[2]); } else { dt = TYPE_UNDEFINED; proj_bonus = number_range(1, URANGE(2, get_obj_weight(projectile), 100) ); } /* * Can't beat a dead char! */ if ( victim->position == POS_DEAD || char_died(victim) ) { extract_obj(projectile); return rVICT_DIED; } if ( wield ) prof_bonus = weapon_prof_bonus_check( ch, wield, &prof_gsn ); else prof_bonus = 0; if ( dt == TYPE_UNDEFINED ) { dt = TYPE_HIT; if ( wield && wield->item_type == ITEM_MISSILE_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) + (dist*2); victim_ac = UMAX( -30, (int) (GET_AC(victim) / 20) ); /* if you can't see what's coming... */ if ( !can_see_obj( victim, projectile) ) victim_ac += 1; if ( !can_see( ch, victim ) ) victim_ac -= 4; /* Weapon proficiency bonus */ victim_ac += prof_bonus; /* * The moment of excitement! */ while ( ( diceroll = number_bits( 5 ) ) >= 20 ) ; if ( diceroll == 0 || ( diceroll != 19 && diceroll < thac0 - victim_ac ) ) { /* Miss. */ if ( prof_gsn != -1 ) learn_from_failure( ch, prof_gsn ); /* Do something with the projectile */ if ( number_percent() < 50 ) extract_obj(projectile); else { if ( projectile->in_obj ) obj_from_obj(projectile); if ( projectile->carried_by ) obj_from_char(projectile); obj_to_room(projectile, victim->in_room); } damage( ch, victim, 0, dt ); tail_chain( ); return rNONE; } /* * Hit. * Calc damage. */ if ( !wield ) /* dice formula fixed by Thoric */ dam = proj_bonus; else dam = number_range(wield->value[1], wield->value[2]) + (proj_bonus / 10); /* * 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;*/ 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 ( dam <= 0 ) dam = 1; plusris = 0; if ( IS_OBJ_STAT(projectile, 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 */ if ( wield ) plusris = obj_hitroll( wield ); /* 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 ) { if ( number_percent() < 50 ) extract_obj(projectile); else { if ( projectile->in_obj ) obj_from_obj(projectile); if ( projectile->carried_by ) obj_from_char(projectile); obj_to_room(projectile, victim->in_room); } return rNONE; } } dam = 0; } if ( (retcode = damage( ch, victim, dam, dt )) != rNONE ) { extract_obj(projectile); return retcode; } if ( char_died(ch) ) { extract_obj(projectile); return rCHAR_DIED; } if ( char_died(victim) ) { extract_obj(projectile); return rVICT_DIED; } retcode = rNONE; if ( dam == 0 ) { if ( number_percent() < 50 ) extract_obj(projectile); else { if ( projectile->in_obj ) obj_from_obj(projectile); if ( projectile->carried_by ) obj_from_char(projectile); obj_to_room(projectile, victim->in_room); } return retcode; } /* weapon spells -Thoric */ if ( wield && !IS_SET(victim->immune, RIS_MAGIC) && !IS_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)/3, ch, victim ); if ( retcode != rNONE || char_died(ch) || char_died(victim) ) { extract_obj(projectile); 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)/3, ch, victim ); if ( retcode != rNONE || char_died(ch) || char_died(victim) ) { extract_obj(projectile); return retcode; } } extract_obj(projectile); tail_chain( ); return retcode; } /* Can we flee that way? --GW */ bool can_flee_dir( CHAR_DATA *ch, int door ) { CHAR_DATA *mob, *next_mob=NULL; bool blocked, mob_found; blocked=FALSE; mob_found=FALSE; /* Find a Mob with a block flag */ for( mob = ch->in_room->first_person; mob; mob=next_mob) { next_mob=mob->next_in_room; if ( IS_NPC(mob) && (IS_SET(mob->acttwo, ACT2_BNORTH) || IS_SET(mob->acttwo, ACT2_BSOUTH) || IS_SET(mob->acttwo, ACT2_BEAST) || IS_SET(mob->acttwo, ACT2_BWEST) || IS_SET(mob->acttwo, ACT2_BUP) || IS_SET(mob->acttwo, ACT2_BDOWN))) { mob_found=TRUE; break; } } /* No mob? Kick us.. */ if ( !mob_found ) return TRUE; /* Does it block the Dir im trying to flee!!?! */ switch(door) { case DIR_NORTH: if ( IS_SET(mob->acttwo, ACT2_BNORTH ) ) { blocked=TRUE; break; } else break; case DIR_SOUTH: if ( IS_SET(mob->acttwo, ACT2_BSOUTH ) ) { blocked=TRUE; break; } else break; case DIR_EAST: if ( IS_SET(mob->acttwo, ACT2_BEAST ) ) { blocked=TRUE; break; } else break; case DIR_WEST: if ( IS_SET(mob->acttwo, ACT2_BWEST ) ) { blocked=TRUE; break; } else break; case DIR_UP: if ( IS_SET(mob->acttwo, ACT2_BUP ) ) { blocked=TRUE; break; } else break; case DIR_DOWN: if ( IS_SET(mob->acttwo, ACT2_BDOWN ) ) { blocked=TRUE; break; } else break; } /* Yep - tell them to fuck off.. */ if (blocked) { char buf[MSL]; buf[0]='\0'; sprintf(buf,"HAHA! You can't flee from me, %s!",capitalize(ch->name)); do_say(mob,buf); return FALSE; } /* Guess not.. run like a child! hehe */ return TRUE; }