#include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "merc.h" #include "magic.h" #include "cabal.h" #include "recycle.h" #include "interp.h" #include "misc.h" #define MARK(room) (SET_BIT( (room)->room_flags, ROOM_MARK) ) #define UNMARK(room) (REMOVE_BIT( (room)->room_flags, ROOM_MARK) ) #define IS_MARKED(room) (IS_SET( (room)->room_flags, ROOM_MARK) ) extern char *target_name; extern char *flag_string args ( ( const struct flag_type *flag_table, int bits ) ); DECLARE_SPEC_FUN( spec_breath_any ); DECLARE_SPEC_FUN( spec_breath_acid ); DECLARE_SPEC_FUN( spec_breath_fire ); DECLARE_SPEC_FUN( spec_breath_frost ); DECLARE_SPEC_FUN( spec_breath_gas ); DECLARE_SPEC_FUN( spec_breath_lightning ); DECLARE_SPEC_FUN( spec_breath_death ); DECLARE_SPEC_FUN( spec_cast_adept ); DECLARE_SPEC_FUN( spec_cast_cleric ); DECLARE_SPEC_FUN( spec_cast_mage ); DECLARE_SPEC_FUN( spec_cast_undead ); DECLARE_SPEC_FUN( spec_executioner ); DECLARE_SPEC_FUN( spec_special_guard ); DECLARE_SPEC_FUN( spec_fido ); DECLARE_SPEC_FUN( spec_guard ); DECLARE_SPEC_FUN( spec_gate_guard ); DECLARE_SPEC_FUN( spec_janitor ); DECLARE_SPEC_FUN( spec_poison ); DECLARE_SPEC_FUN( spec_thief ); DECLARE_SPEC_FUN( spec_nasty ); DECLARE_SPEC_FUN( spec_cast_cabal_healer ); DECLARE_SPEC_FUN( spec_keeper_stay ); DECLARE_SPEC_FUN( spec_keeper_move ); DECLARE_SPEC_FUN( spec_virgil_guard ); DECLARE_SPEC_FUN( spec_shadowdemon ); DECLARE_SPEC_FUN( spec_mob_call ); DECLARE_SPEC_FUN( spec_magic_eye ); DECLARE_SPEC_FUN( spec_displacer_beast ); DECLARE_SPEC_FUN( spec_hunt_wanted ); DECLARE_SPEC_FUN( spec_vanguard ); DECLARE_SPEC_FUN( spec_servant_hide ); DECLARE_SPEC_FUN( spec_justice_sentinel ); DECLARE_SPEC_FUN( spec_hunter_nonallied ); DECLARE_SPEC_FUN( spec_hunter_nonallied_warp ); DECLARE_SPEC_FUN( spec_hunter_nonallied_cwarp ); DECLARE_SPEC_FUN( spec_hunter_allied ); DECLARE_SPEC_FUN( spec_hunter_allied_warp ); DECLARE_SPEC_FUN( spec_hunter_allied_cwarp ); DECLARE_SPEC_FUN( spec_terminator ); DECLARE_SPEC_FUN( spec_knight_seer ); DECLARE_SPEC_FUN( spec_nexus_nemesis ); DECLARE_SPEC_FUN( spec_path_walk ); DECLARE_SPEC_FUN( spec_raider_actions ); DECLARE_SPEC_FUN( spec_awakenlife_actions ); const struct spec_type spec_table[] = { { "spec_breath_any", spec_breath_any }, { "spec_breath_acid", spec_breath_acid }, { "spec_breath_fire", spec_breath_fire }, { "spec_breath_frost", spec_breath_frost }, { "spec_breath_gas", spec_breath_gas }, { "spec_breath_lightning", spec_breath_lightning }, { "spec_breath_death", spec_breath_death }, { "spec_cast_adept", spec_cast_adept }, { "spec_cast_cleric", spec_cast_cleric }, { "spec_cast_mage", spec_cast_mage }, { "spec_cast_undead", spec_cast_undead }, { "spec_executioner", spec_executioner }, { "spec_special_guard", spec_special_guard }, { "spec_fido", spec_fido }, { "spec_guard", spec_guard }, { "spec_gate_guard", spec_gate_guard }, { "spec_janitor", spec_janitor }, { "spec_poison", spec_poison }, { "spec_thief", spec_thief }, { "spec_nasty", spec_nasty }, { "spec_cast_cabal_healer", spec_cast_cabal_healer }, { "spec_keeper_stay", spec_keeper_stay }, { "spec_keeper_move", spec_keeper_move }, { "spec_virgil_guard", spec_virgil_guard }, { "spec_shadowdemon", spec_shadowdemon }, { "spec_mob_call", spec_mob_call }, { "spec_displacer_beast", spec_displacer_beast }, { "spec_hunt_wanted", spec_hunt_wanted }, { "spec_vanguard", spec_vanguard }, { "spec_servant_hide", spec_servant_hide }, { "spec_justice_sentinel", spec_justice_sentinel }, { "spec_hunter_nonallied", spec_hunter_nonallied }, { "spec_hunter_nonallied_warp", spec_hunter_nonallied_warp }, { "spec_hunter_nonallied_cwarp", spec_hunter_nonallied_cwarp }, { "spec_hunter_allied", spec_hunter_allied }, { "spec_hunter_allied_warp", spec_hunter_allied_warp }, { "spec_hunter_allied_cwarp", spec_hunter_allied_cwarp }, { "spec_terminator", spec_terminator }, { "spec_knight_seer", spec_knight_seer }, { "spec_nexus_nemesis", spec_nexus_nemesis }, { "spec_magic_eye", spec_magic_eye }, { "spec_raider_actions", spec_raider_actions }, { "spec_awakenlife_actions", spec_awakenlife_actions }, { NULL, NULL } }; SPEC_FUN *spec_lookup( const char *name ) { int i; for ( i = 0; spec_table[i].name != NULL; i++) if (LOWER(name[0]) == LOWER(spec_table[i].name[0]) && !str_prefix( name,spec_table[i].name)) return spec_table[i].function; return 0; } char *spec_name( SPEC_FUN *function) { int i; for (i = 0; spec_table[i].function != NULL; i++) if (function == spec_table[i].function) return spec_table[i].name; return NULL; } bool spec_nasty( CHAR_DATA *ch ) { CHAR_DATA *victim, *v_next; long gold; if (!IS_AWAKE(ch)) return FALSE; if (ch->position != POS_FIGHTING) { for ( victim = ch->in_room->people; victim != NULL; victim = v_next) { v_next = victim->next_in_room; if (!IS_NPC(victim) && (victim->level > ch->level) && (victim->level < ch->level + 10)) { do_backstab(ch,victim->name); if (ch->position != POS_FIGHTING) do_murder(ch,victim->name); return TRUE; } } return FALSE; } if ( (victim = ch->fighting) == NULL) return FALSE; switch ( number_bits(2) ) { case 0: act( "$n rips apart your coin purse, spilling your gold!", ch, NULL, victim, TO_VICT); act( "You slash apart $N's coin purse and gather $S gold.", ch, NULL, victim, TO_CHAR); act( "$N's coin purse is ripped apart!", ch, NULL, victim, TO_NOTVICT); gold = victim->gold / 10; victim->gold -= gold; ch->gold += gold; return TRUE; case 1: do_flee( ch, ""); return TRUE; default: return FALSE; } } bool dragon( CHAR_DATA *ch, char *spell_name ) { CHAR_DATA *victim, *v_next; int sn; if ( ch->position != POS_FIGHTING ) return FALSE; for ( victim = ch->in_room->people; victim != NULL; victim = v_next ) { v_next = victim->next_in_room; if ( victim->fighting == ch && number_bits( 3 ) == 0 ) break; } if ( victim == NULL ) return FALSE; if ( ( sn = skill_lookup( spell_name ) ) < 0 ) return FALSE; (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim, TARGET_CHAR); return TRUE; } bool spec_breath_any( CHAR_DATA *ch ) { if ( ch->position != POS_FIGHTING ) return FALSE; switch ( number_bits( 3 ) ) { case 0: return spec_breath_fire ( ch ); case 1: case 2: return spec_breath_lightning ( ch ); case 3: return spec_breath_gas ( ch ); case 4: return spec_breath_acid ( ch ); case 5: return spec_breath_death ( ch ); case 6: case 7: return spec_breath_frost ( ch ); } return FALSE; } bool spec_breath_acid( CHAR_DATA *ch ) { return dragon( ch, "acid breath" ); } bool spec_breath_death( CHAR_DATA *ch ) { return dragon( ch, "death breath" ); } bool spec_breath_fire( CHAR_DATA *ch ) { return dragon( ch, "fire breath" ); } bool spec_breath_frost( CHAR_DATA *ch ) { return dragon( ch, "frost breath" ); } bool spec_breath_gas( CHAR_DATA *ch ) { int sn; if ( ch->position != POS_FIGHTING ) return FALSE; if ( ( sn = skill_lookup( "gas breath" ) ) < 0 ) return FALSE; if (number_bits( 3 ) != 0 ) return FALSE; (*skill_table[sn].spell_fun) ( sn, ch->level, ch, NULL,TARGET_CHAR); return TRUE; } bool spec_breath_lightning( CHAR_DATA *ch ) { return dragon( ch, "lightning breath" ); } bool spec_cast_adept( CHAR_DATA *ch ) { CHAR_DATA *victim, *v_next; if ( !IS_AWAKE(ch) ) return FALSE; for ( victim = ch->in_room->people; victim != NULL; victim = v_next ) { v_next = victim->next_in_room; if ( victim != ch && can_see( ch, victim ) && number_bits( 1 ) == 0 && !IS_NPC(victim) && victim->level < 11) break; } if ( victim == NULL ) return FALSE; switch ( number_bits( 4 ) ) { case 0: act( "$n utters the word 'abrazak'.", ch, NULL, NULL, TO_ROOM ); spell_armor( skill_lookup( "armor" ), victim->level,ch,victim,TARGET_CHAR); return TRUE; case 1: act( "$n utters the word 'fido'.", ch, NULL, NULL, TO_ROOM ); spell_bless( skill_lookup( "bless"),ch->level/3,ch,victim,TARGET_CHAR); return TRUE; case 2: act("$n utters the words 'judicandus noselacri'.",ch,NULL,NULL,TO_ROOM); spell_cure_blindness( skill_lookup( "cure blindness" ), ch->level, ch, victim,TARGET_CHAR); return TRUE; case 3: act("$n utters the words 'judicandus dies'.", ch,NULL, NULL, TO_ROOM ); spell_cure_light( skill_lookup( "cure light" ), victim->level,ch,victim,TARGET_CHAR); return TRUE; case 4: act( "$n utters the words 'judicandus sausabru'.",ch,NULL,NULL,TO_ROOM); spell_cure_poison( skill_lookup( "cure poison" ), ch->level, ch, victim,TARGET_CHAR); return TRUE; case 5: act("$n utters the word 'candusima'.", ch, NULL, NULL, TO_ROOM ); spell_refresh(skill_lookup("refresh"),ch->level/2,ch,victim,TARGET_CHAR); return TRUE; case 6: act("$n utters the words 'judicandus eugzagz'.",ch,NULL,NULL,TO_ROOM); spell_cure_disease(skill_lookup("cure disease"), ch->level,ch,victim,TARGET_CHAR); } return FALSE; } bool spec_cast_cabal_healer( CHAR_DATA *ch ) { CHAR_DATA *victim, *v_next; if ( !IS_AWAKE(ch) ) return FALSE; for ( victim = ch->in_room->people; victim != NULL; victim = v_next ) { v_next = victim->next_in_room; if ( victim != ch && can_see( ch, victim ) && number_bits( 1 ) == 0 && !IS_NPC(victim) && _is_cabal(victim->pCabal, ch->pCabal )) break; } if ( victim == NULL ) return FALSE; switch ( number_bits( 3 ) ) { case 0: if ( !is_affected(victim, 4) ) return FALSE; if ( ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC)) send_to_char( "The Medic smears ointment over your eyes.\n\r",victim); else act("$n utters the words 'judicandus noselacri'.",ch,NULL,NULL,TO_ROOM); spell_cure_blindness( skill_lookup( "cure blindness" ),ch->level, ch, victim,TARGET_CHAR); return TRUE; case 1: if ( !is_affected(victim, skill_lookup( "poison" )) ) return FALSE; if ( ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC)) send_to_char( "The Medic drains the venom from your veins.\n\r", victim); else act( "$n utters the words 'judicandus sausabru'.",ch,NULL,NULL,TO_ROOM); spell_cure_poison( skill_lookup( "cure poison" ), ch->level, ch, victim,TARGET_CHAR); return TRUE; case 2: if ( ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC)) return FALSE; act("$n utters the word 'candusima'.", ch, NULL, NULL, TO_ROOM); spell_refresh(skill_lookup("refresh"),victim->level,ch,victim,TARGET_CHAR); return TRUE; case 3: if ( !is_affected(victim, skill_lookup( "plague" )) ) return FALSE; if ( ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC)) send_to_char( "The Medic reduces your fever with some mixed herbs.\n\r", victim); else act("$n utters the words 'judicandus eugzagz'.",ch,NULL,NULL,TO_ROOM); spell_cure_disease(skill_lookup("cure disease"), ch->level,ch,victim,TARGET_CHAR); return TRUE; case 4: if ( ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC)) return FALSE; if ( is_affected(victim, skill_lookup("armor")) ) return FALSE; act( "$n utters the word 'abrazak'.", ch, NULL, NULL, TO_ROOM ); spell_armor( skill_lookup( "armor" ),victim->level,ch,victim,TARGET_CHAR); return TRUE; case 5: if ( ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC)) return FALSE; act("$n utters the words 'judicandus dies'.", ch,NULL, NULL, TO_ROOM ); spell_cure_light( skill_lookup( "cure light" ), victim->level, ch,victim,TARGET_CHAR); return TRUE; case 6: if ( ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC)) return FALSE; if ( is_affected(victim, skill_lookup("bless")) ) return FALSE; act( "$n utters the word 'fido'.", ch, NULL, NULL, TO_ROOM ); spell_bless( skill_lookup( "bless" ),victim->level,ch,victim,TARGET_CHAR); return TRUE; } return FALSE; } bool spec_cast_cleric( CHAR_DATA *ch ) { const int TARGETS = 6; CHAR_DATA *victim, *v_next; CHAR_DATA* targets[TARGETS]; char *spell = NULL; int sn, max_tar = 0; if ( ch->position != POS_FIGHTING || is_affected(ch,gsn_blasphemy)) return FALSE; for ( victim = ch->in_room->people; victim != NULL; victim = v_next ){ v_next = victim->next_in_room; if ( victim->fighting != ch) continue; targets[max_tar++] = victim; if (max_tar >= TARGETS) break; } if ( max_tar < 1 ) return FALSE; else victim = targets[number_range(0, max_tar - 1)]; for ( ;; ){ int min_level; switch ( number_range(0, 12) ){ case 0: min_level = 0; spell = "faerie fire"; break; case 1: min_level = 2; spell = "cause critical"; break; case 2: min_level = 5; spell = "curse"; break; case 3: min_level = 10; spell = "blindness"; break; case 4: min_level = 15; spell = "poison"; break; case 5: min_level = 20; spell = "plague"; break; case 6: min_level = 25; spell = "flamestrike"; break; case 7: min_level = 30; spell = "harm"; break; case 8: min_level = 35; spell = "dispel magic"; break; case 9: min_level = 40; spell = "frenzy"; break; case 10: min_level = 45; if (number_percent() < 50) spell = "spell turning"; else spell = "steel wall"; break; default: min_level = 50; if (IS_GOOD(ch)) spell = "ray of truth"; else if (IS_EVIL(ch)) spell = "path of deceit"; else spell = "harm"; break; } if ( ( sn = skill_lookup( spell ) ) < 0 ) continue; if ( ch->level >= min_level ) break; } if (skill_table[sn].target == TAR_CHAR_DEFENSIVE || skill_table[sn].target == TAR_CHAR_SELF){ act("$n narrows $s eyes.",ch,NULL,NULL,TO_ROOM); (*skill_table[sn].spell_fun) ( sn, ch->level, ch, ch,TARGET_CHAR); } else{ act("$n closes $s eyes momentarily.",ch,NULL,NULL,TO_ROOM); (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR); } return TRUE; } bool spec_cast_mage( CHAR_DATA *ch ) { const int TARGETS = 6; CHAR_DATA *victim, *v_next; CHAR_DATA* targets[TARGETS]; char *spell = NULL; int sn, max_tar = 0; if ( ch->position != POS_FIGHTING || IS_AFFECTED2(ch, AFF_SILENCE)) return FALSE; for ( victim = ch->in_room->people; victim != NULL; victim = v_next ){ v_next = victim->next_in_room; if ( victim->fighting != ch) continue; targets[max_tar++] = victim; if (max_tar >= TARGETS) break; } if ( max_tar < 1 ) return FALSE; else victim = targets[number_range(0, max_tar - 1)]; for ( ;; ) { int min_level; switch ( number_range(0, 12)) { case 0: min_level = 0; spell = "magic missile"; break; case 1: min_level = 2; spell = "faerie fire"; break; case 2: min_level = 5; spell = "dispel magic"; break; case 3: min_level = 10; spell = "blindness"; break; case 4: min_level = 15; spell = "weaken"; break; case 5: min_level = 20; spell = "fireball"; break; case 6: min_level = 25; spell = "silence"; break; case 7: min_level = 30; spell = "flame arrow"; break; case 8: min_level = 35; spell = "fire shield"; break; case 9: min_level = 40; spell = "acid blast"; break; case 10: min_level = 45; spell = "mind disruption"; break; default: min_level = 50; spell = "psionic blast"; break; } if ( ch->level >= min_level ) break; } if ( ( sn = skill_lookup( spell ) ) < 0 ) return FALSE; say_spell( ch, sn ); if (skill_table[sn].target == TAR_CHAR_DEFENSIVE || skill_table[sn].target == TAR_CHAR_SELF) (*skill_table[sn].spell_fun) ( sn, ch->level, ch, ch,TARGET_CHAR); else (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR); return TRUE; } bool spec_cast_undead( CHAR_DATA *ch ) { CHAR_DATA *victim, *v_next; char *spell; int sn; if ( ch->position != POS_FIGHTING || IS_AFFECTED2(ch, AFF_SILENCE)) return FALSE; for ( victim = ch->in_room->people; victim != NULL; victim = v_next ) { v_next = victim->next_in_room; if ( victim->fighting == ch && number_bits( 2 ) == 0 ) break; } if ( victim == NULL ) return FALSE; for ( ;; ) { int min_level; switch ( number_bits( 4 ) ) { case 0: min_level = 0; spell = "blindness"; break; case 1: min_level = 4; spell = "curse"; break; case 2: min_level = 8; spell = "poison"; break; case 3: min_level = 12; spell = "plague"; break; case 4: min_level = 16; spell = "weaken"; break; case 5: min_level = 20; spell = "enfeeblement"; break; case 6: min_level = 24; spell = "blasphemy"; break; case 7: min_level = 28; spell = "silence"; break; case 8: min_level = 32; spell = "energy drain"; break; case 9: min_level = 36; spell = "chorus of anguish"; break; case 10: min_level = 40; spell = "dispel magic"; break; default: min_level = 45; spell = "blood gout"; break; } if ( ch->level >= min_level ) break; } if ( ( sn = skill_lookup( spell ) ) < 0 ) return FALSE; (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR); return TRUE; } /* returns a criminal in the room */ CHAR_DATA* get_criminal( ROOM_INDEX_DATA* room, CHAR_DATA* ch ){ CHAR_DATA* victim, *v_next; for ( victim = room->people; victim != NULL; victim = v_next ){ v_next = victim->next_in_room; //look for raiders if (IS_NPC(victim) && IS_SET(victim->act, ACT_RAIDER) && IS_SET(ch->in_room->area->area_flags, AREA_CITY)){ break; } else if (is_ghost(victim, 600)) continue; else if (IS_NPC(ch) && ch->pIndexData->vnum != MOB_VNUM_SPECIAL_GUARD && ch->pIndexData->vnum != MOB_VNUM_HOUND && is_affected(victim, gsn_bribe)) continue; else if (!IS_NPC(victim) && IS_WANTED(victim) && can_see(ch,victim)) break; } if ( victim == NULL ) return NULL; else return victim; } bool spec_special_guard( CHAR_DATA *ch ){ char buf[MSL]; CHAR_DATA *victim = NULL; CHAR_DATA* mob = ch; bool fInCombat = FALSE; if ( !IS_AWAKE(ch) || !IS_NPC(ch) || ch->master == NULL || is_affected(ch, gsn_ecstacy) ) return FALSE; if (ch->pIndexData->vnum == MOB_VNUM_SPECIAL_GUARD && is_affected(ch->master, gsn_raise_morale)){ SET_BIT(ch->off_flags, OFF_BASH); } else REMOVE_BIT(ch->off_flags, OFF_BASH); if (ch->fighting != NULL){ fInCombat = TRUE; if (ch->pIndexData->vnum == MOB_VNUM_HOUND && is_affected(ch->master, gsn_raise_morale)){ if (!is_affected(ch->fighting, gsn_dirt)){ ch->trust = 6969; do_dirt( ch, "" ); if (ch->fighting == NULL) return FALSE; ch->trust = ch->level; } } victim = ch->fighting; } if ( !fInCombat && (victim = get_criminal( ch->in_room, ch )) == NULL ) return FALSE; else{ MOB_INDEX_DATA* pMobIndex; int mod = 100; int hp_level = 0; int level = !IS_NPC(victim) ? ch->master->level : 55; int i = 0; int hitroll = 0; int damroll = 0; bool fWarrior = FALSE; bool fHalfWar = FALSE; bool fRouge = FALSE; bool fMage = FALSE; /* put lower limit on level */ level = UMAX(21, level); if (!fInCombat){ if (ch->pIndexData->vnum == MOB_VNUM_SPECIAL_GUARD){ sprintf( buf, "%s is a criminal! Justice shall prevail!", PERS2(victim)); REMOVE_BIT(ch->comm,COMM_NOYELL); j_yell( ch, buf ); SET_BIT(ch->comm,COMM_NOYELL); } else if (ch->pIndexData->vnum == MOB_VNUM_HOUND){ check_social(ch, "growl", victim->name); } } /* Used to morph a mob to current victims level and power */ /* Assumes that the original stats for the mob were set for */ /* an opponent of level 50 vs a rouge */ /* decide what type of character this is */ if (IS_NPC(victim)) fWarrior = TRUE; else if (victim->class == class_lookup("monk")) fHalfWar = TRUE; else if (victim->class == class_lookup("vampire")) fWarrior = TRUE; else{ int attack = 1; int defense = 0; /* Offense */ if (victim->pcdata->learned[gsn_second_attack]) attack++; if (victim->pcdata->learned[gsn_third_attack]) attack++; if (victim->pcdata->learned[gsn_fourth_attack]) attack++; if (victim->pcdata->learned[gsn_blades]) attack += 2; if (victim->pcdata->learned[gsn_dan_blade]) attack++; /* defense */ if (victim->pcdata->learned[gsn_parry]) defense++; if (victim->pcdata->learned[gsn_dual_parry]) defense++; if (victim->pcdata->learned[gsn_dodge]) defense++; if (victim->pcdata->learned[gsn_shield_block] || victim->pcdata->learned[gsn_2hands]) defense++; if (victim->pcdata->learned[gsn_terra_shield]) defense++; if (victim->pcdata->learned[gsn_blades]) defense++; if (victim->pcdata->learned[skill_lookup("blur")]) defense++; /* select which type this is */ if (attack > 3 || defense > 3) fWarrior = TRUE; else if (attack > 2 || defense > 1){ if (victim->pcdata->learned[gsn_hide] || victim->pcdata->learned[gsn_camouflage]) fRouge = TRUE; else fHalfWar = TRUE; } else fMage = TRUE; } /* adjust things base on general archtype */ /* most of this is based on special guards plus few modifications */ if ( ( pMobIndex = get_mob_index( mob->pIndexData->vnum)) == NULL){ bug("spec_special_guard: mob index not found.", mob->pIndexData->vnum); return FALSE; } /* common */ REMOVE_BIT(ch->affected_by, AFF_HASTE ); /* class specific */ if (fWarrior){ level += 3; hitroll += hitroll / 2; damroll += level/6; if (IS_SET(pMobIndex->off_flags, OFF_FAST)) SET_BIT(ch->off_flags, OFF_FAST); if (IS_SET(pMobIndex->off_flags, OFF_EXTRA_ATTACK)) SET_BIT(ch->off_flags, OFF_EXTRA_ATTACK); } else if (fHalfWar){ level += 2; hitroll += hitroll / 3; damroll += level/6; if (IS_SET(pMobIndex->off_flags, OFF_FAST)) SET_BIT(ch->off_flags, OFF_FAST); if (IS_SET(pMobIndex->off_flags, OFF_EXTRA_ATTACK)) SET_BIT(ch->off_flags, OFF_EXTRA_ATTACK); } else if (fRouge){ level += 1; hitroll -= 0; damroll -= level/8; if (IS_SET(pMobIndex->off_flags, OFF_FAST)) SET_BIT(ch->off_flags, OFF_FAST); REMOVE_BIT(ch->off_flags, OFF_EXTRA_ATTACK); } else if (fMage){ level += 2; hitroll -= hitroll / 3; damroll -= level/10; REMOVE_BIT(ch->off_flags, OFF_FAST); REMOVE_BIT(ch->off_flags, OFF_EXTRA_ATTACK); } else{ if (IS_SET(pMobIndex->off_flags, OFF_FAST)) SET_BIT(ch->off_flags, OFF_FAST); if (IS_SET(pMobIndex->off_flags, OFF_EXTRA_ATTACK)) SET_BIT(ch->off_flags, OFF_EXTRA_ATTACK); } if ( !fInCombat && level != mob->level){ act("$n seems to change in size and shape to match yours.", mob, NULL, victim, TO_VICT); act("$n seems to change in size and shape to match $N's.", mob, NULL, victim, TO_NOTVICT); } mod = 100 * level / mob->level; mob->level = level; if (!fInCombat){ mob->size = victim->size; for (i=0;i < MAX_STATS; i++) mob->perm_stat[i] = get_max_train(victim, i); for (i=0; i < 4; i++) mob->armor[i] = pMobIndex->ac[i] * mod / 100; hp_level = 100 * mob->hit / mob->max_hit; mob->max_hit = UMAX(1, mod * mob->max_hit / 100); mob->hit = UMAX(1, hp_level * mob->max_hit / 100); } damroll = pMobIndex->damage[DICE_BONUS] * mod / 100; hitroll = pMobIndex->hitroll * mod / 100; mob->hitroll = hitroll; mob->damroll = damroll; mob->damage[DICE_NUMBER] = UMAX(1, mod * pMobIndex->damage[DICE_NUMBER] / 100); if (!fInCombat && ch->master->fighting != victim){ multi_hit( ch, victim, TYPE_UNDEFINED ); } return TRUE; } return FALSE; } bool spec_fido( CHAR_DATA *ch ) { OBJ_DATA *corpse, *c_next, *obj, *obj_next; if ( !IS_AWAKE(ch) ) return FALSE; for ( corpse = ch->in_room->contents; corpse != NULL; corpse = c_next ) { c_next = corpse->next_content; if ( corpse->item_type != ITEM_CORPSE_NPC ) continue; act( "$n savagely devours a corpse.", ch, NULL, NULL, TO_ROOM ); for ( obj = corpse->contains; obj; obj = obj_next ) { obj_next = obj->next_content; obj_from_obj( obj ); obj_to_room( obj, ch->in_room ); if (is_affected_obj(obj, gsn_levitate)) act( "$p slowly rises and stays suspended in mid-air.", ch, obj, NULL, TO_ALL ); } extract_obj( corpse ); return TRUE; } return FALSE; } /* assists players against other NPCS */ bool spec_guard( CHAR_DATA *ch ){ char buf[MSL]; CHAR_DATA *victim, *v_next, *ech = NULL; int max_evil = 300; if ( !IS_AWAKE(ch) || ch->fighting != NULL ) return FALSE; for ( victim = ch->in_room->people; victim != NULL; victim = v_next ){ v_next = victim->next_in_room; //look for raiders if (IS_NPC(victim) && IS_SET(victim->act, ACT_RAIDER) && IS_SET(ch->in_room->area->area_flags, AREA_CITY)){ sprintf( buf, "For glory of %s!!", ch->in_room->area->name); do_yell( ch, buf ); multi_hit( ch, victim, TYPE_UNDEFINED ); return TRUE; } if (is_ghost(victim, 600)) continue; if ( victim->fighting != NULL && victim->fighting != ch && victim->alignment < max_evil ){ max_evil = victim->alignment; ech = victim; } } if (ech == NULL && victim == NULL) return FALSE; else if (ech == NULL) ech = victim; if ( ech != NULL ) { sprintf( buf, "PROTECT THE INNOCENT!! BANZAI!!"); do_say( ch, buf ); multi_hit( ch, ech, TYPE_UNDEFINED ); return TRUE; } return FALSE; } /* attacks criminals but does not announce to justice cabals */ bool spec_executioner( CHAR_DATA *ch ){ char buf[MSL]; CHAR_DATA* victim; if (!ch->in_room) return FALSE; else if ( !IS_AREA(ch->in_room->area, AREA_LAWFUL) || !IS_AWAKE(ch) || ch->fighting != NULL ) return FALSE; else SET_BIT(ch->act2, ACT_LAWFUL ); if ( (victim = get_criminal( ch->in_room, ch )) == NULL) return FALSE; if (IS_NPC(victim) && IS_SET(victim->act, ACT_RAIDER)) sprintf( buf, "For glory of %s!", ch->in_room->area->name); else sprintf( buf, "You will pay for your crimes %s!", victim->name); REMOVE_BIT(ch->comm,COMM_NOYELL); j_yell( ch, buf ); SET_BIT(ch->comm,COMM_NOYELL); sprintf( buf, "%s is at %s of %s!", PERS2(victim), victim->in_room->name, victim->in_room->area->name); cabal_echo_flag( CABAL_HEARGUARD, buf ); /* check of simulacra for justices */ if (is_affected(victim, gsn_doppelganger)){ char buf[MIL]; sprintf( buf, "Warning! Someone seems to be masquerading as %s!", PERS2(victim)); cabal_echo_flag( CABAL_JUSTICE | CABAL_HEARGUARD, buf ); } multi_hit( ch, victim, TYPE_UNDEFINED ); return TRUE; } /* attacks criminals AND announces on justice channels */ bool spec_gate_guard( CHAR_DATA *ch ){ char buf[MSL]; CHAR_DATA *victim; if ( !ch->in_room || !IS_AREA(ch->in_room->area, AREA_LAWFUL) || !IS_AWAKE(ch) || ch->fighting != NULL ) return FALSE; else SET_BIT(ch->act2, ACT_LAWFUL ); if ( (victim = get_criminal( ch->in_room, ch )) == NULL) return FALSE; if (IS_NPC(victim) && IS_SET(victim->act, ACT_RAIDER)) sprintf( buf, "For glory of %s!", ch->in_room->area->name); else{ sprintf( buf, "%s is a criminal! Justice shall prevail!", PERS2(victim)); sprintf( buf, "%s is at %s of %s!", PERS2(victim), victim->in_room->name, victim->in_room->area->name); cabal_echo_flag( CABAL_HEARGUARD, buf ); } REMOVE_BIT(ch->comm,COMM_NOYELL); j_yell( ch, buf ); SET_BIT(ch->comm,COMM_NOYELL); /* check of simulacra for justices */ if (is_affected(victim, gsn_doppelganger)){ char buf[MIL]; sprintf( buf, "Warning! Someone seems to be masquerading as %s!", PERS2(victim)); cabal_echo_flag( CABAL_JUSTICE | CABAL_HEARGUARD, buf ); } multi_hit( ch, victim, TYPE_UNDEFINED ); return TRUE; } bool spec_janitor( CHAR_DATA *ch ) { OBJ_DATA *trash, *trash_next; if ( !IS_AWAKE(ch) ) return FALSE; for ( trash = ch->in_room->contents; trash != NULL; trash = trash_next ) { trash_next = trash->next_content; if ( !IS_SET( trash->wear_flags, ITEM_TAKE ) ) continue; if ( trash->item_type == ITEM_DRINK_CON || trash->item_type == ITEM_TRASH || trash->cost < 10 ) { act( "$n picks up some trash.", ch, NULL, NULL, TO_ROOM ); obj_from_room( trash ); obj_to_char( trash, ch ); return TRUE; } } return FALSE; } bool spec_poison( CHAR_DATA *ch ) { CHAR_DATA *victim; if ( ch->position != POS_FIGHTING || ( victim = ch->fighting ) == NULL || number_percent( ) > 20 + 2 * (ch->level-victim->level) ) return FALSE; act( "You bite $N!", ch, NULL, victim, TO_CHAR ); act( "$n bites $N!", ch, NULL, victim, TO_NOTVICT ); act( "$n bites you!", ch, NULL, victim, TO_VICT ); spell_poison( gsn_poison, ch->level, ch, victim,TARGET_CHAR); return TRUE; } bool spec_thief( CHAR_DATA *ch ) { CHAR_DATA *victim, *v_next; long gold; if ( ch->position != POS_STANDING ) return FALSE; for ( victim = ch->in_room->people; victim != NULL; victim = v_next ) { v_next = victim->next_in_room; if ( IS_NPC(victim) || victim->level >= LEVEL_IMMORTAL || number_bits( 5 ) != 0 || !can_see(ch,victim)) continue; if ( IS_AWAKE(victim) && number_range( 0, ch->level ) == 0 ) { act( "You discover $n's hands in your wallet!", ch, NULL, victim, TO_VICT ); act( "$N discovers $n's hands in $S wallet!", ch, NULL, victim, TO_NOTVICT ); return TRUE; } else { gold = victim->gold * UMIN(number_range(1,20),ch->level) / 100; gold = UMIN(gold, ch->level * ch->level * 20 ); ch->gold += gold; victim->gold -= gold; return TRUE; } } return FALSE; } /* does the cabal services * COMMENTS: * The services are divided into four categories: * * 1) SERV_HEAL : uncurse, heal, cure, restore * 2) SERV_ITEM : identify, bless, bind, reinforce, locate * 3) SERV_TRAIN: advance, train * 4) SERV_SKILL: teach-skill (non cabal) * 5) SERV_SPELL: teach-spell (non cabal) * 6) SERV_CABAL: teach-cabal (cabal skill/spell) * 7) SERV_OTHER: life insurance * * In order for the mob to offer particular group, its first mana die must have the SERV_XXX bit set. * For values of the bits look below, and OR the bit values setting the first mana die to the resultant * sum. */ #define SERV_HEAL 1 #define SERV_ITEM 2 #define SERV_TRAIN 4 #define SERV_SKILL 8 #define SERV_SPELL 16 #define SERV_CABAL 32 #define SERV_OTHER 64 void do_service(CHAR_DATA* ch, CHAR_DATA* mob, char *argument){ OBJ_DATA* obj = NULL; SPELL_FUN *spell = NULL; char arg1[MIL]; char arg2[MIL]; char t_name[MIL]; char* act = NULL; const int unit = 100; //Used for scaling costs, 100 = normal int cost = 0; //Cost subtracted in the end (CPS) int sn = 0; bool fFound = FALSE; int flag = mob->pIndexData->mana[DICE_NUMBER]; argument = one_argument(argument, arg1); sprintf( t_name, "%s", argument ); one_argument(argument, arg2); if (arg1[0] == '\0'){ if (flag == 0 ){ act("$N says '`#I offer no services. (SERVICE BITS NOT SET)``'", ch, NULL, mob, TO_CHAR); return; } act("$N says '`#I offer following services.``'", ch, NULL, mob, TO_CHAR); sendf(ch, "service <type> <target>:\n\r"); if (IS_SET( flag, SERV_HEAL)){ sendf( ch, " uncurse <none> : Remove a curse from body or item.\n\r"\ " heal <none> : Heal body\n\r"\ " cure <none> : Cure ilness\n\r"\ " restore <none> : Restore stamina\n\r\n\r"); } if (IS_SET( flag, SERV_ITEM)){ sendf( ch, " identify <item> : Identify object\n\r"\ " bless <item> : Bless an item\n\r"\ " bind <item> : Bind an owner to item\n\r"\ " reinforce <item> : Make an item resistant to destruction\n\r"\ " locate <item> : Locate a item in the lands.\n\r\n\r"); } if (IS_SET( flag, SERV_TRAIN)){ sendf( ch, " advance <number> : Provide experience\n\r"\ " train <stat> : Provide physical and mental training\n\r\n\r"); } if (IS_SET( flag, SERV_SKILL)|| IS_SET( flag, SERV_SPELL) || IS_SET( flag, SERV_CABAL) ){ if (IS_SET(flag, SERV_SKILL)) sendf( ch, " teach <skill> : Teach and lecture on use of skills\n\r"); if (IS_SET(flag, SERV_SPELL)) sendf( ch, " teach <spell> : Teach and lecture on use of spells\n\r"); if (IS_SET(flag, SERV_CABAL)) sendf( ch, " teach <cabal> : Teach and lecture on use of cabal powers\n\r"); send_to_char("\n\r", ch ); } if (IS_SET( flag, SERV_OTHER)){ sendf( ch, " life-insurance : Secure your items in case of demise\n\r"); } send_to_char("\n\rUse: \"service <type> cost\" for detalied costs.\n\r", ch); return; } /* SERV_HEAL */ if (IS_SET( flag, SERV_HEAL)){ if (!str_prefix(arg1, "uncurse")){ fFound = TRUE; cost = unit * 60 / 100; if (arg2[0] != '\0' && !str_cmp("cost", arg2)){ sendf(ch, "Removes a curse upon a character and his items for %d %s%s per attempt.\n\r", cost, ch->pCabal->currency, (cost == 1? "" : "s") ); return; } spell = spell_remove_curse; sn = skill_lookup("remove curse"); act = "$N sprinkles some dust and mutters a few incanations."; if (IS_AFFECTED(ch, AFF_CURSE)){ sprintf( t_name, "%s", ch->name); } else if (IS_NULLSTR(argument)){ act("$N says '`#You do not seem cursed. Which of your items shall I work on?``'", ch, NULL, mob, TO_CHAR); return; } sprintf( t_name, "%s %s", ch->name, argument ); } else if (!str_prefix(arg1, "heal")){ fFound = TRUE; cost = unit * 25 / 100; if (arg2[0] != '\0' && !str_cmp("cost", arg2)){ sendf(ch, "Quickly restores health for %d %s%s per application.\n\r", cost, ch->pCabal->currency, (cost == 1? "" : "s") ); return; } spell = spell_heal; sn = skill_lookup("heal"); act = "$N mixes an ointment."; } else if (!str_prefix(arg1, "cure")){ fFound = TRUE; cost = unit * 28/ 100; if (arg2[0] != '\0' && !str_cmp("cost", arg2)){ sendf(ch, "Removes many bodly harms at %d %s%s per attempt.\n\r", cost, ch->pCabal->currency, (cost == 1? "" : "s") ); return; } spell = spell_cell_adjustment; sn = skill_lookup("cell adjustment"); act = "$N lights a few smelly candles and chants softly."; } else if (!str_prefix(arg1, "restore")){ fFound = TRUE; cost = unit * 2 / 100; if (!str_cmp("cost", arg2)){ sendf(ch, "Restores stamina at %d %s%s per application.\n\r", cost, ch->pCabal->currency, (cost == 1? "" : "s") ); return; } spell = spell_refresh; sn = skill_lookup("refresh"); act = "$N mutters few words as $s eyes shimmer with power."; } } /* SERV_ITEM */ if (IS_SET( flag, SERV_ITEM)){ if (!str_prefix(arg1, "identify")){ fFound = TRUE; if (arg2[0] == '\0' || !str_cmp("cost", arg2)){ sendf(ch, "Identifies item, cost equal to level of item.\n\r"); return; } if ( (obj = get_obj_list(ch, arg2, ch->carrying)) == NULL){ do_say(mob, "You carry no such item."); return; } cost = obj->level; if (GET_CP(ch) < cost) { act("$N says 'You do not have enough coin for my services.'", ch,NULL,mob,TO_CHAR); return; } spell = spell_identify; sn = skill_lookup("identify"); spell_identify(sn, mob->level, ch, obj, TARGET_OBJ); /* set sn to 0 so the regular spell function doesnt run. */ sn = 0; spell = NULL; act = "$N places $s hands on $s temples and concentrates."; } else if (!str_prefix(arg1, "bless")){ AFFECT_DATA af; const int dur = -1; fFound = TRUE; if (arg2[0] == '\0' || !str_cmp("cost", arg2)){ sendf(ch, "Places a permament blessing on an item.\n\r"\ "Cost is 5 times the level of an item.\n\r"); return; } if ( (obj = get_obj_list(ch, arg2, ch->carrying)) == NULL){ do_say(mob, "You carry no such item."); return; } if (IS_OBJ_STAT(obj,ITEM_BLESS) || IS_OBJ_STAT(obj,ITEM_EVIL)){ do_say(mob, "It is already blessed."); return; } cost = 5 * obj->level; if (GET_CP(ch) < cost) { act("$N says 'You do not have enough coin for my services.'", ch,NULL,mob,TO_CHAR); return; } spell = spell_null; sn = 0; act = "$N begins to mutter incanations around $p."; af.type = skill_lookup("bless arms"); af.level = mob->level; af.duration = dur; af.where = TO_OBJECT; af.bitvector = IS_EVIL(ch) ? ITEM_EVIL : ITEM_BLESS; af.modifier = 0; af.location = 0; affect_to_obj(obj, &af); } else if (!str_prefix(arg1, "bind")){ AFFECT_DATA* paf; const int dur = 480; fFound = TRUE; if (arg2[0] == '\0' || !str_cmp("cost", arg2)){ sendf(ch, "Binds the item to you, as its owner for %d days.\n\r"\ "Cost is 2 times the level of item.\n\r", dur / 24); return; } if ( (obj = get_obj_list(ch, arg2, ch->carrying)) == NULL){ do_say(mob, "You carry no such item."); return; } if (IS_SET(obj->wear_flags,ITEM_HAS_OWNER)){ do_say(mob, "That item is already bound to someone."); return; } cost = 2 * obj->level; if (GET_CP(ch) < cost) { act("$N says 'You do not have enough coin for my services.'", ch,NULL,mob,TO_CHAR); return; } spell = spell_null; sn = 0; act = "Hammer and chisel in hand, $N quickly engraves something into $p."; set_owner(ch, obj, ch->pcdata->deity); /* set owner sets duration to -1, we wont it to dur */ if ( (paf = affect_find(obj->affected, gen_has_owner)) != NULL) paf->duration = dur; } else if (!str_prefix(arg1, "reinforce")){ fFound = TRUE; if (arg2[0] == '\0' || !str_cmp("cost", arg2)){ sendf(ch, "Makes the object more resistant to destruction.\n\r"\ "Cost is 12 times the level of item.\n\r"); return; } if ( (obj = get_obj_list(ch, arg2, ch->carrying)) == NULL){ do_say(mob, "You carry no such item."); return; } if (IS_OBJ_STAT(obj, ITEM_BURN_PROOF)){ do_say(mob, "It is already reinforced."); return; } cost = 12 * obj->level; if (GET_CP(ch) < cost) { act("$N says 'You do not have enough coin for my services.'", ch,NULL,mob,TO_CHAR); return; } spell = spell_null; sn = 0; act = "$N sprinkles some strange reagents onto $p."; SET_BIT(obj->extra_flags, ITEM_BURN_PROOF); } else if (!str_prefix(arg1, "locate")){ fFound = TRUE; cost = 60; if (arg2[0] == '\0' || !str_cmp("cost", arg2)){ sendf(ch, "Locates an item, %d %s%s per attempt.\n\r", cost, ch->pCabal->currency, (cost == 1? "" : "s") ); return; } if (GET_CP(ch) < cost) { act("$N says 'You do not have enough coin for my services.'", ch,NULL,mob,TO_CHAR); return; } spell = spell_locate_object; sn = skill_lookup("locate object"); target_name = argument; spell_locate_object(sn, mob->level, ch, obj, TARGET_OBJ); /* set sn to 0 so the regular spell function doesnt run. */ sn = 0; spell = NULL; act = "$N places $s hands on $s temples and concentrates."; } } /* SERV_TRAIN */ if (IS_SET( flag, SERV_TRAIN)){ if (!str_prefix(arg1, "advance")){ int gain = 0; cost = atoi(arg2); gain = 33 * cost; fFound = TRUE; if (cost < 1){ sendf(ch, "Grants 33 exp points per %s.\n\r", ch->pCabal->currency); return; } else if (GET_CP(ch) < cost) { act("$N says 'You do not have enough coin for my services.'", ch,NULL,mob,TO_CHAR); return; } else if (ch->level >= 45 ){ act("$N says 'I'm sorry but there is nothing else I can teach you.'", ch,NULL,mob,TO_CHAR); return; } act = "$N begins to lecture on far away places and worldly knowledge."; sendf( ch, "You receive %d experience points.\n\r", gain ); gain_exp(ch, gain); sn = 0; spell = NULL; } else if (!str_prefix(arg1, "train")){ char* pOutput; char buf[MIL]; int stat = 0; cost = 500; fFound = TRUE; if (arg2[0] == '\0' || !str_cmp("cost", arg2)){ sendf(ch, "Raises a single statistic, %d %s%s per attempt.\n\r", cost, ch->pCabal->currency, (cost == 1? "" : "s") ); return; } if (GET_CP(ch) < cost) { act("$N says 'You do not have enough coin for my services.'", ch,NULL,mob,TO_CHAR); return; } /* check if can raise stats and raise them */ if ( !str_cmp( arg2, "str" ) ) { stat = STAT_STR; pOutput = "strength"; } else if ( !str_cmp( arg2, "int" ) ) { stat = STAT_INT; pOutput = "intelligence"; } else if ( !str_cmp( arg2, "wis" ) ) { stat = STAT_WIS; pOutput = "wisdom"; } else if ( !str_cmp( arg2, "dex" ) ) { stat = STAT_DEX; pOutput = "dexterity"; } else if ( !str_cmp( arg2, "con" ) ) { stat = STAT_CON; pOutput = "constitution"; } else { strcpy( buf, "You can train:" ); if ( ch->perm_stat[STAT_STR] < get_max_train(ch,STAT_STR)) strcat( buf, " str" ); if ( ch->perm_stat[STAT_INT] < get_max_train(ch,STAT_INT)) strcat( buf, " int" ); if ( ch->perm_stat[STAT_WIS] < get_max_train(ch,STAT_WIS)) strcat( buf, " wis" ); if ( ch->perm_stat[STAT_DEX] < get_max_train(ch,STAT_DEX)) strcat( buf, " dex" ); if ( ch->perm_stat[STAT_CON] < get_max_train(ch,STAT_CON)) strcat( buf, " con" ); if ( buf[strlen(buf)-1] != ':' ) { strcat( buf, ".\n\r" ); send_to_char( buf, ch ); } else send_to_char( "You have nothing left to train", ch); return; } if ( ch->perm_stat[stat] >= get_max_train(ch,stat) ) { act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR ); return; } ch->perm_stat[stat]++; act( "Your $T increases!", ch, NULL, pOutput, TO_CHAR ); act( "$n's $T increases!", ch, NULL, pOutput, TO_ROOM ); /* end training */ act = "$N beams with pride."; sn = 0; spell = NULL; } } /* SERV_SKILL/SPELL/CABAL */ if (IS_SET( flag, SERV_SKILL) || IS_SET( flag, SERV_SPELL) || IS_SET( flag, SERV_CABAL)){ if (!str_prefix(arg1, "teach")){ SKILL_DATA *nsk; int skill = 0; int sn = 0; cost = 100; fFound = TRUE; if (arg2[0] == '\0' || !str_cmp("cost", arg2)){ sendf(ch, "Raises a single skill by 1%%. %d %s%s per session.\n\r", cost, ch->pCabal->currency, (cost == 1? "" : "s")); if (IS_SET(flag, SERV_CABAL)){ sendf(ch, "1/2 price for %s knowledge, 8 %ss for %s knowledge below average level.\n\r", ch->pCabal->who_name, ch->pCabal->currency, ch->pCabal->who_name ); } return; } /* check for skill */ if ( (sn = skill_lookup(argument)) < 1){ act("$N says 'I know nothing of such ability.'", ch,NULL,mob,TO_CHAR); return; } else if ( (skill = get_skill(ch, sn)) == 0){ act("$N says 'You do not seem to be proficient with that ability.'", ch,NULL,mob,TO_CHAR); return; } else if (skill >= 95){ act("$N says 'Your skill in that area far exceeds mine I'm afraid.'", ch,NULL,mob,TO_CHAR); return; } /* check for cabal powers */ /* check for cabal skills */ if (get_cskill( ch->pCabal, sn )){ if (!IS_SET(flag, SERV_CABAL)){ act("$N says 'I know nothing of such exotic abilities I'm afraid.'", ch,NULL,mob,TO_CHAR); return; } if (skill < 75) cost = 8; else cost = 1 * cost / 2; } else{ /* check for skills */ if (skill_table[sn].spell_fun == spell_null && !IS_SET(flag, SERV_SKILL)){ act("$N says 'I know nothing of non magical matters I'm afraid.'", ch,NULL,mob,TO_CHAR); return; } else if (skill_table[sn].spell_fun != spell_null && !IS_SET(flag, SERV_SPELL)){ act("$N says 'I know nothing of magical matters I'm afraid.'", ch,NULL,mob,TO_CHAR); return; } if (skill < 2){ act("$N says 'You must first learn the basics of $t.'", ch, skill_table[sn].name ,mob,TO_CHAR); return; } } if (GET_CP(ch) < cost) { act("$N says 'You do not have enough coin for my services.'", ch,NULL,mob,TO_CHAR); return; } /* check for granted skills first */ if ( (nsk = nskill_find(ch->pcdata->newskills,sn)) != NULL) nsk->learned ++; else ch->pcdata->learned[sn] ++; act = "$N begins to drone on about various skills."; sendf( ch, "Your understanding of %s has increased.\n\r", skill_table[sn].name ); sn = 0; spell = NULL; } } if (IS_SET( flag, SERV_OTHER)){ if (!str_prefix(arg1, "life-insurance")){ AFFECT_DATA af; const int dur = 72; cost = 5 * ch->level; fFound = TRUE; if (!str_cmp("cost", arg2)){ sendf(ch, "Makes the transition to death more peaceful for %d days.\n\r"\ "Cost is %d now and once more upon event of death.\n\r", dur / 24, cost); return; } if (GET_CP(ch) < cost) { act("$N says 'You do not have enough coin for my services.'", ch,NULL,mob,TO_CHAR); return; } if (is_affected (ch, gsn_life_insurance)) { act("$N says 'You are already insured with us child, your death is assured... I mean insured!'", ch, NULL, mob, TO_CHAR); return; } spell = spell_null; sn = 0; act = "$N quickly scribes your name on a scroll, and hands it to his assistant."; af.where = TO_AFFECTS; af.type = skill_lookup("life-insurance"); af.level = ch->level; af.duration = dur; af.location = APPLY_NONE; af.modifier = cost; af.bitvector = 0; affect_to_char(ch,&af); } } if (!fFound) { do_say(mob, "Type \"services\" for list of services I offer."); return; } if (GET_CP(ch) < cost) { act("$N says 'You do not have enough coin for my services.'", ch,NULL,mob,TO_CHAR); return; } WAIT_STATE(ch,PULSE_VIOLENCE*4); CP_GAIN(ch, -cost, TRUE); if (act){ act("$n performs $s service.", mob, NULL, ch, TO_VICT); act(act , ch, obj, mob,TO_ALL); } if (spell != NULL && sn > 0){ target_name = t_name; spell(sn, mob->level, mob, ch, TARGET_CHAR); } } void do_heal(CHAR_DATA *ch, char *argument) { CHAR_DATA *mob; char buf[MSL], arg[MIL], t_name[MIL]; int cost, sn; SPELL_FUN *spell; char *words; for ( mob = ch->in_room->people; mob; mob = mob->next_in_room ) if ( IS_NPC(mob) && IS_SET(mob->act, ACT_IS_HEALER) ) break; if ( mob == NULL ) { send_to_char( "You can't do that here.\n\r", ch ); return; } if ( mob->pCabal ){ if( _is_cabal(ch->pCabal, mob->pCabal)){ do_service(ch, mob, argument); } else{ sprintf( buf, "You must be a member of %s to receive services here %s.", mob->pCabal->name, PERS2( ch )); do_say( mob, buf ); } return; } if (is_exiled(ch, mob->in_room->area->vnum )){ char buf[MIL]; sprintf( buf, "No one in %s will deal with you %s!", mob->in_room->area->name, PERS2(ch)); do_say( mob, buf ); return; } if ( ch->pCabal && IS_CABAL(ch->pCabal, CABAL_NOMAGIC)) { send_to_char("You are not allowed to use magic!\n\r", ch); return; } argument = one_argument(argument,arg); sprintf(t_name, "%s", argument ); if (arg[0] == '\0') { act("$N says 'I offer the following spells:'",ch,NULL,mob,TO_CHAR); send_to_char(" light: cure light wounds 1000 + level*10 gold\n\r",ch); send_to_char(" serious: cure serious wounds 1600 + level*20 gold\n\r",ch); send_to_char(" critic: cure critical wounds 2500 + level*50 gold\n\r",ch); send_to_char(" heal: healing spell 5000 + level*100 gold\n\r",ch); send_to_char(" blind: cure blindness 2000 + level*20 gold\n\r",ch); send_to_char(" disease: cure disease 1500 + level*20 gold\n\r",ch); send_to_char(" poison: cure poison 2500 + level*20 gold\n\r",ch); send_to_char(" uncurse: person or item 5000 + level*20 gold\n\r",ch); send_to_char(" refresh: restore movement 500 + level*10 gold\n\r",ch); send_to_char(" mana: restore mana 1000 + level*20 gold\n\r",ch); send_to_char(" Type heal <type> to be healed.\n\r",ch); return; } if (!str_prefix(arg,"light")) { spell = spell_cure_light; sn = skill_lookup("cure light"); words = "judicandus dies"; cost = 1000 + (ch->level*10); } else if (!str_prefix(arg,"serious")) { spell = spell_cure_serious; sn = skill_lookup("cure serious"); words = "judicandus gzfuajg"; cost = 1600 + (ch->level*20); } else if (!str_prefix(arg,"critical")) { spell = spell_cure_critical; sn = skill_lookup("cure critical"); words = "judicandus qfuhuqar"; cost = 2500 + (ch->level*50); } else if (!str_prefix(arg,"heal")) { spell = spell_heal; sn = skill_lookup("heal"); words = "pzar"; cost = 5000 + (ch->level*100); } else if (!str_prefix(arg,"blindness")) { spell = spell_cure_blindness; sn = skill_lookup("cure blindness"); words = "judicandus noselacri"; cost = 2000 + (ch->level*20); } else if (!str_prefix(arg,"disease")) { spell = spell_cure_disease; sn = skill_lookup("cure disease"); words = "judicandus eugzagz"; cost = 1500 + (ch->level*20); } else if (!str_prefix(arg,"poison")) { spell = spell_cure_poison; sn = skill_lookup("cure poison"); words = "judicandus sausabru"; cost = 2500 + (ch->level*20); } else if (!str_prefix(arg,"uncurse") || !str_prefix(arg,"curse")) { spell = spell_remove_curse; sn = skill_lookup("remove curse"); words = "candussido judifgz"; cost = 5000 + (ch->level*20); if (IS_AFFECTED(ch, AFF_CURSE)){ sprintf( t_name, "%s", ch->name); } else if (IS_NULLSTR(argument)){ act("$N says '`#Which of your items shall I remove the curse from?``'", ch, NULL, mob, TO_CHAR); return; } else sprintf( t_name, "%s %s", ch->name, argument ); } else if (!str_prefix(arg,"mana") || !str_prefix(arg,"energize")) { spell = NULL; sn = -1; words = "energizer"; cost = 1000 + (ch->level*20); } else if (!str_prefix(arg,"refresh") || !str_prefix(arg,"moves")) { spell = spell_refresh; sn = skill_lookup("refresh"); words = "candusima"; cost = 500 + (ch->level*20); } else { act("$N says 'Type 'heal' for a list of spells.'", ch,NULL,mob,TO_CHAR); return; } if (cost > ch->gold) { act("$N says 'You do not have enough gold for my services.'", ch,NULL,mob,TO_CHAR); return; } WAIT_STATE(ch,PULSE_VIOLENCE*4); ch->gold -= cost; mob->gold += cost; act("$n utters the words '$T'.",mob,NULL,words,TO_ROOM); if (spell == NULL) { ch->mana += dice(2,8) + mob->level / 4; ch->mana = UMIN(ch->mana,ch->max_mana); send_to_char("A warm glow passes through you.\n\r",ch); return; } if (sn == -1) return; target_name = t_name; spell(sn,mob->level,mob,ch,TARGET_CHAR); } void acid_effect(void *vo, int level, int dam, int target) { if (target == TARGET_CHAR) { CHAR_DATA *victim = (CHAR_DATA *) vo; if (!IS_AFFECTED(victim, AFF_FAERIE_FIRE) && !saves_spell(3 * level /4 + dam / 15, victim, DAM_ACID,SPELL_AFFLICTIVE)) { AFFECT_DATA af; act("$n starts glowing strangely.",victim,NULL,NULL,TO_ROOM); act("The toxin has made you glow.",victim,NULL,NULL,TO_CHAR); af.where = TO_AFFECTS; af.type = skill_lookup("faerie fire"); af.level = level; af.duration = 2; af.location = APPLY_AC; af.modifier = 25; af.bitvector = AFF_FAERIE_FIRE; affect_to_char( victim, &af ); } if (!IS_NPC(victim)) gain_condition(victim,COND_HUNGER,dam/20); } } void cold_effect(void *vo, int level, int dam, int target) { if (target == TARGET_CHAR) { CHAR_DATA *victim = (CHAR_DATA *) vo; if (!saves_spell(3 * level /4 + dam / 15, victim, DAM_COLD,SPELL_AFFLICTIVE)) { AFFECT_DATA af, *paf; const int gsn_ct = skill_lookup("chill touch"); act("$n turns blue and shivers.",victim,NULL,NULL,TO_ROOM); act("A chill sinks deep into your bones.",victim,NULL,NULL,TO_CHAR); if ( (paf = affect_find(victim->affected, gsn_ct)) != NULL && paf->modifier < -3) return; af.where = TO_AFFECTS; af.type = gsn_ct; af.level = level; af.duration = 0; af.location = APPLY_STR; af.modifier = -1; af.bitvector = 0; affect_join( victim, &af ); } if (!IS_NPC(victim)) gain_condition(victim,COND_HUNGER,dam/20); } } void wound_effect(CHAR_DATA* ch, CHAR_DATA* victim, int level, int dam){ if (victim == NULL || saves_spell(level, victim, DAM_SLASH, SPELL_AFFLICTIVE)) return; if ( !is_affected(victim, gen_move_dam)){ AFFECT_DATA af, *paf; af.type = gen_move_dam; af.level = level; af.duration = number_range(0, 1); af.where = TO_AFFECTS; af.bitvector = 0; af.location = APPLY_NONE; af.modifier = 0; paf = affect_to_char(victim, &af); if (!IS_NPC(ch)){ string_to_affect(paf, ch->name); } act("$n's blow wounds $N gravely.", ch, NULL, victim, TO_NOTVICT); act("Your blow wounds $N gravely.", ch, NULL, victim, TO_CHAR); act("$n's blow wounds you gravely.", ch, NULL, victim, TO_VICT); } } void fire_effect(void *vo, int level, int dam, int target) { if (target == TARGET_CHAR){ CHAR_DATA *victim = (CHAR_DATA *) vo; if (!IS_AFFECTED(victim,AFF_BLIND) && !saves_spell(3 * level / 4 + dam / 15, victim,DAM_FIRE,SPELL_AFFLICTIVE)) { AFFECT_DATA af; act("$n is blinded by smoke!",victim,NULL,NULL,TO_ROOM); act("Your eyes tear up from smoke...you can't see a thing!",victim,NULL,NULL,TO_CHAR); af.where = TO_AFFECTS; af.type = skill_lookup("fire breath"); af.level = level; af.duration = 1; af.location = APPLY_HITROLL; if (!IS_NPC(victim) && number_percent() < get_skill(victim,gsn_blind_fighting)){ if (is_affected(victim, gsn_battletrance)) af.modifier = 0; else af.modifier = -3; } else af.modifier = -6; af.bitvector = AFF_BLIND; affect_to_char(victim,&af); af.location = APPLY_AC; if (!IS_NPC(victim) && number_percent() < get_skill(victim,gsn_blind_fighting)){ if (is_affected(victim, gsn_battletrance)) af.modifier = 0; else af.modifier = +5; } else af.modifier = +15; affect_to_char(victim,&af); } } } void poison_effect(void *vo,int level, int dam, int target) { if (target == TARGET_CHAR) { CHAR_DATA *victim = (CHAR_DATA *) vo; if (!saves_spell(3 * level / 4 + dam / 15, victim,DAM_POISON,SPELL_MALEDICTIVE)) { AFFECT_DATA af; send_to_char("You feel poison coursing through your veins.\n\r",victim); act("$n looks very ill.",victim,NULL,NULL,TO_ROOM); af.where = TO_AFFECTS; af.type = gsn_poison; af.level = level; af.duration = 1; af.location = APPLY_STR; af.modifier = -1; af.bitvector = AFF_POISON; affect_join( victim, &af ); } } } void shock_effect(void *vo,int level, int dam, int target) { if (target == TARGET_CHAR) { CHAR_DATA *victim = (CHAR_DATA *) vo; if (!saves_spell(3 * level / 4 + dam / 15, victim,DAM_LIGHTNING,SPELL_AFFLICTIVE)) { send_to_char("Your muscles stop responding.\n\r",victim); act("$n has been stunned by the shock!", victim, NULL, NULL, TO_ROOM); WAIT_STATE2(victim, 1 * PULSE_VIOLENCE); } } } void paralyze_effect(void *vo,int level, int dam, int target) { if (target == TARGET_CHAR){ CHAR_DATA *victim = (CHAR_DATA *) vo; if (IS_UNDEAD(victim) || !saves_spell(3 * level / 4 + dam / 15, victim,DAM_LIGHTNING,SPELL_AFFLICTIVE)){ if (!is_affected(victim, gsn_paralyze)){ AFFECT_DATA af; act("$n has been paralyzed!", victim, NULL, NULL, TO_ROOM); act("You have been paralyzed!", victim, NULL, NULL, TO_CHAR); af.type = gsn_paralyze; af.level = level; af.duration = 1; af.where = TO_AFFECTS; af.bitvector = 0; af.location = APPLY_NONE; af.modifier = 3; affect_to_char( victim, &af ); } } } } void do_identify( CHAR_DATA *ch, char *argument ) { char arg[MIL], buf[MSL], buf2[MSL]; OBJ_DATA *obj; int i; AFFECT_DATA *paf; bool extract = FALSE; one_argument( argument, arg ); if (arg[0] == '\0') { send_to_char("Identify what?\n\r",ch); return; } obj = get_obj_list(ch,arg,ch->carrying); if (obj== NULL) { send_to_char("You don't have that item.\n\r",ch); return; } /* clone check */ if (obj->pIndexData->vnum == OBJ_VNUM_CLONE){ extract = TRUE; obj = create_object( get_obj_index(obj->cost), obj->level); } sprintf( buf,"Object '%s' is type %s, material %s.", obj->name, item_name(obj->item_type), obj->material); do_say(ch,buf); sprintf( buf,"Extra flags: %s.", extra_bit_name( obj->extra_flags )); do_say(ch,buf); sprintf( buf,"Weight is %d, value is %d, level is %d.", obj->weight / 10, obj->cost, obj->level); do_say(ch,buf); switch ( obj->item_type ) { case ITEM_SOCKET: if (IS_SOC_STAT(obj, SOCKET_ARMOR) && IS_SOC_STAT(obj, SOCKET_WEAPON)) do_say(ch, "Armor and Weapon socket."); else if (IS_SOC_STAT(obj, SOCKET_ARMOR)) do_say(ch, "Armor only socket."); else if (IS_SOC_STAT(obj, SOCKET_WEAPON)) do_say(ch, "Weapon only socket."); else do_say(ch, "Weapon only socket."); if (obj->value[1]){ sprintf(buf, "Adds following to extra flags: %s", flag_string( extra_flags, obj->value[1] ) ); do_say(ch, buf); } if (obj->value[4]){ sprintf(buf, "Adds following to weapon flags: %s", flag_string( weapon_type2, obj->value[4] ) ); do_say(ch, buf); } break; case ITEM_SCROLL: case ITEM_ARTIFACT: case ITEM_POTION: case ITEM_PILL: sprintf( buf, "Level %d spells of:", obj->value[0] ); for ( i = 1; i <= 4; i++ ) if ( obj->value[i] >= 0 && obj->value[i] < MAX_SKILL && skill_table[obj->value[i]].name != NULL) { strcat( buf, " '" ); strcat( buf, skill_table[obj->value[i]].name ); strcat( buf, "'" ); } do_say(ch,buf); break; case ITEM_WAND: case ITEM_STAFF: if (skill_table[obj->value[3]].name == NULL) break; sprintf( buf, "Has %d charges of level %d", obj->value[2], obj->value[0] ); if ( obj->value[3] >= 0 && obj->value[3] < MAX_SKILL ) { strcat( buf, " '" ); strcat( buf, skill_table[obj->value[3]].name ); strcat( buf, "'" ); } do_say(ch,buf); break; case ITEM_DRINK_CON: sprintf(buf,"It holds %s-colored %s.", liq_table[obj->value[2]].liq_color, liq_table[obj->value[2]].liq_name); do_say(ch,buf); break; case ITEM_CONTAINER: sprintf(buf,"Capacity: %d# Maximum weight: %d# flags: %s", obj->value[3], obj->value[0], cont_bit_name(obj->value[1])); do_say(ch,buf); if (obj->value[4] != 100) { sprintf(buf,"Weight multiplier: %d%%", obj->value[4]); do_say(ch,buf); } break; case ITEM_WEAPON: sprintf(buf, "Weapon type is "); if (IS_WEAPON_STAT(obj, WEAPON_TWO_HANDS) ) strcat(buf, "two-handed "); switch (obj->value[0]) { case(WEAPON_EXOTIC) : strcat(buf,"exotic."); break; case(WEAPON_SWORD) : strcat(buf,"sword."); break; case(WEAPON_DAGGER) : strcat(buf,"dagger."); break; case(WEAPON_SPEAR) : strcat(buf,"spear."); break; case(WEAPON_MACE) : strcat(buf,"mace/club."); break; case(WEAPON_AXE) : strcat(buf,"axe."); break; case(WEAPON_FLAIL) : strcat(buf,"flail."); break; case(WEAPON_WHIP) : strcat(buf,"whip."); break; case(WEAPON_POLEARM): strcat(buf,"polearm."); break; case(WEAPON_STAFF) : strcat(buf,"staff."); break; default : strcat(buf,"unknown."); break; } do_say(ch,buf); if (obj->pIndexData->new_format) sprintf(buf,"Damage is %dd%d (average %d).", obj->value[1],obj->value[2], (1 + obj->value[2]) * obj->value[1] / 2); else sprintf( buf, "Damage is %d to %d (average %d).", obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2 ); do_say( ch,buf ); if ( IS_OBJ_STAT(obj, ITEM_SOCKETABLE)) do_say( ch, "Can be socketed."); break; case ITEM_ARMOR: sprintf( buf, "Armor class is %d pierce, %d bash, %d slash, and %d vs. magic.", obj->value[0], obj->value[1], obj->value[2], obj->value[3] ); do_say( ch,buf ); if ( IS_OBJ_STAT(obj, ITEM_SOCKETABLE)) do_say( ch, "Can be socketed."); break; case ITEM_THROW: sprintf( buf, "Has %d %s left.",obj->value[0],obj->short_descr); do_say( ch, buf ); if (obj->pIndexData->new_format) sprintf(buf,"Damage is %dd%d (average %d).", obj->value[1],obj->value[2], (1 + obj->value[2]) * obj->value[1] / 2); else sprintf( buf, "Damage is %d to %d (average %d).", obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2 ); do_say( ch, buf ); break; case ITEM_RANGED: if (obj->value[3] == 0) sprintf(buf, "Can be used to fire: %s.", flag_string(projectile_type, obj->value[0])); else{ OBJ_INDEX_DATA* ammo = get_obj_index( obj->value[3] ); sprintf(buf, "Can be used to fire: %s.", ammo == NULL ? "NOT FOUND" : ammo->short_descr); } do_say(ch, buf); sprintf(buf, "Has accuracy of: %d%%, and rate of fire: %d", obj->value[1], obj->value[2]); do_say(ch, buf); sprintf(buf, "Flags: %s",flag_string(ranged_type, obj->value[4])); do_say(ch, buf); break; case ITEM_PROJECTILE: sprintf(buf, "Is a projectile of type %s", flag_string(projectile_type, obj->value[0])); do_say(ch, buf); if (obj->pIndexData->new_format) sprintf(buf, "Damage is %dd%d (average %d).", obj->value[1],obj->value[2], (1 + obj->value[2]) * obj->value[1] / 2); else sprintf( buf, "Damage is %d to %d (average %d).", obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2 ); do_say(ch, buf); } if (!obj->enchanted) for ( paf = obj->pIndexData->affected; paf != NULL; paf = paf->next ) { if ( paf->location != APPLY_NONE && (paf->location < APPLY_O_COND || paf->where == TO_SKILL) && paf->modifier != 0 ) { sprintf( buf, "Affects %s by %d.", (paf->where == TO_SKILL ? skill_table[paf->location].name : affect_loc_name( paf->location )), paf->modifier ); do_say( ch,buf ); } if (paf->bitvector) { switch(paf->where) { case TO_AFFECTS: sprintf(buf,"Adds %s affect.", affect_bit_name(paf->bitvector)); break; case TO_OBJECT: sprintf(buf,"Adds %s object flag.", extra_bit_name(paf->bitvector)); break; case TO_WEAPON: sprintf(buf,"Adds %s weapon flags.", weapon_bit_name(paf->bitvector)); break; case TO_IMMUNE: sprintf(buf,"Adds immunity to %s.", imm_bit_name(paf->bitvector)); break; case TO_RESIST: sprintf(buf,"Adds resistance to %s.", imm_bit_name(paf->bitvector)); break; case TO_VULN: sprintf(buf,"Adds vulnerability to %s.", imm_bit_name(paf->bitvector)); break; case TO_SKILL: /* handled above */ break; default: sprintf(buf,"Unknown bit %d: %d", paf->where,paf->bitvector); break; } do_say( ch,buf ); } } for ( paf = obj->affected; paf != NULL; paf = paf->next ) if ( paf->location != APPLY_NONE && (paf->location < APPLY_O_COND || paf->where == TO_SKILL) && paf->modifier != 0 ) { sprintf( buf, "Affects %s by %d", (paf->where == TO_SKILL ? skill_table[paf->location].name : affect_loc_name( paf->location )), paf->modifier ); if ( paf->duration > -1) sprintf(buf2,", %d hours.",paf->duration); else sprintf(buf2,"."); strcat (buf, buf2); do_say( ch,buf ); if (paf->bitvector) { switch(paf->where) { case TO_AFFECTS: sprintf(buf,"Adds %s affect.", affect_bit_name(paf->bitvector)); break; case TO_OBJECT: sprintf(buf,"Adds %s object flag.", extra_bit_name(paf->bitvector)); break; case TO_WEAPON: sprintf(buf,"Adds %s weapon flags.", weapon_bit_name(paf->bitvector)); break; case TO_IMMUNE: sprintf(buf,"Adds immunity to %s.", imm_bit_name(paf->bitvector)); break; case TO_RESIST: sprintf(buf,"Adds resistance to %s.", imm_bit_name(paf->bitvector)); break; case TO_VULN: sprintf(buf,"Adds vulnerability to %s.", imm_bit_name(paf->bitvector)); break; case TO_SKILL: /* handled above */ break; default: sprintf(buf,"Unknown bit %d: %d", paf->where,paf->bitvector); break; } do_say( ch,buf ); } }//END if APPLY_NONE //MANA CHARGE if ( (paf = affect_find(obj->affected, gen_mana_charge)) != NULL) { char buf [MIL]; if(mcharge_info(ch, buf, obj, paf, TRUE)) do_say(ch, buf); } if (obj->pCabal || obj->race || obj->class >= 0){ sprintf(buf, "I have a feeling only a %s%s%s%s%s%scan use it.", obj->race ? race_table[obj->race].name : "", obj->race ? " " : "", obj->class >= 0 ? class_table[obj->class].name : "", obj->class >= 0 ? " ": "", obj->pCabal ? obj->pCabal->name : "", obj->pCabal ? " ": ""); do_say(ch, buf); } if (CAN_WEAR(obj, ITEM_UNIQUE)) do_say(ch,"Unique item."); if (CAN_WEAR(obj, ITEM_RARE)) do_say(ch,"Rare item."); if (CAN_WEAR(obj, ITEM_PARRY)) do_say(ch,"Can be dual parried."); if ( obj && HAS_TRIGGER_OBJ( obj, TRIG_USE ) ) do_say(ch, "I have a feeling this item can be used somehow."); if (extract) extract_obj( obj ); } void do_random( CHAR_DATA *ch, char *argument ) { RID* pR = get_rand_room(0,0, //area range (0 to ignore) 0,0, //room ramge (0 to ignore) NULL,0, //areas to choose from NULL,0, //areas to exclude NULL,0, //sectors required NULL,0, //sectors to exlude NULL,0, //room1 flags required NULL,0, //room1 flags to exclude NULL,0, //room2 flags required NULL,0, //room2 flags to exclude 5, //number of seed areas FALSE, //exit required? FALSE, //Safe? ch); //Character for room checks send_to_char("You have been teleported!\n\r",ch); act( "$n vanishes!", ch, NULL, NULL, TO_ROOM ); char_from_room( ch ); char_to_room( ch, pR ); if (ch == NULL || ch->in_room == NULL) return; act( "$n suddenly pops into existence.", ch, NULL, NULL, TO_ROOM ); if (ch == NULL || ch->in_room == NULL) return; do_look( ch, "auto" ); } void do_home( CHAR_DATA *ch, char *argument ) { ROOM_INDEX_DATA *location; if (IS_NPC(ch)) location = get_room_index(ch->homevnum); else location = get_room_index(get_temple(ch)); if (location == NULL) { send_to_char("You are completely lost.\n\r",ch); return; } else if (location == ch->in_room) { send_to_char("You are already home.\n\r",ch); return; } else { if (IS_AFFECTED(ch,AFF_FLYING) && !is_affected(ch,gsn_thrash)) act("$n flies home.",ch,NULL,NULL,TO_ROOM); else act("$n walks home.",ch,NULL,NULL,TO_ROOM); char_from_room(ch); char_to_room(ch,location); act("$n enters the room.",ch,NULL,NULL,TO_ROOM); do_look(ch,"auto"); } } bool spec_keeper_stay(CHAR_DATA *ch) { if (ch->fighting != NULL) return FALSE; if (ch->position < POS_SLEEPING) return FALSE; if (ch->pIndexData->pShop == NULL || (ch->pIndexData->pShop->open_hour == 0 && ch->pIndexData->pShop->close_hour == 23)) return FALSE; if (ch->status == 1 && ch->position != POS_SLEEPING) { act("$n yawns and goes to sleep.", ch, NULL, NULL, TO_ROOM); ch->position = POS_SLEEPING; } else if (mud_data.time_info.hour == ch->pIndexData->pShop->close_hour && ch->status == 0 && ch->position != POS_SLEEPING) { act("$n closes up the shop for the night.", ch, NULL, NULL, TO_ROOM); act("$n yawns and settles down for a few hours of sleep.", ch, NULL, NULL, TO_ROOM); ch->position = POS_SLEEPING; ch->status = 1; return TRUE; } else if (mud_data.time_info.hour == ch->pIndexData->pShop->open_hour && ch->status == 1 && ch->position == POS_SLEEPING) { ch->position = POS_STANDING; act("$n wakes up and gets ready for work.",ch, NULL, NULL, TO_ROOM); do_say(ch,"This shop is now opened for business!"); ch->status = 0; return TRUE; } return FALSE; } bool spec_keeper_move(CHAR_DATA *ch) { int open = 0; int close = 0; int time = 0; if (ch->pIndexData->pShop == NULL){ nlogf("spec_keeper_move: mvnum: %d, error in shop info.", ch->pIndexData->vnum); return FALSE; } if (ch->pIndexData->pShop->open_hour < 0){ nlogf("spec_keeper_move: mvnum: %d, error in shop info.", ch->pIndexData->vnum); return FALSE; } if (ch->pIndexData->pShop->close_hour < 0){ nlogf("spec_keeper_move: mvnum: %d, error in shop info.", ch->pIndexData->vnum); return FALSE; } open = ch->pIndexData->pShop->open_hour; close = ch->pIndexData->pShop->close_hour; time = mud_data.time_info.hour; // bool fReverse = (open > close); if (ch->fighting != NULL) return FALSE; if (ch->position < POS_SLEEPING) return FALSE; if (ch->pIndexData->pShop == NULL || open == close || (open == 0 && close == 0)) return FALSE; /* auto sleep shop if woken */ if (ch->status == 1 && ch->position != POS_SLEEPING) { check_social(ch, "grumble", ""); act("$n yawns and goes to sleep.", ch, NULL, NULL, TO_ROOM); ch->position = POS_SLEEPING; } /* close shop */ else if ( time == close && ch->status == 0 && ch->position != POS_SLEEPING) { act("$n closes up the shop for the night.", ch, NULL, NULL, TO_ROOM); move_char(ch, 4, FALSE); act("$n yawns and settles down for a few hours of sleep.", ch, NULL, NULL, TO_ROOM); ch->position = POS_SLEEPING; ch->status = 1; return TRUE; } else if ( time == open && ch->status == 1 && ch->position == POS_SLEEPING) { ch->position = POS_STANDING; act("$n wakes up and heads downstairs for work.", ch, NULL, NULL, TO_ROOM); move_char(ch, 5, FALSE); do_say(ch,"This shop is now opened for business!"); ch->status = 0; return TRUE; } return FALSE; } bool spec_virgil_guard(CHAR_DATA *ch) { return FALSE; } bool spec_shadowdemon(CHAR_DATA *ch) { int chance = number_percent(); CHAR_DATA *victim; if (ch->fighting != NULL) return spec_poison(ch); if (ch->master == NULL) return FALSE; if (!IS_AWAKE(ch)) return FALSE; victim = ch->master; if (ch->position != POS_FIGHTING && ch->in_room == ch->master->in_room) { if (chance < 2) { act("$n snarls and attacks you for wasting its time.",ch,NULL,victim,TO_VICT); act("$n snarls and lunges at $N.",ch,NULL,victim,TO_NOTVICT); multi_hit(ch, victim, TYPE_UNDEFINED); return TRUE; } else if (chance < 10) { act("$n growls with a hint of annoyance.",ch,NULL,NULL,TO_ALL); return TRUE; } else return FALSE; } return FALSE; } bool spec_mob_call( CHAR_DATA *ch ) { CHAR_DATA *victim, *wolf; AFFECT_DATA af; if ( ch->position != POS_FIGHTING || !IS_AFFECTED(ch,AFF_CHARM)) return FALSE; if ( (victim = ch->fighting) == NULL) return FALSE; if ( is_affected(ch,gsn_mind_link) ) return FALSE; if ( ch->pIndexData->vnum == MOB_VNUM_DISPLACER && victim->in_room->sector_type != SECT_FIELD && victim->in_room->sector_type != SECT_FOREST && victim->in_room->sector_type != SECT_HILLS && victim->in_room->sector_type != SECT_MOUNTAIN ) return FALSE; if ( ch->master == NULL || (number_percent() > get_skill(ch->master,gsn_mind_link))) return FALSE; if ( number_bits( 3 ) != 0 ) return FALSE; act("$n shimmers and seems to split in half!",ch,NULL,NULL,TO_ROOM); wolf = create_mobile(ch->pIndexData); clone_mobile(ch,wolf); wolf->master = NULL; wolf->leader = NULL; REMOVE_BIT(wolf->affected_by,AFF_CHARM); REMOVE_BIT(wolf->act2, ACT_NEED_MASTER); char_to_room(wolf,ch->in_room); af.where = TO_AFFECTS; af.type = gsn_timer; af.level = ch->level; af.duration = 3; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = 0; affect_to_char(wolf,&af); af.type = gsn_mind_link; af.duration = 12; affect_to_char(ch,&af); multi_hit(wolf,victim,TYPE_UNDEFINED); check_improve(ch->master,gsn_mind_link,TRUE,1); return TRUE; } bool spec_displacer_beast( CHAR_DATA *ch ) { //this function does all the wierd things for the displacer beast. int chance = 0; //const //beast just emotes, other wise it toggles vis/invis const int non_chance = 95; const int pop_chance = 98; //bools bool is_invis = FALSE; /* run the mob spec for duplicating displacer */ spec_mob_call( ch ); if ( (chance = number_percent()) < non_chance) return FALSE; //First we check if visible if (IS_AFFECTED(ch, AFF_INVISIBLE)) is_invis = TRUE; //Now we decide what to do. if (chance < pop_chance) act("$n suddenly disappears only to reappear in a new spot seconds later.", ch, NULL, NULL, TO_ALL); else { if (is_invis) {do_visible(ch, NULL);act("$n appears suddenly!", ch, NULL, NULL, TO_ALL);} else { act("$ns shape blurs and shimmers out of existence.", ch, NULL, NULL, TO_ALL); SET_BIT( ch->affected_by, AFF_INVISIBLE); }//end if visible }//end if not pop return TRUE; }//end spec_displacer_beast. /* if the mob is not hunting anyone, it looks for any wanted/outlaws in area, selects a random one and hunts them */ bool spec_hunt_wanted(CHAR_DATA *ch) { const int max_char = 8; CHAR_DATA* chars[max_char]; CHAR_DATA* vch; int last_char = 0; int i = 0; if (ch->hunting != NULL) return FALSE; else SET_BIT(ch->act2, ACT_LAWFUL ); for (i = 0; i < max_char; i ++) chars[i] = NULL; /* select players to choose from */ for (vch = player_list; vch; vch = vch->next_player ){ if (!IS_NPC(vch) && IS_WANTED(vch) && vch->in_room && vch->in_room->area == ch->in_room->area && can_see(ch, vch )) chars[last_char++] = vch; } if (last_char < 1) return FALSE; else ch->hunting = chars[number_range(0, last_char - 1 )]; return TRUE; } /* Written by: Virigoth * * Returns: true if somethign was done * * Comment: Vanguards behavior is coded here, there is two functions * * vanguard_behave and vanguard_fight * * Former handles non combat behavior, latter combat behavior */ bool vanguard_fight(CHAR_DATA* ch, CHAR_DATA* victim){ /* first and foremost: - Vangaurd cannot fight mobs or lawfuls or non-evils - doing so results in it leaving the master. combat behavior: I] Health above 25%: - Spell (50) -- turn undead if undead -- Banishment if demon -- lightning -- flamearrow -- Sear if capable -- dispel evil if nothing else cast. - Non spell -- Grapple -- Bodyslam -- Sidestep -- Disarm/shielddisarm/offhand - Other -- Rescues if master below 30 */ char buf[MIL]; const int level = ch->level; int chance = 0; const int do_combat = 75; //Control chance that any actiosn are done. const int do_spell = 75; const int low_health = 30; //% health at wich behavior changes. const int to_taunt = 30; //chance top taunt the oppoennt/owner int to_spell = 50; //chance to use a spell, otherwise use skills. int to_turn = 0; //used only if undead target int to_banish = 0; //used only if demon target int to_sear = 0; //only if cabable, else it is skipped. int to_light = 50; //lighting int to_flame = 80; //flame arrow //otheriwise dispel evil int to_grapple = 20; //grapple lag skill (increaed if < low_health) int to_slam = 50; //bodyslam (100 if < low health) int to_trip = 70; //trip, ruled by low_health int to_disarm = 90; //disarm (if primary no_remove or empty checks sec./shield) //kick if nothing else selected. int hp_rescue = 40; //if health > rescue health% to_rescue = 0 int to_rescue = 40; //chance to attempt to rescue if < res_health bool fHasYelled = FALSE; //Used to mark if yelled as to not make too many yells/round if (!ch || !victim) return FALSE; if (!IS_AFFECTED(ch, AFF_CHARM) || !ch->master) return FALSE; /* Check who we are fighting */ /* Viri: removed for now if ((!IS_EVIL(victim) && !victim->master) || (IS_NPC(victim) && !victim->master && victim->pCabal == NULL && !IS_AFFECTED(victim, AFF_CHARM)) ){ if (!IS_IMMORTAL(ch->master)){ sprintf(buf, "I will have none of your petty squables %s, fight you own battles!", ch->master->name); REMOVE_BIT(ch->comm, COMM_NOYELL); do_yell(ch, buf); fHasYelled = TRUE; SET_BIT(ch->comm, COMM_NOYELL); die_follower(ch, TRUE); return TRUE; } } */ /* combat behavior */ /* check rescue first */ if ( (ch->master->hit * 100 / ch->master->max_hit < hp_rescue) && ch->master->fighting && ch->master->fighting->fighting == ch->master){ if (number_percent() < to_rescue){ check_social(ch, "snort",""); sprintf(buf, "You seem to be in need of a rescue %s. Turning into a damsel are you?", PERS(ch->master, ch)); do_say(ch, buf); sprintf(buf, ch->master->name); do_rescue(ch, buf); return TRUE; } } /* specific stuff */ if (victim->race == race_lookup("demon") && !is_affected(victim, skill_lookup("minor banishment")) ){ to_banish = 100; to_spell = 100; } else if (IS_UNDEAD(victim) && !is_affected(victim, gsn_turn_undead) ) to_turn = 100; else if ( IS_OUTSIDE(ch) && !IS_SET(ch->in_room->room_flags, ROOM_DARK) && mud_data.time_info.hour > 7 && mud_data.time_info.hour < 18){ if (mud_data.weather_info.sky < SKY_RAINING) to_sear = 30; else if (mud_data.weather_info.sky < SKY_CLOUDY) to_sear = 100; } /* test for special behavior when traget is weak. */ if ( 100 * victim->hit / victim->max_hit < low_health){ /* we do not cast spells, but lag */ to_spell = 0; /* check if protective shield is on. */ if (get_lagprot(victim) != LAG_SHIELD_NONE){ to_grapple = 0; to_slam = 0; if (!IS_AFFECTED(victim, AFF_FLYING)) to_trip = 100; else{ /* kick/disarm will be performed */ to_trip = 0; to_disarm = 30; } } /* no shield set */ else{ /* grapple or slam */ to_grapple = 50; to_slam = 100; } /* no spell check */ if (is_affected(ch, gsn_blasphemy)) to_spell = 0; /* check if we yell something sarcastic*/ if (number_percent() < to_taunt){ bool to_yell = FALSE; switch (number_range(0, 10)){ default: case 0: sprintf(buf, "Surely you can do better then this %s?", PERS(victim, ch)); break; case 1: sprintf(buf, "Truly the death of your seed will be a benefit to any %s.", race_table[victim->race].name); break; case 2: sprintf(buf, "You seem to be bleeding quite profusely %s.", PERS(victim, ch)); check_social(ch, "cackle", ""); break; case 3: sprintf(buf, "You seem quite hurt %s. Perhaps one more bodyslam is in order?", PERS(victim, ch)); break; case 4: sprintf(buf, "If that is best you have %s, next time bring an army.", PERS(victim, ch)); break; case 5: sprintf(buf, "Put some muscle into it %s, I cannot do all the work myself.", PERS(ch->master, ch)); check_social(ch, "snort", ""); break; case 6: sprintf(buf, "Run while there is still breath in your lungs %s, for soon it will be gone!", PERS(victim, ch)); to_yell = TRUE; break; case 7: sprintf(buf, "%s you pathetic %s! Even a mudschool monster hits harder!", PERS(victim, ch), race_table[victim->race].name); to_yell = TRUE; break; case 8: sprintf(buf, "Surely %s was drunk when it created you %s!", IS_NPC(victim) ? "The One God" : victim->pcdata->deity, PERS(victim, ch)); to_yell = TRUE; break; case 9: sprintf(buf, "All those that wish to witness a dead %s come to me!", race_table[victim->race].name); to_yell = TRUE; break; case 10: sprintf(buf, "Know %s's wrath %s you pitiful %s!", ch->master->pcdata->deity, PERS(victim, ch), race_table[victim->race].name); to_yell = TRUE; break; }//end say/yell select if (to_yell){ REMOVE_BIT(ch->comm, COMM_NOYELL); do_yell(ch, buf); fHasYelled = TRUE; SET_BIT(ch->comm, COMM_NOYELL); } else do_say(ch, buf); }//END Taunting. }//END behavior if opponent hurt /* stuff said if regular combat */ else if (number_percent() < to_taunt){ bool to_yell = FALSE; switch (number_range(0, 10)){ default: case 0: sprintf(buf, "Tis but a flesh wound. I'm sure you've had worse."); break; case 1: sprintf(buf, "Parry, dodge, counter, parry.. So predictable."); check_social(ch, "sigh", ""); break; case 2: act("$n turns $s slit-less helm towards $N.", ch, NULL, ch->master, TO_NOTVICT); act("$n turns $s slit-less helm towards $N.", ch, NULL, ch->master, TO_VICT); act("You turn your slit-less helm towards $N.", ch, NULL, ch->master, TO_CHAR); check_social(ch, "snort", ""); sprintf(buf, "And who taught you to fence %s?", PERS(ch->master, ch)); break; case 3: sprintf(buf, "The wind must be strong %s, you keep missing.", PERS(victim, ch)); break; case 4: do_pmote(ch, "Straightens in obvious disdain."); if (victim->master){ sprintf(buf, "Are you so weak %s that you depend on %s to be your bitch?.", PERS(victim->master, ch), PERS(victim, ch)); } else if (victim->pCabal == get_cabal("nexus") || victim->race == race_lookup("demon")) sprintf(buf, "Use the Chaos %s...", PERS(victim, ch)); else if (IS_UNDEAD(victim)) sprintf(buf, "Lost any body parts lately %s? ", PERS(victim, ch)); else if (victim->race == race_lookup("ogre") || ch->master->race == race_lookup("ogre")) sprintf(buf, "Damn creature, spit that thing out of your mouth so I can hear what you're saying!"); else if (victim->race == race_lookup("dwarf") || victim->race == race_lookup("duergar") || victim->race == race_lookup("halfling")){ switch (number_range(0, 2)){ case 0: sprintf(buf, "My back is starting to hurt from bending over to fight you %s!", PERS(ch->master, ch));break; case 1: sprintf(buf, "I will not fight a fat child! Ohh its a %s!", race_table[victim->race].name);break; case 2: sprintf(buf, "You going to stand up and fight like a man shortie?");break; break; }//END SELECT }//END short races else sprintf(buf, "What %s has seen in you %s is beyond me.", ch->master->pcdata->deity, PERS(ch->master, ch)); break; case 5: sprintf(buf, "Put some muscle into it %s, I cannot do all the work myself.", PERS(ch->master, ch)); check_social(ch, "snort", ""); break; case 6: sprintf(buf, "For glory of %s!", ch->master->pcdata->deity); to_yell = TRUE; break; case 7: sprintf(buf, "The light shall be ever victorious!"); to_yell = TRUE; break; case 8: sprintf(buf, "Cry havoc, and let loose the dogs of war!"); to_yell = TRUE; break; case 9: sprintf(buf, "All those that wish to witness a dead %s come to me!", race_table[victim->race].name); to_yell = TRUE; break; case 10: sprintf(buf, "Pain is but a trivial price for your demise %s!", PERS(victim, ch)); to_yell = TRUE; break; }//end say/yell select if (to_yell){ REMOVE_BIT(ch->comm, COMM_NOYELL); do_yell(ch, buf); fHasYelled = TRUE; SET_BIT(ch->comm, COMM_NOYELL); } else do_say(ch, buf); }//END Regular Taunting. /* Execute the combat stuff */ if (number_percent() < to_spell && number_percent() < do_spell){ if ( (chance = number_percent()) < to_turn){ do_pmote(ch, "raises its armored hands to they sky as it calls upon its master's power."); spell_turn_undead(gsn_turn_undead, level, ch, (void*) victim, TARGET_CHAR); } else if (chance < to_banish){ if (!fHasYelled){ sprintf(buf, "%s! By %s's power I banish you from these lands!", PERS(victim, ch), ch->master->pcdata->deity); REMOVE_BIT(ch->comm, COMM_NOYELL); fHasYelled = TRUE; do_yell(ch, buf); SET_BIT(ch->comm, COMM_NOYELL); } spell_mbanish(skill_lookup("minor banishment"), level, ch, (void*) victim, TARGET_CHAR); } else if (chance < to_sear){ act("$n's armor flares with blinding light!", ch, NULL, NULL, TO_ROOM); act("Your armor flares with blinding light!", ch, NULL, NULL, TO_ROOM); broadcast(ch, "The area is suddenly lit up by a bright flare of light.\n\r"); spell_sear(skill_lookup("sear"), level, ch, (void*) victim, TARGET_CHAR); } else if (chance < to_light){ act("Air crackles around $n as $e quickly locks $N in its armored grasp!", ch, NULL, victim, TO_NOTVICT); act("Air crackles around $n as $e locks you in $s armored grasp!", ch, NULL, victim, TO_VICT); act("Air crackles around you as you lock $N in your armored grasp!", ch, NULL, victim, TO_CHAR); broadcast(ch, "Crackle of energy followed by screams and smell of burnt flesh drift into the room.\n\r"); spell_shocking_grasp(skill_lookup("shocking grasp"), level, ch, (void*) victim, TARGET_CHAR); } else if (chance < to_flame){ act("A wave of heat washes by you as sheets of flame shoot forth from $n's gauntlets!", ch, NULL, NULL, TO_ROOM); act("A wave of heat washes by you as sheets of flame shoot forth from your gauntlets!", ch, NULL, NULL, TO_CHAR); broadcast(ch, "A wave of heat washes by you.\n\r"); spell_flame_arrow(skill_lookup("flame arrow"), level, ch, (void*) victim, TARGET_CHAR); } else{ act("$n points $s weapon at $N as it releases a beam of silver light!", ch, NULL, victim, TO_NOTVICT); act("$n points $s weapon at you as it releases a beam of silver light!", ch, NULL, victim, TO_VICT); act("You point your weapon at $N as it releases a beam of silver light!", ch, NULL, victim, TO_CHAR); spell_dispel_evil(skill_lookup("dispel evil"), level, ch, (void*) victim, TARGET_CHAR); } }//End spell else if (number_percent() < do_combat) { if ( (chance = number_percent()) < to_grapple){ do_grapple(ch, ""); } else if (chance < to_slam){ act("Amidst great clanking of metal, $n charges at $N.", ch, NULL, victim, TO_NOTVICT); act("Amidst great clanking of metal, $n charges at you.", ch, NULL, victim, TO_VICT); act("Amidst great clanking of metal, you charge at $N.", ch, NULL, victim, TO_CHAR); do_bodyslam(ch,""); } else if (chance < to_trip){ do_say(ch, "On your knees heathen!"); do_trip(ch,""); } else if (chance < to_disarm){ OBJ_DATA* wield; if ( (wield = get_eq_char( ch, WEAR_WIELD )) == NULL || IS_OBJ_STAT(wield,ITEM_NOREMOVE) || is_affected_obj(wield, gsn_graft_weapon) || is_affected_obj(wield, gen_dark_meta)) { if ( (wield = get_eq_char( ch, WEAR_SECONDARY )) != NULL) do_offhand_disarm(ch, ""); else if ( (wield = get_eq_char( ch, WEAR_SHIELD )) != NULL) do_shield_disarm(ch, ""); }//End if cannot diarm prim. else do_disarm(ch, ""); } else do_kick(ch, ""); }//End regular combat. return TRUE; }//END vanguard combat. bool vanguard_behave(CHAR_DATA* ch){ /* Rules the non-combat behavior of vangaurd */ CHAR_DATA* mch = NULL; //master CHAR_DATA* rch = NULL; //random CHAR_DATA* vch; char buf[MIL]; const int max_chars = 12;//max characters to select form int tot_chars = 0;//current total char. CHAR_DATA* chars[max_chars]; const int to_act = 10; //chance to do anything. int to_area = 30; //Checks says stuff about area. int to_action = 50; //Performs actions int to_say = 100; //Says soemthing // int to_yell = 100; //yells out bool fHasYelled = FALSE; bool fSay = FALSE; bool fYell = FALSE; int chance = number_percent(); /* first check if master is around */ for (vch = ch->in_room->people; vch; vch = vch->next_in_room){ if (!can_see(ch, vch) || IS_IMMORTAL(vch)) continue; if (vch != ch && vch != ch->master && tot_chars < max_chars) chars[tot_chars++] = vch; if (vch != ch->master) continue; mch = vch; break; } /* Return to master occasionly */ if (!mch && !IS_SET(ch->special,SPECIAL_SENTINEL) && ch->master && ch->master->in_room && !IS_ROOM(ch->master->in_room, ROOM_NO_INOUT) && !IS_ROOM(ch->in_room, ROOM_NO_INOUT) && number_percent() < 20){ act("With great fanfare and cloud of sparks shedding from $s armor $n departs!", ch, NULL, NULL, TO_ALL); char_from_room(ch); char_to_room(ch, ch->master->in_room); act("With great fanfare and cloud of sparks shedding from $s armor $n arrives!", ch, NULL, NULL, TO_ALL); } /* check for halberd */ if (get_eq_char( ch, WEAR_WIELD) == NULL){ OBJ_DATA* wield; do_say(ch, "Where is that damn halberd?!"); /* equip it */ wield = create_object( get_obj_index(OBJ_VNUM_VANGUARD_WEP), ch->level ); obj_to_ch(wield, ch); wear_obj(ch, wield, TRUE, FALSE); } /* get the random character. */ if (tot_chars > 0) rch = chars[number_range(0, tot_chars - 1)]; if (number_percent() > to_act) return FALSE; /* say thing on area */ if (chance < to_area){ fYell = FALSE; fSay = FALSE; switch (number_range(0, 12)){ /* CABALS */ case 0: case 1: case 12: if (ch->in_room->pCabal && ch->in_room->pCabal == get_parent(ch->pCabal)){ fSay = TRUE; do_emote(ch, "seems to relax its stance slightly."); sprintf(buf, "Ahh, home sweet home, bloody righteous as usual."); } else if (ch->in_room->pCabal && ch->in_room->pCabal == get_cabal("nexus")){ fSay = TRUE; check_social(ch, "snort", ""); sprintf(buf, "This place reeks of scared demons. They must know I am about."); } else if (ch->in_room->pCabal == get_cabal("warmaster")){ fSay = TRUE; do_emote(ch, "adjusts his halberd."); sprintf(buf, "Why are we here? All I sense is old sweat and lack of intelligence.."); } else if (ch->in_room->pCabal && ch->in_room->pCabal == get_cabal("syndicate")){ fYell = TRUE; if (number_percent() < 50) sprintf(buf, "Come out, come out, where ever you are!"); else{ do_emote(ch, "slams $s gauntlet into $s armored chest making a loud clank"); sprintf(buf, "Bring out yer dead! Bring out yer dead!"); } } else if (ch->in_room->pCabal && ch->in_room->pCabal == get_cabal("savant")){ check_social(ch, "chuckle", ""); fSay = TRUE; sprintf(buf, "Seeking magical aid in your \"performace\", are you?"); } else if (ch->in_room->pCabal && IS_CABAL(ch->in_room->pCabal, CABAL_JUSTICE)){ fSay = TRUE; sprintf(buf, "And what are we doing here? Wish you a pretty wanted flag?"); } else if (ch->in_room->pCabal && IS_CABAL(ch->in_room->pCabal, CABAL_ROYAL)){ fYell = TRUE; sprintf(buf, "Hail the Royal House of [%s]!", ch->in_room->pCabal->who_name); } else{ if (mch){ act("In a strange metalic voice $n belches out: `#Danger $N $t, Danger!``", ch, (mch->pcdata->family[0]? mch->pcdata->family : ""), mch, TO_ROOM); act("In a strange metalic voice you belche out: `#Danger $N $t, Danger!``", ch, (mch->pcdata->family[0]? mch->pcdata->family : ""), mch, TO_CHAR); } else{ fSay = TRUE; sprintf(buf, "Pretty little area.. Could use a few shrines to Palison though."); } } break; /* GENERAL AREA */ case 2: case 3: fSay = TRUE; check_social(ch, "chuckle", ""); sprintf(buf, "%s.. I've laid more then few demons to rest around here.",ch->in_room->area->name); break; case 4: case 5: do_emote(ch, "scans all around."); break; case 6: case 7: if (mch){ fSay = TRUE; sprintf(buf, "Well %s.. We've been here for a while now. What now?", mch->name); } else check_social(ch, "grumble", ""); break; case 8: case 9: act("$n looks up into the sky.", ch, NULL, NULL, TO_ROOM); act("You look up into the sky.", ch, NULL, NULL, TO_CHAR); break; case 10: case 11: act("You notice $n discreetly try to clean a bird dropping from $s armor.", ch, NULL, NULL, TO_ROOM); act("You try to discreetly clean a bird dropping from your armor.", ch, NULL, NULL, TO_CHAR); break; } if (fYell && !fHasYelled){ REMOVE_BIT(ch->comm, COMM_NOYELL); do_yell(ch, buf); fHasYelled = TRUE; SET_BIT(ch->comm, COMM_NOYELL); } else if (fSay) do_say(ch, buf); }//END of AREA actions. else if (chance < to_action){ fYell = FALSE; fSay = FALSE; switch (number_range(0, 5)){ case 0: act("Little sparks of energy seem to crackle around $n's armor.", ch, NULL, NULL, TO_ROOM); act("Little sparks of energy seem to crackle around your armor.", ch, NULL, NULL, TO_CHAR); broadcast(ch, "In the distance you hear a slight crackle of energy."); break; case 1: if (rch){ act("$n looks $N over briefly as $s fists slam together with a loud clank.", ch, NULL, rch, TO_NOTVICT); act("$n looks you over briefly as $s fists slam together with a loud clank.", ch, NULL, rch, TO_VICT); act("You look $N over briefly and slam your fists together with a loud clank.", ch, NULL, rch, TO_CHAR); } else{ act("$n slams $s armored fists together in a sign of impatience.", ch, NULL, NULL, TO_ROOM); act("You slam your armored fists together in a sign of impatience.", ch, NULL, NULL, TO_CHAR); } break; case 2: if (rch){ act("$n's halaberd whistles through the air only to pass an inch from $N's head!", ch, NULL, rch, TO_NOTVICT); act("$n's halaberd whistles through the air only to pass an inch from your head!", ch, NULL, rch, TO_VICT); check_social(ch, "chuckle", ""); } else act("$n pits $s halberd into a deadly spin in a dazzling show of skill.", ch, NULL, NULL, TO_ROOM); break; case 3: do_emote(ch, "loses all signs of life becoming a large armored statue."); break; case 4: act("$n's visor less helm spins full circle about. Creepy..", ch, NULL, NULL, TO_ROOM); break; case 5: if (rch){ act("Armor creaks and sizzles with heat as $n towers over $N.", ch, NULL, rch, TO_NOTVICT); act("Armor creaks and sizzles with heat as $n towers over you.", ch, NULL, rch, TO_VICT); } else act("Armor creaks and sizzles with heat as $n straightens to $s full height.", ch, NULL,NULL, TO_ROOM); break; } if (fYell && !fHasYelled){ REMOVE_BIT(ch->comm, COMM_NOYELL); do_yell(ch, buf); fHasYelled = TRUE; SET_BIT(ch->comm, COMM_NOYELL); } else if (fSay) do_say(ch, buf); }//END ACTION /* Says */ else if (chance < to_say){ fYell = FALSE; fSay = FALSE; switch (number_range(0, 3)){ case 0: case 1: /* Race specific stuff skipped to case 2 if no rch*/ if (rch){ act("$n turns towards $N briefly.", ch, NULL, rch, TO_NOTVICT); act("$n turns towards you briefly.", ch, NULL, rch, TO_VICT); if (rch->race == race_lookup("human")){ fSay = TRUE; sprintf(buf, "%s.. How average..", race_table[rch->race].name); } else if (rch->race == race_lookup("illithid")){ fSay = TRUE; sprintf(buf, "Hope your intelligence makes up for your looks %s", PERS(rch, ch)); } else if (rch->race == race_lookup("illithid")){ fSay = TRUE; if (number_percent() < 50) sprintf(buf, "Hope your intelligence makes up for your looks %s.", PERS(rch, ch)); else{ check_social(ch, "chuckle", ""); sprintf(buf, "Ever seen calamari %s?", PERS(rch, ch)); } } else if (rch->race == race_lookup("duergar") || rch->race == race_lookup("dwarf")){ fSay = TRUE; sprintf(buf, "Watch my legplating %s, else you impale your face on a spikard.", PERS(rch, ch)); } else if (IS_UNDEAD(rch)){ fSay = TRUE; sprintf(buf, "You look like you missed out on your last embalming session %s.", PERS(rch, ch)); } else{ fSay = TRUE; sprintf(buf, "Not bad.. not bad at all..."); } break; }//END if random char case 2: case 3: fSay = TRUE; if (rch) sprintf(buf, "Is there not something you need to do %s?", PERS(rch, ch)); else sprintf(buf, "Is there not something we should be doing?"); break; }//end switch if (fYell && !fHasYelled){ REMOVE_BIT(ch->comm, COMM_NOYELL); do_yell(ch, buf); fHasYelled = TRUE; SET_BIT(ch->comm, COMM_NOYELL); } else if (fSay) do_say(ch, buf); }//END SAYS return TRUE; } bool spec_vanguard(CHAR_DATA *ch) { int trust = ch->trust; if (!ch) return FALSE; if (!ch->in_room) return FALSE; if (!IS_AWAKE(ch)) return FALSE; /* enable mobprog like access tos kills */ ch->trust = 6969; if (ch->fighting) vanguard_fight(ch, ch->fighting); else vanguard_behave(ch); ch->trust = trust; return TRUE; } bool spec_servant_hide(CHAR_DATA *ch){ if (!ch) return FALSE; if (ch->pIndexData->vnum != MOB_VNUM_SERVANT_AIR) return FALSE; if (ch->fighting) return FALSE; /* Hide if SENTRY */ if (IS_SET(ch->special, SPECIAL_SENTINEL) && !IS_AFFECTED(ch, AFF_HIDE)){ act("$n seems to disperse into nothingness", ch, NULL, NULL, TO_ROOM); SET_BIT(ch->affected_by, AFF_HIDE); } else if (!IS_SET(ch->special, SPECIAL_SENTINEL)) REMOVE_BIT(ch->affected_by, AFF_HIDE); return TRUE; } bool spec_justice_sentinel(CHAR_DATA *ch){ /* hides and invises if not incombat, scans area for visible wanted and reports to master. */ CHAR_DATA* victim; AFFECT_DATA* paf; char buf[MIL]; char buf1[MIL]; char buf2[MIL]; const int to_act = 40; bool fFound = FALSE; /* Hide */ if (!ch->fighting){ if (!IS_AFFECTED(ch, AFF_HIDE)) SET_BIT(ch->affected_by, AFF_HIDE); if (!IS_AFFECTED(ch, AFF_INVISIBLE)) SET_BIT(ch->affected_by, AFF_INVISIBLE); } if (IS_AFFECTED(ch, AFF_CHARM)) return FALSE; /* cannot be following someone */ if (ch->master) return FALSE; if (number_percent() > to_act) return FALSE; if ( (paf = affect_find(ch->affected, gsn_timer)) != NULL && paf->duration <= 1){ sprintf(buf, "Reporting end of duty at %s in %s.", ch->in_room->name, ch->in_room->area->name); cabal_echo_flag( CABAL_JUSTICE, buf ); extract_char(ch, TRUE); return FALSE; } if (ch->fighting){ sprintf(buf, "Reporting an attack by %s. Engaging.", PERS(ch->fighting, ch)); cabal_echo_flag( CABAL_JUSTICE, buf ); return TRUE; } /* scan area for baddies */ if( (IS_AFFECTED(ch, AFF_BLIND) && !is_affected(ch, gsn_bat_form)) || (IS_AFFECTED(ch, AFF_BLIND) && bat_blind(ch)) || bat_blind(ch) ) { send_to_char( "You can't see a thing!\n\r", ch ); return FALSE; } if (IS_AFFECTED2(ch,AFF_TERRAIN)) { send_to_char( "Darkness.. Darkness everywhere!\n\r",ch); return FALSE; } if (IS_SET(ch->in_room->room_flags,ROOM_NOWHERE) && !IS_IMMORTAL(ch)) { send_to_char( "You can't see the area out of this room.\n\r",ch); return FALSE; } /* scan now */ if (number_percent() < 15){ act("You sense a hidden presence scan the area.", ch, NULL, NULL, TO_ROOM); broadcast(ch, "You sense someones eyes on your back...\n\r"); } buf[0] = '\0'; buf1[0] = '\0'; buf2[0] = '\0'; for ( victim = player_list; victim != NULL; victim = victim->next_player ){ if (IS_SET(victim->act, PLR_WANTED) && (!IS_AFFECTED2(victim,AFF_SHADOWFORM) || IS_IMMORTAL(ch)) && (!IS_AFFECTED2(victim,AFF_TREEFORM)) && (!IS_NPC(victim) || is_affected(victim,gsn_doppelganger)) && !IS_IMMORTAL(victim) && victim->in_room != NULL && !IS_SET(victim->in_room->room_flags,ROOM_NOWHERE) && !room_is_private(victim->in_room) && victim->in_room->area == ch->in_room->area && !is_affected(victim,gsn_bat_form) && !is_affected(victim,gsn_coffin) && !is_affected(victim,gsn_entomb) && !IS_AFFECTED2(victim,AFF_CATALEPSY) && can_see( ch, victim ) ) { sprintf(buf2, "%s%s", (fFound? ", ":""), PERS(victim, ch)); fFound = TRUE; strcat(buf1, buf2); } } if (fFound){ REMOVE_BIT(ch->affected_by, AFF_HIDE); sprintf(buf, "Reporting %s in area of %s.", buf1, ch->in_room->area->name); cabal_echo_flag( CABAL_JUSTICE, buf ); SET_BIT(ch->affected_by, AFF_HIDE); return TRUE; } return FALSE; } /* checks if the person has been marked by this eye yet */ bool can_meye_report(CHAR_DATA* victim, char* name, int sn){ AFFECT_DATA* paf; for (paf = victim->affected; paf; paf = paf->next ){ if (paf->type != sn || !paf->has_string || str_cmp(paf->string, name)) continue; else break; } if (paf) return FALSE; else return TRUE; } bool spec_magic_eye(CHAR_DATA *ch){ /* hides camoes and invises if not incombat, scans area for visible pk threats of leader and reports to leader. */ CHAR_DATA* victim; AFFECT_DATA* paf; char buf[MIL]; char buf1[MIL]; char buf2[MIL]; const int to_act = 100; const int gsn_magic_eye = skill_lookup("magic eye"); bool fFound = FALSE; /* Hide */ if (!ch->fighting){ if (!IS_AFFECTED(ch, AFF_HIDE)) SET_BIT(ch->affected_by, AFF_HIDE); if (!IS_AFFECTED2(ch, AFF_CAMOUFLAGE)) SET_BIT(ch->affected2_by, AFF_CAMOUFLAGE); if (!IS_AFFECTED(ch, AFF_INVISIBLE)) SET_BIT(ch->affected_by, AFF_INVISIBLE); } if (IS_AFFECTED(ch, AFF_CHARM)) return FALSE; /* cannot be following someone */ if (ch->master) return FALSE; if (ch->leader == NULL) return FALSE; if (number_percent() > to_act) return FALSE; if ( (paf = affect_find(ch->affected, gsn_timer)) != NULL && paf->duration <= 1){ send_to_char("Your magic eye has expired.\n\r", ch->leader); act("$n disappears in a flash of energy.", ch, NULL, NULL, TO_ROOM); extract_char(ch, TRUE); return FALSE; } /* scan area for baddies */ if(IS_AFFECTED(ch, AFF_BLIND)){ return FALSE; } if (IS_AFFECTED2(ch,AFF_TERRAIN)){ return FALSE; } if (IS_SET(ch->in_room->room_flags,ROOM_NOWHERE) && !IS_IMMORTAL(ch)){ return FALSE; } /* scan now */ if (number_percent() < 15){ act("You sense a hidden presence scan the area.", ch, NULL, NULL, TO_ROOM); broadcast(ch, "You sense someones eyes on your back...\n\r"); } buf[0] = '\0'; buf1[0] = '\0'; buf2[0] = '\0'; for ( victim = player_list; victim != NULL; victim = victim->next_player ){ if (!IS_NPC(victim) && !IS_AFFECTED2(victim,AFF_SHADOWFORM) && !IS_AFFECTED2(victim,AFF_TREEFORM) && !IS_IMMORTAL(victim) && victim != ch->leader && victim->in_room != NULL && !IS_SET(victim->in_room->room_flags,ROOM_NOWHERE) && !room_is_private(victim->in_room) && victim->in_room->area == ch->in_room->area && !is_affected(victim,gsn_coffin) && !is_affected(victim,gsn_entomb) && !IS_AFFECTED2(victim,AFF_CATALEPSY) && is_pk(ch->leader, victim) && can_see( ch, victim ) && can_meye_report(victim, ch->leader->name, gsn_magic_eye)) { AFFECT_DATA af; sprintf(buf2, "%s%s", (fFound? ", ":""), PERS(victim, ch)); fFound = TRUE; strcat(buf1, buf2); /* mark the person so we do not report them for a while */ af.type = gsn_magic_eye; af.level = ch->level; af.duration = 3; af.bitvector = 0; af.where = TO_NONE; af.location = APPLY_NONE; af.modifier =0; paf = affect_to_char( victim, &af ); string_to_affect(paf, ch->leader->name ); } } if (fFound){ sprintf(buf, "%s: Spotted %s.\n\r", PERS2(ch), buf1); send_to_char(buf, ch->leader); return TRUE; } return FALSE; } /* The scan_for_victim function recursivly looks through rooms in near area up to depth of "depth" NOTE: THE BEHAVIOR OF THE SCAN AGAINST PC/MOBS IS DICTATED BY: PC_ONLY: : chance to only target pc according to rand < PC_ONLY CABAL : If vnum of cabal, those cabal members will not be hunted. PREY_TYPE : Selector for PREY: 0 : NONE 1 : RACE 2 : RACE_ONLY (HUNTS THAT RACE AND NOTHING ELSE) 3 : CLASS 4 : CLASS_ONLY (HUNTS THAT CLASS AND NOTHING ELSE) 5 : CABAL 6 : CABAL_ONLY (HUNTS THAT CABAL AND NOTHING ELSE) PREY : Integer reference to specific prey based on PREY_TYPE Should reflect xxx_lookup from game tables. */ CHAR_DATA* scan_for_victim( CHAR_DATA* ch, ROOM_INDEX_DATA* room, const int max_depth, int depth, int PC_ONLY, bool ALIGN_CHECK, int CABAL, int PREY_TYPE, int PREY ){ CHAR_DATA* vch; int i; /* control varaibles */ bool fPC_ONLY = number_percent() <= PC_ONLY ? TRUE : FALSE; /* E-Z */ if (depth > max_depth ) return NULL; /* check for characters in room */ for (vch = room->people; vch; vch = vch->next_in_room){ /* following always reject a character */ if (vch->level < 20 || ch == vch || (IS_NPC(vch) && ch->group == vch->group) || (fPC_ONLY && IS_NPC(vch)) || (IS_NPC(vch) && ch->pIndexData->vnum == vch->pIndexData->vnum) || (ch->summoner != NULL && ch->summoner == vch) || IS_IMMORTAL(vch) || !can_see(ch, vch) || is_ghost(vch, 600) || is_safe_quiet(ch, vch)) continue; /* FRIENDLY Cabal overrides anything else as well */ if (CABAL && vch->pCabal && is_same_cabal(get_cabal_vnum( CABAL), vch->pCabal )) continue; /* prey selection overrides fALLIED selection */ if (PREY_TYPE){ bool fONLY = FALSE; int vch_prey = -1; int prey_cab = vch->pCabal ? vch->pCabal->vnum : 0; switch (PREY_TYPE){ /* RACE */ case 1: vch_prey = vch->race; break; case 2: vch_prey = vch->race; fONLY = TRUE; break; /* CLASS */ case 3: vch_prey = vch->class; break; case 4: vch_prey = vch->class; fONLY = TRUE; break; /* CABAL */ case 5: vch_prey = prey_cab; break; case 6: vch_prey = prey_cab; fONLY = TRUE; break; default: vch_prey = -1; } /* vch_prey now contains the match that we are hunting if any */ if (vch_prey != -1 && vch_prey == PREY) return vch; /* At this point we did not match a prey, check if this was a prey ONLY */ /* if so, we do not look for any other match and check next char */ if (fONLY) continue; } /* Finaly align check rejection */ if (ALIGN_CHECK){ if ( (IS_EVIL(ch) && IS_EVIL(vch) && number_percent() < 40) || (IS_GOOD(ch) && IS_GOOD(vch) && number_percent() < 40) || ch->race == vch->race || (IS_UNDEAD(ch) && IS_UNDEAD(vch)) ) continue; } return vch; } /* No valid characters found in this room, move on to adjacent rooms */ for ( i= 0; i < MAX_DOOR; i++){ EXIT_DATA *pexit; if ((pexit = room->exit[i]) == NULL) continue; if (pexit->to_room == NULL || IS_MARKED( pexit->to_room )) continue; if (IS_SET(pexit->to_room->area->area_flags, AREA_MUDSCHOOL)) continue; /* Mark the room for rejection */ MARK( room ); vch = scan_for_victim(ch, pexit->to_room, max_depth, depth + 1, PC_ONLY, ALIGN_CHECK, CABAL, PREY_TYPE, PREY); UNMARK( room ); if (vch) return vch; } return NULL; } /* function responsible for hunter killer behavior NOTE: THE BEHAVIOR OF THE SCAN AGAINST PC/MOBS IS DICTATED BY: PC_ONLY: : chance to only target pc according to rand < PC_ONLY CABAL : If vnum of cabal, those cabal members will not be hunted. PREY_TYPE : Selector for PREY: 0 : NONE (PREY is the movement range) 1 : RACE 2 : RACE_ONLY (HUNTS THAT RACE AND NOTHING ELSE) 3 : CLASS 4 : CLASS_ONLY (HUNTS THAT CLASS AND NOTHING ELSE) 5 : CABAL 6 : CABAL_ONLY (HUNTS THAT CABAL AND NOTHING ELSE) PREY : Integer reference to specific prey based on PREY_TYPE Should reflect xxx_lookup from game tables. */ bool hunter_killer(CHAR_DATA* ch, int PC_ONLY, bool fALLIED, bool fWARP, bool fCITYWARP, int CABAL, int PREY_TYPE, int PREY){ extern char * const dir_name[]; ROOM_INDEX_DATA* to_room, *last_room; int max_depth = PREY_TYPE == 0 ? PREY : 15; //Maximum rooms away that new prey will found const int max_hunt = 30; //Max distance for detecting hunted int max_steps = PREY_TYPE == 0 ? PREY : 10; //Max number of steps to be taken at once int steps = 0; int door = 0; CHAR_DATA* victim = NULL; /* The function checks all rooms surrounding it up to depth of "depth" in recursive fashion. If a valid target is found (ch of level > 20) the mob fakes "moving" there by shoting few messages, and then teleporting in. */ if (ch->fighting) return TRUE; /* all this is skipped if we are already hunting someone. In such case, we check if the hunted is within the max_hut range to follow him and if so, we follow max_fol steps. Otherwise we stop hunting */ if (ch->hunting != NULL){ /* check for distance */ victim = ch->hunting; if (find_first_step(ch->in_room, victim->in_room, max_hunt, TRUE, NULL) < 0){ act("$n begins to look for a new prey.", ch, NULL, NULL, TO_ROOM); act("You begin to look for a new prey.", ch, NULL, NULL, TO_CHAR); ch->hunting = NULL; return TRUE; } } else victim = scan_for_victim(ch, ch->in_room, max_depth, 0, PC_ONLY, fALLIED, CABAL, PREY_TYPE, PREY); /* At this point if a victim is not found we look for pc's are left in area */ if (victim == NULL ){ CHAR_DATA* vch; if (ch->in_room->area->nplayer > 0){ for ( vch = player_list; vch != NULL; vch = vch->next_player ){ if (!IS_IMMORTAL(vch) && vch->in_room && ch->in_room && vch->in_room->area == ch->in_room->area) break; } } else vch = NULL; /* now we know if there are ANY valid pc's in the area */ /* if there is no one in the area and the mob is set to warp or warpcity */ /* the mob moves to any area */ if (vch == NULL && (fWARP || fCITYWARP)){ AREA_DATA* pArea; AREA_DATA* areas[top_area]; int max_area = -1; /* run through area vnums and make sure they are ok to be selected */ for (pArea = area_first; pArea; pArea = pArea->next){ if (IS_SET(pArea->area_flags, AREA_MUDSCHOOL) || IS_SET(pArea->area_flags, AREA_RESTRICTED)) continue; if (fCITYWARP && !IS_SET(pArea->area_flags, AREA_CITY)) continue; areas[++max_area] = pArea; } /* Now we warp to a random room in the area selected */ if (max_area > -1){ AREA_DATA* pArea = areas[number_range(0, max_area)]; ROOM_INDEX_DATA* pRoomIndex; ROOM_INDEX_DATA* rooms[pArea->max_vnum - pArea->min_vnum]; int max_room = -1; int vnum = 0; for ( vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++ ){ if ( ( pRoomIndex = get_room_index( vnum ) ) != NULL) rooms[++max_room] = pRoomIndex; } /* now we have an array full of valid rooms */ if (max_room > -1){ /* warp away */ ROOM_INDEX_DATA* pRoomIndex = rooms[number_range(0, max_room)]; act("$n disappears suddenly!", ch, NULL, NULL, TO_ROOM); char_from_room(ch); act("$n appears suddenly!", ch, NULL, NULL, TO_ROOM); char_to_room(ch, pRoomIndex); return TRUE; } } } } /* If we have not warped we wander */ if (victim == NULL && !IS_SET(ch->act, ACT_WANDER)) return TRUE; /* get the room to move to */ if (victim) to_room = victim->in_room; else{ /* select a random exit to leave through */ EXIT_DATA* pexit; int pre_doors[MAX_DOOR]; int doors[MAX_DOOR]; int pre_max_door = -1; int max_door = -1; int last_door = -1 * ch->status; int i = 0; /* put valid exits into array */ for (i = 0; i < MAX_DOOR; i++){ if ((pexit = ch->in_room->exit[i]) == NULL) continue; if (pexit->to_room == NULL) continue; if (IS_SET(pexit->to_room->area->area_flags, AREA_MUDSCHOOL) || IS_SET(pexit->to_room->area->area_flags, AREA_RESTRICTED)) continue; if (IS_SET(pexit->exit_info, EX_NOPASS)) continue; pre_doors[++pre_max_door] = i; } /* we use status to preven doubling back to the room we came from unless that is the only valid exit (only if there is more then 1 exit) */ last_door = rev_dir[last_door]; for (i = 0; i <= pre_max_door; i++){ if (pre_max_door > 0 && pre_doors[i] == last_door) continue; else doors[++max_door] = pre_doors[i]; } /* now we have all the valid doors in array */ if (max_door < 0) return TRUE; else{ int door = doors[number_range(0, max_door)]; /* status used above to make sure the mob doesnt walk back and forth */ ch->status = -1 * door; to_room = ch->in_room->exit[door]->to_room; } } /* start moving */ while (ch->in_room != to_room && steps < max_steps){ steps++; door = UMAX(0, find_first_step(ch->in_room, to_room, max_hunt, TRUE, NULL)); if (door < 0 || door > MAX_DOOR) return FALSE; if ( ch->in_room->exit[door] && ch->in_room->exit[door]->to_room && IS_SET( ch->in_room->exit[door]->exit_info, EX_CLOSED ) && !(IS_AFFECTED(ch,AFF_PASS_DOOR) && !IS_SET(ch->in_room->exit[door]->exit_info,EX_NOPASS)) ){ do_open( ch, (char *) dir_name[door] ); } if (IS_SET(ch->in_room->exit[door]->to_room->room_flags, ROOM_NO_MOB)) return TRUE; last_room = ch->in_room; move_char( ch, door, FALSE ); /* check if died */ if (!ch->in_room) return FALSE; if (ch->in_room == last_room) return TRUE; } /* attack if had victim */ if (victim == NULL) return TRUE; if (ch->in_room != victim->in_room) return TRUE; /* if (IS_NPC(victim)){ REMOVE_BIT(victim->comm,COMM_NOCHANNELS); REMOVE_BIT(victim->comm,COMM_NOYELL); } */ /* instead of attackign we run a TRIG_SPECIAL check, and let the mobprog do whatever it wants */ if (IS_NPC(ch)){ if (HAS_TRIGGER_MOB(ch, TRIG_SPECIAL)) p_percent_trigger( ch, NULL, NULL, victim, NULL, NULL, TRIG_SPECIAL); } else do_murder(ch, victim->name); /* if (IS_NPC(victim)){ SET_BIT(victim->comm,COMM_NOCABAL); SET_BIT(victim->comm,COMM_NOYELL); } */ return TRUE; } /* This is a spec function for mobs that will cause them to look for victims in immediate area NOTE: THE BEHAVIOR OF THE HUNTER AGAINST PC/MOBS IS DICTATED BY MANA and GROUP GROUP : If vnum of cabal, non of those cabal members will be hunted. mana[DICE_NUMBER] : Chance for PC ONLY mana[DICE_TYPE] : Selector for DICE BONUS: 0 : NONE (DICE_BONUS becomes the movement range) 1 : RACE 2 : CLASS 3 : CABAL 4 : RACE _ONLY 5 : CLASS_ONLY 6 : CABAL_ONLY mana[DICE_BONUS] : Integer reference to specific prey based on mana[DICE_TYPE]. Should reflect xxx_lookup from game tables. */ bool spec_hunter_nonallied(CHAR_DATA *ch){ bool fALLIED = FALSE; bool fCITYWARP = FALSE; bool fWARP = FALSE; int PC_ONLY = ch->pIndexData->mana[DICE_NUMBER]; int CABAL = ch->group; int PREY_TYPE = ch->pIndexData->mana[DICE_TYPE]; int PREY = ch->pIndexData->mana[DICE_BONUS]; return hunter_killer(ch, PC_ONLY, fALLIED, fWARP, fCITYWARP, CABAL, PREY_TYPE, PREY); } bool spec_hunter_nonallied_warp(CHAR_DATA *ch){ bool fALLIED = FALSE; bool fCITYWARP = FALSE; bool fWARP = TRUE; int PC_ONLY = ch->pIndexData->mana[DICE_NUMBER]; int CABAL = ch->group; int PREY_TYPE = ch->pIndexData->mana[DICE_TYPE]; int PREY = ch->pIndexData->mana[DICE_BONUS]; return hunter_killer(ch, PC_ONLY, fALLIED, fWARP, fCITYWARP, CABAL, PREY_TYPE, PREY); } bool spec_hunter_nonallied_cwarp(CHAR_DATA *ch){ bool fALLIED = FALSE; bool fCITYWARP = TRUE; bool fWARP = TRUE; int PC_ONLY = ch->pIndexData->mana[DICE_NUMBER]; int CABAL = ch->group; int PREY_TYPE = ch->pIndexData->mana[DICE_TYPE]; int PREY = ch->pIndexData->mana[DICE_BONUS]; return hunter_killer(ch, PC_ONLY, fALLIED, fWARP, fCITYWARP, CABAL, PREY_TYPE, PREY); } bool spec_hunter_allied(CHAR_DATA *ch){ bool fALLIED = TRUE; bool fCITYWARP = FALSE; bool fWARP = FALSE; int PC_ONLY = ch->pIndexData->mana[DICE_NUMBER]; int CABAL = ch->group; int PREY_TYPE = ch->pIndexData->mana[DICE_TYPE]; int PREY = ch->pIndexData->mana[DICE_BONUS]; return hunter_killer(ch, PC_ONLY, fALLIED, fWARP, fCITYWARP, CABAL, PREY_TYPE, PREY); } bool spec_hunter_allied_warp(CHAR_DATA *ch){ bool fALLIED = TRUE; bool fCITYWARP = FALSE; bool fWARP = TRUE; int PC_ONLY = ch->pIndexData->mana[DICE_NUMBER]; int CABAL = ch->group; int PREY_TYPE = ch->pIndexData->mana[DICE_TYPE]; int PREY = ch->pIndexData->mana[DICE_BONUS]; return hunter_killer(ch, PC_ONLY, fALLIED, fWARP, fCITYWARP, CABAL, PREY_TYPE, PREY); } bool spec_hunter_allied_cwarp(CHAR_DATA *ch){ bool fALLIED = TRUE; bool fCITYWARP = TRUE; bool fWARP = TRUE; int PC_ONLY = ch->pIndexData->mana[DICE_NUMBER]; int CABAL = ch->group; int PREY_TYPE = ch->pIndexData->mana[DICE_TYPE]; int PREY = ch->pIndexData->mana[DICE_BONUS]; return hunter_killer(ch, PC_ONLY, fALLIED, fWARP, fCITYWARP, CABAL, PREY_TYPE, PREY); } /* makes the mob change damage type to suit the vuln */ bool spec_terminator(CHAR_DATA *ch){ CHAR_DATA* vch; int vuln = 0; int norm = 0; int i = 0; if (ch->fighting == NULL) return FALSE; else vch = ch->fighting; if (get_eq_char(ch,WEAR_WIELD) != NULL) return FALSE; /* we run through the hit table looking for vuln match */ for (i = 0; i < MAX_DAMAGE_MESSAGE; i++ ){ int type = attack_table[i].damage; if (type < 0 || type == DAM_INTERNAL) continue; if (check_immune(vch, type, FALSE) > IS_NORMAL){ vuln = i; break; } if (norm) continue; if (check_immune(vch, type, FALSE) == IS_NORMAL){ norm = i; } } /* now we have either norm or vuln */ if (vuln){ if (vuln != ch->dam_type){ act("$n changes $s weapon.", ch, NULL, NULL, TO_ROOM); act("You change your weapon.", ch, NULL, NULL, TO_CHAR); ch->dam_type = vuln; } } else if (norm && norm != ch->dam_type){ act("$n changes $s weapon.", ch, NULL, NULL, TO_ROOM); act("You change your weapon.", ch, NULL, NULL, TO_CHAR); ch->dam_type = norm; } return TRUE; } void do_star_seer( CHAR_DATA *ch, char *argument ){ AFFECT_DATA af; OBJ_DATA* obj; AREA_DATA* pArea; char buf[MIL]; char* text; const int max_obj = 16; int max = 0; OBJ_DATA* objects[max_obj]; const int sn = skill_lookup("locate object"); if (!IS_NPC(ch)){ return; } if (is_affected(ch, sn)){ do_say(ch, "I fear I am too tired child. Seek my help in few days time."); return; } af.type = sn; af.level = 60; af.duration = 12; af.where = TO_NONE; af.bitvector = 0; af.location = APPLY_NONE; af.modifier = 0; for ( obj = object_list; obj != NULL; obj = obj->next ){ if (obj->pIndexData->vnum == OBJ_VNUM_STARSTONE && obj->in_room != NULL && max < max_obj) objects[max++] = obj; } act("$n closes her eyes and kneels and begins to chant a holy psalm.", ch, NULL, NULL, TO_ROOM); if (max && number_percent() < 75){ do_say(ch, "Darkness I see.. Darkness everywhere.. Wait!"); affect_to_char(ch, &af); } else{ do_say(ch, "Darkness I see.. Darkness everywhere.."); act("$n opens here eyes and stands up.", ch, NULL, NULL, TO_ROOM); do_say(ch, "I'm sorry child, but He did not grant me a vision."); af.duration /= 4; affect_to_char(ch, &af); return; } /* get random obj */ obj = objects[number_range(0, max - 1)]; /* get random area to mention */ if ( (pArea = get_rand_aexit(obj->in_room->area)) == NULL) pArea = obj->in_room->area; /* compose the text to say */ switch (obj->in_room->sector_type){ default: text = "lies on the ground" ; break; case SECT_INSIDE: text = "lies indoors" ; break; case SECT_CITY: text = "rests on a sidewalk" ; break; case SECT_FIELD: text = "lies in grass" ; break; case SECT_FOREST: text = "lies in bush" ; break; case SECT_HILLS: text = "lies on a hill" ; break; case SECT_MOUNTAIN: text = "lies amongst stones" ; break; case SECT_WATER_SWIM: text = "lies in depths" ; break; case SECT_WATER_NOSWIM:text = "lies in water" ; break; case SECT_SWAMP: text = "lies in mud" ; break; case SECT_AIR: text = "falls through air" ; break; case SECT_DESERT: text = "lies in sand" ; break; case SECT_LAVA: text = "lies in fire" ; break; case SECT_SNOW: text = "lies in ice" ; break; } sprintf(buf, "I.. I see a starstone.. It %s and a specter of %s looms on the horizon.", text, pArea->name); do_say(ch, buf); act("$n arises and opens $s eyes.", ch, NULL, NULL, TO_ROOM); do_say(ch, "I'm sorry child, but that is all He has shown me."); } void do_obelisk_seer( CHAR_DATA *ch, char *argument ){ AFFECT_DATA af; OBJ_DATA* obj; AREA_DATA* pArea; char buf[MIL]; char* text; const int max_obj = 32; int max = 0; OBJ_DATA* objects[max_obj]; const int sn = skill_lookup("locate object"); if (!IS_NPC(ch)){ return; } if (is_affected(ch, sn)){ do_say(ch, "I fear I am too tired child. Seek my help in few days time."); return; } af.type = sn; af.level = 60; af.duration = 12; af.where = TO_NONE; af.bitvector = 0; af.location = APPLY_NONE; af.modifier = 0; for ( obj = object_list; obj != NULL; obj = obj->next ){ if (is_name("crusader_obelisk", obj->name) && obj->in_room != NULL && max < max_obj) objects[max++] = obj; } act("$n closes her eyes and kneels and begins to chant a holy psalm.", ch, NULL, NULL, TO_ROOM); if (max && number_percent() < 75){ do_say(ch, "Darkness I see.. Darkness everywhere.. Wait!"); affect_to_char(ch, &af); } else{ do_say(ch, "Darkness I see.. Darkness everywhere.."); act("$n opens here eyes and stands up.", ch, NULL, NULL, TO_ROOM); do_say(ch, "I'm sorry child, but He did not grant me a vision."); af.duration /= 4; affect_to_char(ch, &af); return; } /* get random obj */ obj = objects[number_range(0, max - 1)]; /* get random area to mention */ if ( (pArea = get_rand_aexit(obj->in_room->area)) == NULL) pArea = obj->in_room->area; /* compose the text to say */ switch (obj->in_room->sector_type){ default: text = "stands on the ground" ; break; case SECT_INSIDE: text = "stands indoors" ; break; case SECT_CITY: text = "stands on a sidewalk" ; break; case SECT_FIELD: text = "stands in grass" ; break; case SECT_FOREST: text = "stands in bush" ; break; case SECT_HILLS: text = "stands on a hill" ; break; case SECT_MOUNTAIN: text = "stands amongst stones" ; break; case SECT_WATER_SWIM: text = "rests in depths" ; break; case SECT_WATER_NOSWIM:text = "stands in water" ; break; case SECT_SWAMP: text = "stands in mud" ; break; case SECT_AIR: text = "floats through air" ; break; case SECT_DESERT: text = "stands in sand" ; break; case SECT_LAVA: text = "stands in fire" ; break; case SECT_SNOW: text = "stands in ice" ; break; } sprintf(buf, "I.. I see a giant obelisk.. It %s in %s..", text, obj->in_room->name); do_say(ch, buf); sprintf(buf, "and a specter of %s looms on the horizon.", pArea->name); do_say(ch, buf); act("$n arises and opens $s eyes.", ch, NULL, NULL, TO_ROOM); do_say(ch, "I'm sorry child, but that is all He has shown me."); } /* checks if any demons, undead, or vendetta cabaled chars are in the first area this char's cabal connects to */ bool spec_knight_seer(CHAR_DATA *ch){ AREA_DATA* pa = NULL; CHAR_DATA* vch; EXIT_DATA* pExit; AFFECT_DATA af; int door = 0; bool fEnemy = FALSE; bool fDemon = FALSE; bool fUndead = FALSE; char buf[MIL]; if (ch->pCabal == NULL || ch->pCabal->present < 1) return FALSE; else if (ch->pCabal->anchor == NULL) return FALSE; else if (is_affected(ch, gsn_identify)) return FALSE; /* get the area this cabal connects to */ for ( door = 0; door < MAX_DOOR; door ++ ){ pExit = ch->pCabal->anchor->exit[door]; if (pExit == NULL || pExit->to_room == NULL) continue; if (pExit->to_room->area == ch->pCabal->anchor->area) continue; pa = pExit->to_room->area; break; } if (pa == NULL || pa->nplayer < 1) return FALSE; /* we have the area, run through players that are in there */ for (vch = player_list; vch; vch = vch->next_player ){ if (vch->in_room == NULL || vch->in_room->area != pa ) continue; if (IS_UNDEAD(vch)) fUndead = TRUE; else if (IS_DEMON(vch)) fDemon = TRUE; if (vch->pCabal && is_friendly(vch->pCabal, ch->pCabal) == CABAL_ENEMY) fEnemy = TRUE; if ( fUndead && fDemon && fEnemy) break; } if (!fUndead && !fDemon && !fEnemy) return FALSE; /* print the message */ if (fEnemy) sprintf( buf, "[%s]: 'Beware.. An enemy draws near!'", PERS2(ch)); else if (fUndead && fDemon) sprintf( buf, "[%s]: 'Beware.. An Unholy and Demonic presence draws near!'", PERS2(ch)); else if (fUndead) sprintf( buf, "[%s]: 'Beware.. An Unholy presence draws near!'", PERS2(ch)); else if (fDemon) sprintf( buf, "[%s]: 'Beware.. A Demonic presence draws near!'", PERS2(ch)); else sprintf( buf, "[%s]: 'I sense a presence that I should not!'", PERS2(ch)); cabal_echo(ch->pCabal, buf ); /* wait so we do not spam */ af.type = gsn_identify; af.level = 60; af.duration = 12; af.where = TO_NONE; af.bitvector = 0; af.location = APPLY_NONE; af.modifier = 0; affect_to_char( ch, &af); return TRUE; } bool spec_nexus_nemesis(CHAR_DATA *ch){ CHAR_DATA* victim = NULL; ROOM_INDEX_DATA* pRoom = NULL; /* decides the behavior of nemesis, teleports to rooms near its target if not in same area */ if (ch->hunting == NULL && ch->fighting == NULL && (ch->in_room && ch->in_room->vnum != ch->homevnum)){ act("$n grins with satisfaction as its form looses all detail and fades away.", ch, NULL, NULL, TO_ROOM ); extract_char( ch, TRUE ); return TRUE; } else{ victim = ch->hunting; ch->hunttime = 999; } if (victim == NULL || victim->in_room == NULL || victim->in_room->vnum == ROOM_VNUM_LIMBO) return FALSE; /* now the acutal hunt part */ if (victim->in_room->area != ch->in_room->area && number_percent() < 35){ /* we get a random room that leads into this room to move to */ ROOM_INDEX_DATA* exits[MAX_DOOR]; EXIT_DATA* pe; int last_exit = 0; int door = 0; for (door = 0; door < MAX_DOOR; door ++ ){ if ( (pe = victim->in_room->exit[door]) == NULL) continue; if (pe->to_room->exit[rev_dir[door]] == NULL || pe->to_room->exit[rev_dir[door]]->to_room != victim->in_room) continue; exits[last_exit++] = pe->to_room; } if (last_exit < 1) pRoom = NULL; else pRoom = exits[number_range(0, last_exit - 1)]; if (pRoom){ act("$n phases out and disappears.", ch, NULL, NULL, TO_ROOM); char_from_room( ch ); char_to_room( ch, pRoom ); act("$n phases in and flashes a terrible grin.", ch, NULL, NULL, TO_ROOM); return FALSE; } } return FALSE; } void path_walk( CHAR_DATA* ch ){ PATH_QUEUE* path, *curr, *prev = NULL; ROOM_INDEX_DATA* room_old; int temp_trust = ch->trust; path = ch->spec_path; if (ch->fighting || path == NULL) return; //make sure pets with a path stop if they enter their master's room else if (IS_AFFECTED(ch, AFF_CHARM) && ch->master && ch->master->in_room == ch->in_room){ clean_path_queue(ch->spec_path); ch->spec_path = NULL; return; } /* exit this room, and enter next room */ curr = path; prev = curr; /* try to use move_char first, if that doesn't work force the action */ if (ch->in_room != curr->room){ ch->trust = 6969; room_old = ch->in_room; move_char( ch, (int)curr->from_dir, TRUE ); if (ch->in_room == NULL) return; else if (ch->fighting) return; else if (ch->in_room == room_old || ch->in_room != curr->room){ act("$n leaves $t.", ch, dir_name[(int)path->from_dir], NULL, TO_ALL); char_from_room( ch ); char_to_room( ch, curr->room ); act("$n enters.", ch, dir_name[(int)path->from_dir], NULL, TO_ALL); } ch->trust = temp_trust; if (IS_AFFECTED(ch, AFF_CHARM) && ch->master && ch->master->in_room == ch->in_room){ clean_path_queue(ch->spec_path); ch->spec_path = NULL; return; } } /* repoint current path for next run*/ ch->spec_path = curr->next; if (prev){ prev->next = NULL; clean_path_queue( path ); } /* run spec prog if we are at end */ if ( (ch->spec_path == NULL || ch->spec_path->room == NULL) && HAS_TRIGGER_MOB(ch, TRIG_SPECIAL)){ p_percent_trigger( ch, NULL, NULL, ch, NULL, NULL, TRIG_SPECIAL); } return; } /* walk along set path in ->spec_data pointer, takes ->mana[DICE_NUMBER] steps */ bool spec_path_walk(CHAR_DATA *ch){ int i; for (i = 0; i < UMAX(1, ch->pIndexData->mana[DICE_NUMBER]); i++){ path_walk( ch ); if (ch == NULL || ch->in_room == NULL) return FALSE; } return TRUE; } /* controls behavior of raider mobs * In order of decision: * 0) If area is not city do nothing * 1) If a lawful mob is present attack it * 2) If a mob is present of level <= 50 attack it * 3) if we roll success vs torch_chance, torch the area * - All mobs run away/die * - A VNUM_OBJ_RAID is created in room * - ch->pCabal gains cps and support * - cabal owner of area loses cps and support * - if area lawful, justice loses cps and support * 4) If we have no path, select new destination in area */ bool spec_raider_actions(CHAR_DATA *ch){ CHAR_DATA* vch, *vch_next, *lawful = NULL, *target = NULL; char buf[MIL]; OBJ_DATA* obj; int torch_chance = 20; const int dur = 24; int cps_dam; int sup_dam; //from this point on we have to be in a city or cabal home if ( !IS_AREA(ch->in_room->area, AREA_CITY) && !IS_AREA(ch->in_room->area, AREA_CABAL)) return FALSE; if (ch->in_room == NULL) return FALSE; else if (ch->fighting) return FALSE; //check for mobs present in the room for (vch = ch->in_room->people; vch; vch = vch->next_in_room ){ if (!IS_NPC(vch) || IS_AFFECTED(vch, AFF_CHARM) || vch == ch || IS_SET(vch->act, ACT_RAIDER) || is_same_cabal(ch->pCabal, vch->pCabal)) continue; else if (!can_see( ch, vch)) continue; else if (vch->level > 50 || IS_SET(vch->act, ACT_NOPURGE) || IS_SET(vch->act, ACT_TOO_BIG)){ torch_chance = 100; continue; } else if (IS_SET(vch->act2, ACT_LAWFUL)) lawful = vch; else if (vch->pCabal && !is_same_cabal(ch->pCabal, vch->pCabal)) target = vch; else target = vch; } //check if we have a lawful mob to attack if (lawful) vch = lawful; else if (target) vch = target; else vch = NULL; if (vch){ sprintf(buf, "Help! I am being attacked by %s!",PERS(ch,vch)); REMOVE_BIT(vch->comm, COMM_NOYELL); do_yell(vch, buf); SET_BIT(vch->comm, COMM_NOYELL); multi_hit( ch, vch, TYPE_UNDEFINED ); return TRUE; } for (obj = ch->in_room->contents; obj; obj = obj->next_content){ if (obj->vnum == OBJ_VNUM_RAID_OBJECT) break; } //in cabals the raiders can re-troch if (obj == NULL || (IS_AREA(ch->in_room->area, AREA_CABAL) && obj->timer < dur - 2)){ /* no targets to attack */ if (number_percent() > torch_chance) return FALSE; /* torch the place */ if (obj != NULL){ obj->timer = dur; act("$n happily continues torching the surroundings.", ch, NULL, NULL, TO_ROOM); } else{ act("Cackling with glee, $n sets the area ablaze.", ch, NULL, NULL, TO_ROOM); //create some rubble make_item_char(ch, OBJ_VNUM_RAID_OBJECT, dur); } //hurt reations if (ch->pCabal && ch->in_room->area->pCabal){ affect_cabal_relations(ch->pCabal, ch->in_room->area->pCabal, -PACT_MAX_RATING / 20, TRUE ); } //set area flag if (ch->in_room->area->raid != NULL) SET_BIT(ch->in_room->area->area_flags, AREA_RAID); //force npcs to die in the blaze for (vch = ch->in_room->people; vch; vch = vch_next){ vch_next = vch->next_in_room ; if (!IS_NPC(vch) || IS_AFFECTED(vch, AFF_CHARM) || vch == ch || (vch->pCabal && vch->pCabal->altar == vch) || IS_SET(vch->off_flags,CABAL_GUARD) || IS_SET(vch->act, ACT_RAIDER) || is_same_cabal(ch->pCabal, vch->pCabal)) continue; act("$n dies, trapped in the blazing rubble!", vch, NULL, NULL, TO_ROOM); extract_char( vch, TRUE ); } sup_dam = number_range(1, 6 * CABAL_FULL_SUPPORT) / 6; cps_dam = number_range( CPTS, 2 * CPTS); /* HANDLE support-cp gain/loss */ sup_dam = number_range(1, 6 * CABAL_FULL_SUPPORT) / 6; cps_dam = number_range( CPTS, 2 * CPTS); /* LOSS-GAIN */ if (ch->pCabal && ch->in_room->area->pCabal && is_friendly(ch->pCabal, ch->in_room->area->pCabal) == CABAL_ENEMY){ //if target area has cabal with no members lower gain if (ch->in_room->area->pCabal->present < 1){ sup_dam = sup_dam / 3; cps_dam = cps_dam / 3; } /* LOSS */ if (ch->in_room->area->pCabal->present > 0){ ch->in_room->area->pCabal->raid_sup -= sup_dam; ch->in_room->area->pCabal->raid_cps -= cps_dam; } /* GAIN */ ch->pCabal->raid_sup += sup_dam; ch->pCabal->raid_cps += cps_dam; } if (IS_AREA(ch->in_room->area, AREA_LAWFUL)){ justice_raid_gain( -sup_dam / 2, -cps_dam / 2 ); } } //set a new path else if (ch->spec_path == NULL){ ROOM_INDEX_DATA* pTo; ROOM_INDEX_DATA* pFrom = ch->in_room; PATH_QUEUE* path; int sectors[2] = {SECT_CITY, SECT_INSIDE}; int area_pool = 10; int dist = 0; pTo = get_rand_room(pFrom->area->vnum,pFrom->area->vnum,//area range (0 to ignore) 0,0, //room ramge (0 to ignore) 0,0, //areas to choose from NULL,0, //areas to exclude sectors,2, //sectors required NULL,0, //sectors to exlude NULL,0, //room1 flags required 0,0, //room1 flags to exclude NULL,0, //room2 flags required NULL,0, //room2 flags to exclude area_pool, //number of seed areas TRUE, //exit required? FALSE, //Safe? NULL); //Character for room checks if (pTo == NULL || pTo == pFrom) return FALSE; //see if we can get a path between the two rooms if ( (path = generate_path( pFrom, pTo, 256, TRUE, &dist, NULL)) == NULL){ clean_path(); return FALSE; } else clean_path(); ch->spec_path = path; return FALSE; } return FALSE; }; //handles the destruction of a room bool awakenlife_roomdestroy( CHAR_DATA* ch, ROOM_INDEX_DATA* room ){ CHAR_DATA* vch, *vch_next, *lawful = NULL, *target = NULL; OBJ_DATA* obj; char buf[MIL]; const int dur = 24; int cps_dam, sup_dam; /* Rules for destruction: 1) Any mobs of rank 50 and lower are attacked 2) Mobs higher then 50 or ones that have NO_PURGE are destroyed 3) CP gain/loss is 1:1 for victim cabal vs owner of mob */ //check for mobs present in the room for (vch = room->people; vch; vch = vch->next_in_room ){ if (!IS_NPC(vch) || IS_SET(vch->act, ACT_NONCOMBAT) || IS_AFFECTED(vch, AFF_CHARM) || vch == ch || IS_SET(vch->act, ACT_RAIDER) || is_same_cabal(ch->pCabal, vch->pCabal)) continue; else if (!can_see( ch, vch)) continue; else if (vch->level > 50 || IS_SET(vch->act, ACT_NOPURGE) || IS_SET(vch->act, ACT_TOO_BIG)){ continue; } else if (IS_SET(vch->act2, ACT_LAWFUL)) lawful = vch; else if (vch->pCabal && !is_same_cabal(ch->pCabal, vch->pCabal) && is_friendly(ch->pCabal, vch->pCabal) == CABAL_ENEMY) target = vch; else target = vch; } //check if we have a lawful mob to attack if (lawful) vch = lawful; else if (target) vch = target; else vch = NULL; //If we have a mob to attack attack it now if (vch){ sprintf(buf, "Help! I am being attacked by %s!",PERS(ch,vch)); REMOVE_BIT(vch->comm, COMM_NOYELL); do_yell(vch, buf); SET_BIT(vch->comm, COMM_NOYELL); multi_hit( ch, vch, TYPE_UNDEFINED ); return FALSE; } /* BELOW THIS POINT HAPPENDS ONLY IF THERE ARE NO MOBS TO ATTACK */ //check for rubble from previous destruction for (obj = ch->in_room->contents; obj; obj = obj->next_content){ if (obj->vnum == OBJ_VNUM_RAID_OBJECT) break; } //in cabals the monster can re-troch if (obj == NULL || (IS_AREA(ch->in_room->area, AREA_CABAL) && obj->timer < dur - 2)){ /* torch the place */ if (obj != NULL){ obj->timer = dur; act("Roaring with rage $n destroys the remains of the area..", ch, NULL, NULL, TO_ROOM); } else{ act("Roaring with rage $n reduces the area to rubble.", ch, NULL, NULL, TO_ROOM); //create some rubble make_item_char(ch, OBJ_VNUM_RAID_OBJECT, dur); } //hurt reations if (ch->pCabal && ch->in_room->area->pCabal){ affect_cabal_relations(ch->pCabal, ch->in_room->area->pCabal, -PACT_MAX_RATING / 20, TRUE ); } //force npcs to die in the blaze for (vch = ch->in_room->people; vch; vch = vch_next){ vch_next = vch->next_in_room ; if (!IS_NPC(vch) || (vch->pCabal && vch->pCabal->altar == vch) || IS_SET(vch->act, ACT_NONCOMBAT) || IS_SET(vch->act, ACT_IS_HEALER) || IS_AFFECTED(vch, AFF_CHARM) || vch == ch || IS_SET(vch->off_flags,CABAL_GUARD) || IS_SET(vch->act, ACT_RAIDER) || (vch->pCabal && is_friendly(ch->pCabal, vch->pCabal) != CABAL_ENEMY)) continue; act("$n dies, trapped in the blazing rubble!", vch, NULL, NULL, TO_ROOM); extract_char( vch, TRUE ); } /* HANDLE support-cp gain/loss */ if (IS_AREA(ch->in_room->area, AREA_CITY) || IS_AREA(ch->in_room->area, AREA_CABAL)){ sup_dam = number_range(1, 10); cps_dam = number_range( 2 * CPTS, 4 * CPTS); } else{ sup_dam = 0; cps_dam = 0; } /* LOSS-GAIN */ if (ch->pCabal && ch->in_room->area->pCabal && is_friendly(ch->pCabal, ch->in_room->area->pCabal) == CABAL_ENEMY){ //if target area has cabal with no members lower gain if (ch->in_room->area->pCabal->present < 1){ sup_dam = sup_dam / 3; cps_dam = cps_dam / 3; } /* LOSS */ if (ch->in_room->area->pCabal->present > 0){ ch->in_room->area->pCabal->raid_sup -= sup_dam; ch->in_room->area->pCabal->raid_cps -= cps_dam; } /* GAIN */ ch->pCabal->raid_sup += sup_dam; if (ch->summoner != NULL) CPS_GAIN( ch->summoner, cps_dam, TRUE ); } //justice loss if (IS_AREA(ch->in_room->area, AREA_LAWFUL)){ justice_raid_gain( -sup_dam / 2, -cps_dam / 2 ); } } return TRUE; } //handles targetting of new destination for RAMPAGE state. void awakenlife_rampage( CHAR_DATA* ch){ ROOM_INDEX_DATA* pTo; ROOM_INDEX_DATA* pFrom = ch->in_room; int area_pool = 10; pTo = get_rand_room(pFrom->area->vnum, pFrom->area->vnum,//area range (0 to ignore) 0,0, //room ramge (0 to ignore) 0,0, //areas to choose from NULL,0, //areas to exclude NULL,0, //sectors required NULL,0, //sectors to exlude NULL,0, //room1 flags required 0,0, //room1 flags to exclude NULL,0, //room2 flags required NULL,0, //room2 flags to exclude area_pool, //number of seed areas TRUE, //exit required? FALSE, //Safe? NULL); //Character for room checks if (pTo == NULL || pTo == pFrom) return; else set_path( ch, pFrom, pTo, 256, NULL); return; } //handles behavior of the awaken life monsters. //current orders are stored in pc's status variable. bool spec_awakenlife_actions( CHAR_DATA *ch ){ int state; if (ch == NULL || ch->in_room == NULL) return FALSE; else state = ch->status; //safety to make sure the monsters are always linked. if (ch->summoner == NULL || IS_NPC(ch->summoner) || ch->summoner->pcdata->familiar != ch){ act("Not sensing its master's presence $N returns to its homeland.", ch, NULL, NULL, TO_ROOM); stop_fighting( ch, TRUE ); char_from_room( ch ); extract_char( ch, TRUE ); return TRUE; } else if (ch->pCabal && is_captured(ch->pCabal)){ act("With the $t Standard captured, $n returns to its homeland.", ch, ch->pCabal->name, NULL, TO_ROOM); stop_fighting( ch, TRUE ); char_from_room( ch ); extract_char( ch, TRUE ); return TRUE; } //do nothing if we are fighting if (ch->fighting != NULL) return FALSE; // we do nothing while moving except while on rampage else if (ch->spec_path != NULL && state != AWAKENLIFE_RAMP) return FALSE; switch (state){ //move or retreat states do nothing except move default: case AWAKENLIFE_NONE: break; case AWAKENLIFE_MOVE: case AWAKENLIFE_RETR: sendf( ch->summoner, "[%s]: Has reached the target destination.\n\r", PERS2(ch)); ch->status = AWAKENLIFE_NONE; break; //destroy and rampage state destroys the room case AWAKENLIFE_DEST: case AWAKENLIFE_RAMP: if (awakenlife_roomdestroy( ch, ch->in_room )){ if (ch != NULL && ch->in_room != NULL && state == AWAKENLIFE_DEST){ sendf( ch->summoner, "[%s]: Target destroyed.\n\r", PERS2(ch)); ch->status = AWAKENLIFE_NONE; } } //stop further execution if this mob is dead now if (ch == NULL || ch->in_room == NULL) return TRUE; //if this is rampage, get new destination if we have no path if (state == AWAKENLIFE_RAMP && ch->fighting == NULL) awakenlife_rampage( ch ); break; } return FALSE; }