/****************************************************************************
* [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// *
* -----------------------------------------------------------| (0...0) *
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( *
* -----------------------------------------------------------| {o o} *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ *
* Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~*
* Tricops and Fireblade | *
* ------------------------------------------------------------------------ *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* ------------------------------------------------------------------------ *
* "Special procedure" module *
****************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.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);
DECLARE_SPEC_FUN(spec_questmaster);
DECLARE_SPEC_FUN(spec_gemcutter);
/*
* 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;
if (!str_cmp(name, "spec_questmaster"))
return spec_questmaster;
if (!str_cmp(name, "spec_gemcutter"))
return spec_gemcutter;
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";
if (special == spec_questmaster)
return "spec_questmaster";
if (special == spec_gemcutter)
return "spec_gemcutter";
return "";
}
/* if a spell casting mob is hating someone... try and summon them */
void summon_if_hating(CHAR_DATA * ch)
{
CHAR_DATA *victim;
char buf[MSL];
char name[MIL];
bool found = FALSE;
if (ch->position <= POS_SLEEPING)
return;
if (ch->fighting || ch->fearing || !ch->hating || is_room_safe(ch))
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->next)
{
if (!str_cmp(ch->hating->name, victim->name))
{
found = TRUE;
break;
}
}
if (!found)
return;
if (ch->in_room == victim->in_room)
return;
if (!IS_NPC(victim))
sprintf(buf, "summon 0.%s", name);
else
sprintf(buf, "summon %s", name);
do_cast(ch, buf);
return;
}
/*
* Core procedure for dragons.
*/
bool dragon(CHAR_DATA * ch, char *spell_name)
{
CHAR_DATA *victim;
CHAR_DATA *v_next;
int sn;
if (ch->position != POS_FIGHTING
&& ch->position != POS_EVASIVE && ch->position != POS_DEFENSIVE && ch->position != POS_AGGRESSIVE && ch->position != POS_BERSERK)
return FALSE;
for (victim = ch->in_room->first_person; victim; victim = v_next)
{
v_next = victim->next_in_room;
if (who_fighting(victim) == ch && number_bits(2) == 0)
break;
}
if (!victim)
return FALSE;
if ((sn = skill_lookup(spell_name)) < 0)
return FALSE;
(*skill_table[sn]->spell_fun) (sn, ch->level, ch, victim);
return TRUE;
}
/*
* Special procedures for mobiles.
*/
bool spec_breath_any(CHAR_DATA * ch)
{
if (ch->position != POS_FIGHTING
&& ch->position != POS_EVASIVE && ch->position != POS_DEFENSIVE && ch->position != POS_AGGRESSIVE && ch->position != POS_BERSERK)
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(CHAR_DATA * ch)
{
return dragon(ch, "acid 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
&& ch->position != POS_EVASIVE && ch->position != POS_DEFENSIVE && ch->position != POS_AGGRESSIVE && ch->position != POS_BERSERK)
return FALSE;
if ((sn = skill_lookup("gas breath")) < 0)
return FALSE;
(*skill_table[sn]->spell_fun) (sn, ch->level, ch, NULL);
return TRUE;
}
bool spec_breath_lightning(CHAR_DATA * ch)
{
return dragon(ch, "lightning breath");
}
bool spec_cast_adept(CHAR_DATA * ch)
{
CHAR_DATA *victim;
CHAR_DATA *v_next;
if (!IS_AWAKE(ch) || ch->fighting)
return FALSE;
for (victim = ch->in_room->first_person; victim; victim = v_next)
{
v_next = victim->next_in_room;
if (victim != ch && can_see(ch, victim))
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(skill_lookup("armor"), ch->level, ch, victim);
return TRUE;
case 1:
act(AT_MAGIC, "$n utters the word 'sunimod'.", ch, NULL, NULL, TO_ROOM);
spell_smaug(skill_lookup("bless"), ch->level, ch, victim);
return TRUE;
case 2:
act(AT_MAGIC, "$n utters the word 'suah'.", ch, NULL, NULL, TO_ROOM);
spell_cure_blindness(skill_lookup("cure blindness"), ch->level, ch, victim);
return TRUE;
case 3:
act(AT_MAGIC, "$n utters the word 'nran'.", ch, NULL, NULL, TO_ROOM);
spell_smaug(skill_lookup("cure light"), ch->level, ch, victim);
return TRUE;
case 4:
act(AT_MAGIC, "$n utters the word 'nyrcs'.", ch, NULL, NULL, TO_ROOM);
spell_cure_poison(skill_lookup("cure poison"), ch->level, ch, victim);
return TRUE;
case 5:
act(AT_MAGIC, "$n utters the word 'gartla'.", ch, NULL, NULL, TO_ROOM);
spell_smaug(skill_lookup("refresh"), ch->level, ch, victim);
return TRUE;
case 6:
act(AT_MAGIC, "$n utters the word 'naimad'.", ch, NULL, NULL, TO_ROOM);
spell_smaug(skill_lookup("cure serious"), ch->level, ch, victim);
return TRUE;
case 7:
act(AT_MAGIC, "$n utters the word 'gorog'.", ch, NULL, NULL, TO_ROOM);
spell_remove_curse(skill_lookup("remove curse"), ch->level, ch, victim);
return TRUE;
}
return FALSE;
}
bool spec_cast_cleric(CHAR_DATA * ch)
{
return FALSE;
}
bool spec_cast_mage(CHAR_DATA * ch)
{
return FALSE;
}
bool spec_cast_undead(CHAR_DATA * ch)
{
return FALSE;
}
bool spec_executioner(CHAR_DATA * ch)
{
char buf[MSL];
CHAR_DATA *victim;
CHAR_DATA *v_next;
char *crime;
if (!IS_AWAKE(ch) || ch->fighting)
return FALSE;
crime = "";
for (victim = ch->in_room->first_person; victim; victim = v_next)
{
v_next = victim->next_in_room;
if (!IS_NPC(victim) && xIS_SET(victim->act, PLR_KILLER))
{
crime = "KILLER";
break;
}
if (!IS_NPC(victim) && xIS_SET(victim->act, PLR_THIEF))
{
crime = "THIEF";
break;
}
}
if (!victim)
return FALSE;
if (is_room_safe(ch))
{
sprintf(buf, "%s You are a COWARD!", victim->name);
do_yell(ch, buf);
return TRUE;
}
sprintf(buf, "%s PROTECT THE INNOCENT! MORE BLOOOOD!!!", victim->name);
do_tell(ch, buf);
one_hit(ch, victim, TYPE_UNDEFINED, LM_BODY);
if (char_died(ch))
return TRUE;
/* Added log in case of missing cityguard -- Tri */
/*
cityguard = get_mob_index(MOB_VNUM_CITYGUARD);
if (!cityguard)
{
sprintf(buf, "Missing Cityguard - Vnum:[%d]", MOB_VNUM_CITYGUARD);
bug(buf, 0);
return TRUE;
}
char_to_room(create_mobile(cityguard), ch->in_room);
char_to_room(create_mobile(cityguard), ch->in_room); */
return TRUE;
}
bool spec_fido(CHAR_DATA * ch)
{
OBJ_DATA *corpse;
OBJ_DATA *c_next;
OBJ_DATA *obj;
OBJ_DATA *obj_next;
if (!IS_AWAKE(ch))
return FALSE;
for (corpse = ch->in_room->first_content; corpse; corpse = c_next)
{
c_next = corpse->next_content;
if (corpse->item_type != ITEM_CORPSE_NPC)
continue;
act(AT_ACTION, "$n savagely devours a corpse.", ch, NULL, NULL, TO_ROOM);
for (obj = corpse->first_content; obj; obj = obj_next)
{
obj_next = obj->next_content;
obj_from_obj(obj);
obj_to_room(obj, ch->in_room, ch);
}
extract_obj(corpse);
return TRUE;
}
return FALSE;
}
bool spec_questmaster(CHAR_DATA * ch)
{
if (!IS_NPC(ch))
return FALSE;
else
return TRUE;
}
bool spec_gemcutter(CHAR_DATA * ch)
{
if (!IS_NPC(ch))
return FALSE;
else
return TRUE;
}
bool spec_guard(CHAR_DATA * ch)
{
char buf[MSL];
CHAR_DATA *victim;
CHAR_DATA *v_next;
CHAR_DATA *ech;
char *crime;
int max_evil;
if (!IS_AWAKE(ch) || ch->fighting)
return FALSE;
max_evil = 300;
ech = NULL;
crime = "";
for (victim = ch->in_room->first_person; victim; victim = v_next)
{
v_next = victim->next_in_room;
if (!IS_NPC(victim) && xIS_SET(victim->act, PLR_KILLER))
{
crime = "KILLER";
break;
}
if (!IS_NPC(victim) && xIS_SET(victim->act, PLR_THIEF))
{
crime = "THIEF";
break;
}
if (victim->fighting && who_fighting(victim) != ch && victim->alignment < max_evil)
{
max_evil = victim->alignment;
ech = victim;
}
}
if (victim && is_room_safe(ch))
{
sprintf(buf, "%s You are a COWARD!", victim->name);
do_tell(ch, buf);
return TRUE;
}
if (victim)
{
sprintf(buf, "%s PROTECT THE INNOCENT!! BANZAI!!", victim->name);
do_tell(ch, buf);
one_hit(ch, victim, TYPE_UNDEFINED, LM_BODY);
return TRUE;
}
if (ech)
{
act(AT_YELL, "$n screams 'PROTECT THE INNOCENT!! BANZAI!!", ch, NULL, NULL, TO_ROOM);
one_hit(ch, ech, TYPE_UNDEFINED, LM_BODY);
return TRUE;
}
return FALSE;
}
bool spec_janitor(CHAR_DATA * ch)
{
OBJ_DATA *trash;
OBJ_DATA *trash_next;
if (!IS_AWAKE(ch))
return FALSE;
for (trash = ch->in_room->first_content; trash; trash = trash_next)
{
trash_next = trash->next_content;
if (!IS_SET(trash->wear_flags, ITEM_TAKE) || IS_OBJ_STAT(trash, ITEM_BURIED))
continue;
if (trash->item_type == ITEM_DRINK_CON
|| trash->item_type == ITEM_TRASH || trash->cost < 10 || (trash->pIndexData->vnum == OBJ_VNUM_SHOPPING_BAG && !trash->first_content))
{
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(CHAR_DATA * 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 (gethour() == 6)
{
path = open_path;
move = TRUE;
pos = 0;
}
if (gethour() == 20)
{
path = close_path;
move = TRUE;
pos = 0;
}
}
if (ch->fighting)
return spec_cast_cleric(ch);
if (!move || ch->position < POS_SLEEPING)
return FALSE;
switch (path[pos])
{
case '0':
case '1':
case '2':
case '3':
move_char(ch, get_exit(ch->in_room, path[pos] - '0'), 0);
break;
case 'W':
ch->position = POS_STANDING;
act(AT_ACTION, "$n awakens and groans loudly.", ch, NULL, NULL, TO_ROOM);
break;
case 'S':
ch->position = 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(CHAR_DATA * ch)
{
CHAR_DATA *victim;
if (ch->position != POS_FIGHTING
&& ch->position != POS_EVASIVE && ch->position != POS_DEFENSIVE && ch->position != POS_AGGRESSIVE && ch->position != POS_BERSERK)
return FALSE;
if ((victim = who_fighting(ch)) == NULL || number_percent() > 75)
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->level, ch, victim);
return TRUE;
}
bool spec_thief(CHAR_DATA * ch)
{
CHAR_DATA *victim;
CHAR_DATA *v_next;
int gold;
if (ch->position != POS_STANDING)
return FALSE;
for (victim = ch->in_room->first_person; victim; victim = v_next)
{
v_next = victim->next_in_room;
if (IS_NPC(victim) || victim->level >= LEVEL_IMMORTAL || number_bits(2) != 0 || !can_see(ch, victim)) /* Thx Glop */
continue;
if (IS_AWAKE(victim) && number_range(0, 20) == 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
{
gold = number_range(victim->gold/15, victim->gold/25);
ch->gold += gold;
victim->gold -= gold;
return TRUE;
}
}
return FALSE;
}