/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | * * -----------------------------------------------------------| \\._.// * * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version) | (0...0) * * -----------------------------------------------------------| ).:.( * * SMAUG (C) 1994, 1995, 1996 by Derek Snider | {o o} * * -----------------------------------------------------------| / ' ' \ * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, |~'~.VxvxV.~'~* * Scryn, Swordbearer, Rennard, Tricops, and Gorog. | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * "Special procedure" module * ****************************************************************************/ #include "stdafx.h" #include "smaug.h" #include "area.h" #include "skill.h" #include "mobiles.h" #include "objects.h" #include "rooms.h" #include "descriptor.h" #include "character.h" /* * The following special functions are available for mobiles. */ 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_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_fido ); DECLARE_SPEC_FUN ( spec_guard ); DECLARE_SPEC_FUN ( spec_janitor ); DECLARE_SPEC_FUN ( spec_mayor ); DECLARE_SPEC_FUN ( spec_poison ); DECLARE_SPEC_FUN ( spec_thief ); /* * Given a name, return the appropriate spec fun. */ SPEC_FUN *spec_lookup (const char *name) { if (!str_cmp (name, "spec_breath_any" )) return spec_breath_any; if (!str_cmp (name, "spec_breath_acid" )) return spec_breath_acid; if (!str_cmp (name, "spec_breath_fire" )) return spec_breath_fire; if (!str_cmp (name, "spec_breath_frost" )) return spec_breath_frost; if (!str_cmp (name, "spec_breath_gas" )) return spec_breath_gas; if (!str_cmp (name, "spec_breath_lightning" )) return spec_breath_lightning; if (!str_cmp (name, "spec_cast_adept" )) return spec_cast_adept; if (!str_cmp (name, "spec_cast_cleric" )) return spec_cast_cleric; if (!str_cmp (name, "spec_cast_mage" )) return spec_cast_mage; if (!str_cmp (name, "spec_cast_undead" )) return spec_cast_undead; if (!str_cmp (name, "spec_executioner" )) return spec_executioner; if (!str_cmp (name, "spec_fido" )) return spec_fido; if (!str_cmp (name, "spec_guard" )) return spec_guard; if (!str_cmp (name, "spec_janitor" )) return spec_janitor; if (!str_cmp (name, "spec_mayor" )) return spec_mayor; if (!str_cmp (name, "spec_poison" )) return spec_poison; if (!str_cmp (name, "spec_thief" )) return spec_thief; return 0; } /* * Given a pointer, return the appropriate spec fun text. */ char *lookup_spec (SPEC_FUN *special) { if (special == spec_breath_any ) return "spec_breath_any"; if (special == spec_breath_acid) return "spec_breath_acid"; if (special == spec_breath_fire) return "spec_breath_fire"; if (special == spec_breath_frost ) return "spec_breath_frost"; if (special == spec_breath_gas ) return "spec_breath_gas"; if (special == spec_breath_lightning) return "spec_breath_lightning"; if (special == spec_cast_adept ) return "spec_cast_adept"; if (special == spec_cast_cleric) return "spec_cast_cleric"; if (special == spec_cast_mage ) return "spec_cast_mage"; if (special == spec_cast_undead) return "spec_cast_undead"; if (special == spec_executioner) return "spec_executioner"; if (special == spec_fido ) return "spec_fido"; if (special == spec_guard ) return "spec_guard"; if (special == spec_janitor) return "spec_janitor"; if (special == spec_mayor ) return "spec_mayor"; if (special == spec_poison ) return "spec_poison"; if (special == spec_thief ) return "spec_thief"; return ""; } /* if a spell casting mob is hating someone... try and summon them */ void summon_if_hating (CCharacter *ch) { CCharacter *victim; char buf[MAX_STRING_LENGTH]; char name[MAX_INPUT_LENGTH]; BOOL found = FALSE; if (ch->GetFightData () || ch->fearing || !ch->hating || ch->GetInRoom ()->IsSafe ()) return; /* if player is close enough to hunt... don't summon */ if (ch->hunting) return; one_argument (ch->hating->name, name); /* make sure the char exists - works even if player quits */ for (victim = first_char; victim; victim = victim->GetNext ()) { if (!str_cmp (ch->hating->name, victim->GetName ())) { found = TRUE; break; } } if (!found) return; if (ch->GetInRoom () == victim->GetInRoom ()) return; if (!victim->IsNpc ()) sprintf (buf, "summon 0.%s", name); else sprintf (buf, "summon %s", name); do_cast (ch, buf); return; } /* * Core procedure for dragons. */ BOOL dragon (CCharacter *ch, char *spell_name) { CCharacter *victim; CCharacter *v_next; int sn; if (! ch->IsFightPosition ()) return FALSE; for (victim = ch->GetInRoom ()->first_person; victim; victim = v_next) { v_next = victim->GetNextInRoom (); if (victim->GetFightWho () == ch && number_bits (2) == 0) break; } if (! victim) return FALSE; if ((sn = SkillTable.Lookup (spell_name)) < 0) return FALSE; (*SkillTable.GetSpellFunction (sn)) (sn, ch->GetLevel (), ch, victim); return TRUE; } /* * Special procedures for mobiles. */ BOOL spec_breath_any (CCharacter *ch) { if (! ch->IsFightPosition ()) 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: case 6: case 7: return spec_breath_frost (ch); } return FALSE; } BOOL spec_breath_acid (CCharacter *ch) { return dragon (ch, "acid breath"); } BOOL spec_breath_fire (CCharacter *ch) { return dragon (ch, "fire breath"); } BOOL spec_breath_frost (CCharacter *ch) { return dragon (ch, "frost breath"); } BOOL spec_breath_gas (CCharacter *ch) { int sn; if (! ch->IsFightPosition ()) return FALSE; if ((sn = SkillTable.Lookup ("gas breath")) < 0) return FALSE; (*SkillTable.GetSpellFunction (sn)) (sn, ch->GetLevel (), ch, NULL); return TRUE; } BOOL spec_breath_lightning (CCharacter *ch) { return dragon (ch, "lightning breath"); } BOOL spec_cast_adept (CCharacter *ch) { CCharacter *victim; CCharacter *v_next; if (!ch->IsAwake ()) return FALSE; for (victim = ch->GetInRoom ()->first_person; victim; victim = v_next) { v_next = victim->GetNextInRoom (); if (victim != ch && can_see (ch, victim) && number_bits (1) == 0) break; } if (!victim) return FALSE; switch (number_bits (3)) { case 0: act (AT_MAGIC, "$n utters the word 'ciroht'.", ch, NULL, NULL, TO_ROOM); spell_smaug (SkillTable.Lookup ("armor"), ch->GetLevel (), ch, victim); return TRUE; case 1: act (AT_MAGIC, "$n utters the word 'sunimod'.", ch, NULL, NULL, TO_ROOM); spell_smaug (SkillTable.Lookup ("bless"), ch->GetLevel (), ch, victim); return TRUE; case 2: act (AT_MAGIC, "$n utters the word 'suah'.", ch, NULL, NULL, TO_ROOM); spell_cure_blindness (SkillTable.Lookup ("cure blindness"), ch->GetLevel (), ch, victim); return TRUE; case 3: act (AT_MAGIC, "$n utters the word 'nran'.", ch, NULL, NULL, TO_ROOM); spell_smaug (SkillTable.Lookup ("cure light"), ch->GetLevel (), ch, victim); return TRUE; case 4: act (AT_MAGIC, "$n utters the word 'nyrcs'.", ch, NULL, NULL, TO_ROOM); spell_cure_poison (SkillTable.Lookup ("cure poison"), ch->GetLevel (), ch, victim); return TRUE; case 5: act (AT_MAGIC, "$n utters the word 'gartla'.", ch, NULL, NULL, TO_ROOM); spell_smaug (SkillTable.Lookup ("refresh"), ch->GetLevel (), ch, victim); return TRUE; } return FALSE; } BOOL spec_cast_cleric (CCharacter *ch) { CCharacter *victim; CCharacter *v_next; char *spell; int sn; summon_if_hating (ch); if (! ch->IsFightPosition ()) return FALSE; for (victim = ch->GetInRoom ()->first_person; victim; victim = v_next) { v_next = victim->GetNextInRoom (); if (victim->GetFightWho () == ch && number_bits (2) == 0) break; } if (!victim || victim == ch) return FALSE; for (;;) { int min_level; switch (number_bits (4)) { case 0: min_level = 0; spell = "blindness"; break; case 1: min_level = 3; spell = "cause serious"; break; case 2: min_level = 7; spell = "earthquake"; break; case 3: min_level = 9; spell = "cause critical"; break; case 4: min_level = 10; spell = "dispel evil"; break; case 5: min_level = 12; spell = "curse"; break; case 7: min_level = 13; spell = "flamestrike"; break; case 8: case 9: case 10: min_level = 15; spell = "harm"; break; default: min_level = 16; spell = "dispel magic"; break; } if (ch->GetLevel () >= min_level) break; } if ((sn = SkillTable.Lookup (spell)) < 0) return FALSE; (*SkillTable.GetSpellFunction (sn)) (sn, ch->GetLevel (), ch, victim); return TRUE; } BOOL spec_cast_mage (CCharacter *ch) { CCharacter *victim; CCharacter *v_next; char *spell; int sn; summon_if_hating (ch); if (! ch->IsFightPosition ()) return FALSE; for (victim = ch->GetInRoom ()->first_person; victim; victim = v_next) { v_next = victim->GetNextInRoom (); if (victim->GetFightWho () == ch && number_bits (2) == 0) break; } if (!victim || victim == ch) return FALSE; for (;;) { int min_level; switch (number_bits (4)) { case 0: min_level = 0; spell = "blindness"; break; case 1: min_level = 3; spell = "chill touch"; break; case 2: min_level = 7; spell = "weaken"; break; /* Commented out by Narn, Nov 28/95 at the request of Selic case 3: min_level = 8; spell = "teleport"; break; */ case 4: min_level = 11; spell = "colour spray"; break; case 6: min_level = 13; spell = "energy drain"; break; case 7: case 8: case 9: min_level = 15; spell = "fireball"; break; default: min_level = 20; spell = "acid blast"; break; } if (ch->GetLevel () >= min_level) break; } if ((sn = SkillTable.Lookup (spell)) < 0) return FALSE; (*SkillTable.GetSpellFunction (sn)) (sn, ch->GetLevel (), ch, victim); return TRUE; } BOOL spec_cast_undead (CCharacter *ch) { CCharacter *victim; CCharacter *v_next; char *spell; int sn; summon_if_hating (ch); if (! ch->IsFightPosition ()) return FALSE; for (victim = ch->GetInRoom ()->first_person; victim; victim = v_next) { v_next = victim->GetNextInRoom (); if (victim->GetFightWho () == ch && number_bits (2) == 0) break; } if (!victim || victim == ch) return FALSE; for (;;) { int min_level; switch (number_bits (4)) { case 0: min_level = 0; spell = "curse"; break; case 1: min_level = 3; spell = "weaken"; break; case 2: min_level = 6; spell = "chill touch"; break; case 3: min_level = 9; spell = "blindness"; break; case 4: min_level = 12; spell = "poison"; break; case 5: min_level = 15; spell = "energy drain"; break; case 6: min_level = 18; spell = "harm"; break; /* Commented out by Narn, Nov 28/95 case 7: min_level = 21; spell = "teleport"; break; */ default: min_level = 35; spell = "gate"; break; } if (ch->GetLevel () >= min_level) break; } if ((sn = SkillTable.Lookup (spell)) < 0) return FALSE; (*SkillTable.GetSpellFunction (sn)) (sn, ch->GetLevel (), ch, victim); return TRUE; } BOOL spec_executioner (CCharacter *ch) { char buf[MAX_STRING_LENGTH]; CMobIndexData *cityguard; CCharacter *victim; CCharacter *v_next; char *crime; if (!ch->IsAwake () || ch->GetFightData ()) return FALSE; crime = ""; for (victim = ch->GetInRoom ()->first_person; victim; victim = v_next) { v_next = victim->GetNextInRoom (); if (!victim->IsNpc () && victim->IsKiller ()) { crime = "KILLER"; break; } if (!victim->IsNpc () && victim->IsThief ()) { crime = "THIEF"; break; } } if (!victim) return FALSE; if (ch->GetInRoom ()->IsSafe ()) { sprintf (buf, "%s is a %s! As well as a COWARD!", victim->GetName (), crime); do_yell (ch, buf); return TRUE; } sprintf (buf, "%s is a %s! PROTECT THE INNOCENT! MORE BLOOOOD!!!", victim->GetName (), crime); do_shout (ch, buf); multi_hit (ch, victim, TYPE_UNDEFINED); if (char_died (ch)) return TRUE; /* Added log in case of missing cityguard -- Tri */ cityguard = MobTable.GetMob (MOB_VNUM_CITYGUARD); if (!cityguard) { sprintf (buf, "Missing Cityguard - Vnum:[%d]", MOB_VNUM_CITYGUARD); bug (buf, 0); return TRUE; } create_mobile (cityguard)->SendToRoom (ch->GetInRoom ()); create_mobile (cityguard)->SendToRoom (ch->GetInRoom ()); return TRUE; } BOOL spec_fido (CCharacter *ch) { CObjData *corpse; CObjData *obj; if (! ch->IsAwake ()) return FALSE; POSITION pos = ch->GetInRoom ()->GetHeadContentPos (); while (corpse = ch->GetInRoom ()->GetNextContent (pos)) { if (corpse->item_type != ITEM_CORPSE_NPC) continue; act (AT_ACTION, "$n savagely devours a corpse.", ch, NULL, NULL, TO_ROOM); POSITION Cpos = corpse->GetHeadContentPos (); while (obj = corpse->GetNextContent (Cpos)) { obj_from_obj (obj); obj_to_room (obj, ch->GetInRoom ()); } extract_obj (corpse); return TRUE; } return FALSE; } BOOL spec_guard (CCharacter *ch) { char buf[MAX_STRING_LENGTH]; CCharacter *victim; CCharacter *v_next; CCharacter *ech; char *crime; int max_evil; if (!ch->IsAwake () || ch->GetFightData ()) return FALSE; max_evil = 300; ech = NULL; crime = ""; for (victim = ch->GetInRoom ()->first_person; victim; victim = v_next) { v_next = victim->GetNextInRoom (); if (!victim->IsNpc () && victim->IsKiller ()) { crime = "KILLER"; break; } if (!victim->IsNpc () && victim->IsThief ()) { crime = "THIEF"; break; } if (victim->GetFightData () && victim->GetFightWho () != ch && victim->GetAlignment () < max_evil) { max_evil = victim->GetAlignment (); ech = victim; } } if (victim && ch->GetInRoom ()->IsSafe ()) { sprintf (buf, "%s is a %s! As well as a COWARD!", victim->GetName (), crime); do_yell (ch, buf); return TRUE; } if (victim) { sprintf (buf, "%s is a %s! PROTECT THE INNOCENT!! BANZAI!!", victim->GetName (), crime); do_shout (ch, buf); multi_hit (ch, victim, TYPE_UNDEFINED); return TRUE; } if (ech) { act (AT_YELL, "$n screams 'PROTECT THE INNOCENT!! BANZAI!!", ch, NULL, NULL, TO_ROOM); multi_hit (ch, ech, TYPE_UNDEFINED); return TRUE; } return FALSE; } BOOL spec_janitor (CCharacter *ch) { CObjData *trash; if (! ch->IsAwake ()) return FALSE; POSITION pos = ch->GetInRoom ()->GetHeadContentPos (); while (trash = ch->GetInRoom ()->GetNextContent (pos)) { if (! IS_SET (trash->wear_flags, ITEM_TAKE) || trash->IsBuried ()) continue; if (trash->item_type == ITEM_DRINK_CON || trash->item_type == ITEM_TRASH || trash->cost < 10 || (trash->pIndexData->vnum == OBJ_VNUM_SHOPPING_BAG && trash->IsEmpty ())) { act (AT_ACTION, "$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_mayor (CCharacter *ch) { static const char open_path[] = "W3a3003b33000c111d0d111Oe333333Oe22c222112212111a1S."; static const char close_path[] = "W3a3003b33000c111d0d111CE333333CE22c222112212111a1S."; static const char *path; static int pos; static BOOL move; if (!move) { if (time_info.hour == 6) { path = open_path; move = TRUE; pos = 0; } if (time_info.hour == 20) { path = close_path; move = TRUE; pos = 0; } } if (ch->GetFightData ()) return spec_cast_cleric (ch); if (!move || ch->GetPosition () < POS_SLEEPING) return FALSE; switch (path[pos]) { case '0': case '1': case '2': case '3': move_char (ch, get_exit (ch->GetInRoom (), path[pos] - '0'), 0); break; case 'W': ch->SetPosition (POS_STANDING); act (AT_ACTION, "$n awakens and groans loudly.", ch, NULL, NULL, TO_ROOM); break; case 'S': ch->SetPosition (POS_SLEEPING); act (AT_ACTION, "$n lies down and falls asleep.", ch, NULL, NULL, TO_ROOM); break; case 'a': act (AT_SAY, "$n says 'Hello Honey!'", ch, NULL, NULL, TO_ROOM); break; case 'b': act (AT_SAY, "$n says 'What a view! I must do something about that dump!'", ch, NULL, NULL, TO_ROOM); break; case 'c': act (AT_SAY, "$n says 'Vandals! Youngsters have no respect for anything!'", ch, NULL, NULL, TO_ROOM); break; case 'd': act (AT_SAY, "$n says 'Good day, citizens!'", ch, NULL, NULL, TO_ROOM); break; case 'e': act (AT_SAY, "$n says 'I hereby declare the town of Darkhaven open!'", ch, NULL, NULL, TO_ROOM); break; case 'E': act (AT_SAY, "$n says 'I hereby declare the town of Darkhaven closed!'", ch, NULL, NULL, TO_ROOM); break; case 'O': do_unlock (ch, "gate"); do_open (ch, "gate"); break; case 'C': do_close (ch, "gate"); do_lock (ch, "gate"); break; case '.' : move = FALSE; break; } pos++; return FALSE; } BOOL spec_poison (CCharacter *ch) { CCharacter *victim; if (! ch->IsFightPosition () || (victim = ch->GetFightWho ()) == NULL || number_percent () > 2 * ch->GetLevel ()) return FALSE; act (AT_HIT, "You bite $N!", ch, NULL, victim, TO_CHAR ); act (AT_ACTION, "$n bites $N!", ch, NULL, victim, TO_NOTVICT); act (AT_POISON, "$n bites you!", ch, NULL, victim, TO_VICT ); spell_poison (gsn_poison, ch->GetLevel (), ch, victim); return TRUE; } BOOL spec_thief (CCharacter *ch) { CCharacter *victim; CCharacter *v_next; int gold, maxgold; if (ch->GetPosition () != POS_STANDING) return FALSE; for (victim = ch->GetInRoom ()->first_person; victim; victim = v_next) { v_next = victim->GetNextInRoom (); if (victim->IsNpc () || victim->GetLevel () >= LEVEL_IMMORTAL || number_bits (2) != 0 || !can_see (ch, victim)) /* Thx Glop */ continue; if (victim->IsAwake () && number_range (0, ch->GetLevel ()) == 0) { act (AT_ACTION, "You discover $n's hands in your sack of gold!", ch, NULL, victim, TO_VICT); act (AT_ACTION, "$N discovers $n's hands in $S sack of gold!", ch, NULL, victim, TO_NOTVICT); return TRUE; } else { maxgold = ch->GetLevel () * ch->GetLevel () * 1000; gold = victim->GetGold () * number_range (1, URANGE (2, ch->GetLevel ()/4, 10)) / 100; ch->AddGold (9 * gold / 10); victim->AddGold (-gold); if (ch->GetGold () > maxgold) { ch->GetInRoom ()->GetArea ()->BoostEconomy (ch->GetGold () - maxgold/2); ch->SetGold (maxgold/2); } return TRUE; } } return FALSE; }