/***************************************************************************
* Mud20 1.0 by Todd H. Johnson (Kregor) a derivative of the Open Gaming *
* License by Wizards of the Coast. All comments referring to D20, OGL, *
* and SRD refer to the System Reference Document for the Open Gaming *
* system. Any inclusion of these derivatives must include credit to the *
* Mud20 system, the full and complete Open Gaming LIcense, and credit to *
* the respective authors. See ../doc/srd.txt for more information. *
* *
* Emud 2.2 by Igor van den Hoven, Michiel Lange, and Martin Bethlehem. *
* *
* MrMud 1.4 by David Bills, Dug Michael and Martin Gallwey *
* *
* 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{rfeld, Tom Madsen, and Katje Nyboe. *
***************************************************************************/
/***************************************************************************
* magic.c: Spells and functions for magic *
***************************************************************************/
#include "mud.h"
/*
Local functions.
*/
#define DO_SPELL(spell) bool spell( int sn, int level, CHAR_DATA *ch, void *vo, int target )
#define DO_SONG(song) bool song( int sn, int level, CHAR_DATA *ch, void *vo, int target )
int value; /* This is the value after the target */
/* This forces instant incubation of disease in Contagion spell */
void disease_update args(( CHAR_DATA *ch ));
#define turn 10
#define hr 100
#define PARTIAL -1 /* return for partial save, where TRUE is full save */
bool ForReal = TRUE;
/*
* Hack one_argument to pick out skill names
* This removes the need for quotes around skill
* names in commands. This only goes three arguments deep,
* as no skill name is longer than three words. - Kregor 7/4/12
*/
char *snarf_skill_name( char *argument, char *name )
{
char ArgA[MAX_INPUT_LENGTH];
char ArgB[MAX_INPUT_LENGTH];
char ArgC[MAX_INPUT_LENGTH];
push_call("snarf_skill_name(%p,%p)",argument,name);
if (argument == NULL)
{
log_string("snarf_skill_name: argument == NULL");
dump_stack();
pop_call();
return NULL;
}
one_argument(argument, ArgA);
// returning empty string should stop any wierdness - Kregor
strcpy(name, "");
if (skill_lookup(ArgA) != -1)
{
argument = one_argument(argument, ArgA);
strcpy(name, ArgA);
one_argument(argument, ArgB);
if (skill_lookup(format("%s %s", ArgA, ArgB)) != -1)
{
argument = one_argument(argument, ArgB);
cat_sprintf(name, " %s", ArgB);
one_argument(argument, ArgC);
if (skill_lookup(format("%s %s", name, ArgC)) != -1)
{
argument = one_argument(argument, ArgC);
cat_sprintf(name, " %s", ArgC);
}
}
}
pop_call();
return argument;
}
/*
* Called on casting of aggressive spell.
*/
void make_char_fight_char( CHAR_DATA *ch, CHAR_DATA *victim )
{
push_call("make_char_fight_char(%p,%p)",ch,victim);
if (ch == NULL || victim == NULL || !IS_AWAKE(victim))
{
pop_call();
return;
}
if (ch == victim)
{
pop_call();
return;
}
if (in_combat(ch) && in_combat(victim))
{
pop_call();
return;
}
if (ch == supermob || victim == supermob)
{
pop_call();
return;
}
fight(victim, ch);
pop_call();
return;
}
/*
* Caster level check vs. spell resistance of vict
* Roll 1d20 + caster level to beat spell resistance.
* Spell penetration feat gives +1, greater penetration +2,
* epic penetration +3 - Kregor 3/10/08
*/
bool check_spell_resist(CHAR_DATA *victim, CHAR_DATA *ch, int sn, int level)
{
int diceroll, resist;
push_call("check_spell_resist(%p,%p)",ch,victim);
if (!is_spell_like(sn))
{
pop_call();
return FALSE;
}
if (IS_SET(skill_table[sn].spell_school, SDESC_MIND))
{
if (get_curr_int(victim) < 0)
{
act( "$N is unaffected by your spell.", ch, NULL, victim, TO_CHAR);
act( "You resist $n's spell.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
}
if (rspec_req(victim, RSPEC_SWARM) && !IS_AREA_SPELL(sn))
{
act( "Your spell fails to dissipate $N.", ch, NULL, victim, TO_CHAR);
act( "You resist $n's spell.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
if (skill_table[sn].spell_school == SCHOOL_DIVINATION)
{
if (domain_apotheosis(victim, DOMAIN_MADNESS) && !domain_apotheosis(ch, DOMAIN_MADNESS))
{
act("You fail to divine through $N's madness.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
if (skill_table[sn].spell_school == SCHOOL_ILLUSION && !IS_OFFENSIVE(victim, sn))
{
pop_call();
return FALSE;
}
if (IS_SET(skill_table[sn].flags, SF_NO_RESIST))
{
pop_call();
return FALSE;
}
else if (IS_AFFECTED(victim, AFF_IMMUNE_SPELL))
{
act( "$N resists your spell.", ch, NULL, victim, TO_CHAR);
act( "You resist $n's spell.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
if (sn == gsn_confusion || sn == gsn_lesser_confusion || sn == gsn_symbol_of_insanity || sn == gsn_insanity)
{
if (domain_apotheosis(victim, DOMAIN_MADNESS))
{
act("Your madness cannot surpass that already posessed by $N", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
}
if ((IS_FLATFOOTED(victim) || IS_HELPLESS(victim)) && learned(ch, gsn_feint_resistance))
{
pop_call();
return FALSE;
}
if (skill_table[sn].spell_school == SCHOOL_EVOCATION && arcane_mastery(ch, SCHOOL_EVOCATION))
diceroll = UMAX(dice(1,20), dice(1,20));
else
diceroll = dice(1,20);
diceroll += level + learned(ch, gsn_spell_penetration);
if (race_skill(ch, gsn_high_magic))
diceroll += 1;
if (IS_SET(skill_table[sn].spell_desc, SDESC_NEGATIVE) && get_bloodline(ch) == BLOODLINE_UNDEAD)
diceroll += class_level(ch, CLASS_SORCERER) / 5 + 1;
if (learned(ch, gsn_feint_resistance))
diceroll += UMAX(0, stat_bonus(TRUE, ch, APPLY_WIS));
resist = spell_resist(victim);
if (IS_EVIL(ch))
resist = UMAX(get_apply(victim, APPLY_SR_EVIL), resist);
if (IS_GOOD(ch))
resist = UMAX(get_apply(victim, APPLY_SR_GOOD), resist);
if (IS_LAWFUL(ch))
resist = UMAX(get_apply(victim, APPLY_SR_LAW), resist);
if (IS_CHAOTIC(ch))
resist = UMAX(get_apply(victim, APPLY_SR_CHAOS), resist);
if (!resist)
{
pop_call();
return FALSE;
}
if (diceroll < resist)
{
act( "$N resists your spell.", ch, NULL, victim, TO_CHAR);
act( "You resist $n's spell.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
/*
* Check whether nondetection wards against a scryer
*/
bool check_nondetection ( CHAR_DATA *ch, CHAR_DATA *victim, int sn )
{
int ranks = 0;
push_call("check_nondetection(%p,%p)",ch,victim);
if ((ranks = get_affect_level(ch, sn)) <= 0)
{
if ((ranks = get_caster_level(ch, sn)) <= 0)
{
if (sn == gsn_detect_evil && class_level(ch, CLASS_PALADIN))
{
ranks = class_level(ch, CLASS_PALADIN);
}
else if (sn == gsn_detect_good && class_level(ch, CLASS_BLACKGUARD))
{
ranks = class_level(ch, CLASS_BLACKGUARD);
}
else if ((ranks = skill_table[sn].native_level * 2) <= 0)
{
pop_call();
return TRUE;
}
}
}
if (domain_apotheosis(victim, DOMAIN_MADNESS) && !domain_apotheosis(ch, DOMAIN_MADNESS))
{
act("You fail to divine through $N's madness.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
if (IS_AFFECTED(victim, AFF_MIND_BLANK))
{
if (!domain_apotheosis(ch, DOMAIN_KNOWLEDGE) || will_save(victim, ch, ranks, sn))
{
pop_call();
return TRUE;
}
}
if (IS_AFFECTED(victim, AFF_NONDETECTION))
{
if (dice(1,20) + ranks < 11 + UMAX(5, get_affect_level(ch, gsn_nondetection)))
{
pop_call();
return TRUE;
}
else
{
pop_call();
return TRUE;
}
}
pop_call();
return FALSE;
}
/*
crash-proof skill names. - Kregor
*/
char *skill_name( int sn )
{
return (sn > -1 && is_string(skill_table[sn].name) ? skill_table[sn].name : "!unknown skill!");
}
/*
Lookup a skill by name.
*/
int skill_lookup( char *name )
{
int sn;
push_call("skill_lookup(%p)",name);
for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
{
if (tolower(name[0]) == skill_table[sn].name[0])
{
if (!strcmp(name, skill_table[sn].name))
{
pop_call();
return sn;
}
}
}
for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
{
if (tolower(name[0]) == skill_table[sn].name[0])
{
if (is_multi_name_short(name, skill_table[sn].name))
{
pop_call();
return sn;
}
}
}
pop_call();
return -1;
}
/*
* is ch even a caster? - Kregor
*/
bool is_caster(CHAR_DATA *ch)
{
int cnt;
push_call("is_caster(%p)",ch);
for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
{
if (!class_level(ch, cnt))
continue;
if (class_table[cnt].mana_table == MANA_NONE)
continue;
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
/*
* Variation of dice for spells, to figure metamagic effects - Kregor
*/
int spell_dice( CHAR_DATA *ch, int sn, int number, int size )
{
int idice, roll, sum, bonus;
push_call("spell_dice(%p,%p,%p)",ch,number,size);
if (size <= 0)
{
pop_call();
return 0;
}
for (idice = bonus = sum = 0 ; idice < number ; idice++)
{
if ((roll = (lrand48() % size) + 1) == 1 && (get_bloodline(ch) == BLOODLINE_DESTINED || domain_apotheosis(ch, DOMAIN_LUCK)))
{
roll = (lrand48() % size) + 1;
}
else if (roll == 1 && is_spell(sn) && skill_table[sn].target == TAR_CHAR_OFFENSIVE && domain_apotheosis(ch, DOMAIN_DESTRUCTION))
{
roll = 2;
}
sum += roll;
}
if (IS_SET(ch->cast_feats, METAMAGIC_EMPOWER)
|| (ch->cast_class == CLASS_CLERIC && strstr(skill_table[sn].name, "inflict") && learned(ch, gsn_empower_infliction))
|| (ch->cast_class == CLASS_CLERIC && strstr(skill_table[sn].name, "cure") && learned(ch, gsn_empower_curing)))
bonus = sum / 2;
if (IS_SET(ch->cast_feats, METAMAGIC_MAXIMIZE)
|| (ch->cast_class == CLASS_CLERIC && strstr(skill_table[sn].name, "cure") && domain_apotheosis(ch, DOMAIN_HEALING)))
sum = number * size;
pop_call();
return sum + bonus;
}
/*
* Return the casting class of a spell - Kregor
* If cast as a racial ability, return -2.
* If not castable by any class CH has, return -1.
*/
int casting_class( CHAR_DATA *ch, int sn, bool fCasting )
{
int class = -1;
push_call("casting_class(%p,%p)",ch,sn);
if (ch->casting && ch->cast_sn == sn)
{
class = ch->cast_class;
}
else if (!fCasting)
{
if ((class = prepared(ch,sn)) == -1)
{
if ((class = spontaneous_cast(ch,sn)) == -1)
{
if ((class = multi(ch,sn)) == -1)
{
if (race_skill(ch, sn))
{
class = -2;
}
}
}
}
}
pop_call();
return class;
}
/*
* Return the class a given spell is
* prepared as - Kregor
*/
int prepared( CHAR_DATA *ch, int sn )
{
int class = -1;
push_call("prepared(%p,%p)",ch,sn);
if (IS_NPC(ch) || IS_GOD(ch))
{
class = multi(ch, sn);
}
else if (ch->pcdata->prepared[sn] > 0)
class = ch->pcdata->prepared[sn];
pop_call();
return class;
}
/*
* Calc the effective caster level of a class,
* including prestige classes that add caster levels - Kregor
*
* per d20, prestige classes add to spells known,
* spells per day (mana), and caster level, so this
* function should find be in functions for all three.
*/
int eff_caster_level( CHAR_DATA *ch, int class )
{
int cls, lvl, level;
push_call("eff_caster_level(%p.%p)",ch,class);
if ((lvl = UMIN(ch->mclass[class], 20)) < 1)
{
pop_call();
return 0;
}
/*
* add caster levels for prestige classes
* Order of progression: Wizard or Sorcerer over Bard for Arcane,
* Cleric or Druid over Paladin or Ranger for Divine,
* Cleric or Druid over Wizard or Sorcerer for Either
* Because the code does not allow Cleric/Druid or Wizard/Sorcerer multi,
* no safeguards are in place for having levels in both.
*/
for (cls = MAX_CORE_CLASS ; cls < MAX_PRESTIGE_CLASS ; cls++)
{
if ((level = class_level(ch, cls)) <= 0)
continue;
if (cls == class)
continue;
switch (class_table[cls].mana_table)
{
default:
break;
case MANA_PRESTIGE_ARC:
case MANA_PREST_ARC_HALF:
if (class_table[cls].mana_table == MANA_PREST_ARC_HALF)
level = ROUNDUP(level / 2);
if (class == CLASS_WIZARD)
lvl += level;
else if (class == CLASS_SORCERER)
lvl += level;
else if (class == CLASS_BARD && !class_level(ch, CLASS_WIZARD) && !class_level(ch, CLASS_SORCERER))
lvl += level;
break;
case MANA_PRESTIGE_DIV:
case MANA_PREST_DIV_HALF:
if (class_table[cls].mana_table == MANA_PREST_DIV_HALF)
level = ROUNDUP(level / 2);
if (class == CLASS_CLERIC)
lvl += level;
else if (class == CLASS_DRUID)
lvl += level;
else if (class == CLASS_PALADIN && !class_level(ch, CLASS_CLERIC) && !class_level(ch, CLASS_DRUID))
lvl += level;
else if (class == CLASS_RANGER && !class_level(ch, CLASS_CLERIC) && !class_level(ch, CLASS_PALADIN) && !class_level(ch, CLASS_CLERIC) && !class_level(ch, CLASS_DRUID))
lvl += level;
break;
case MANA_PRESTIGE_EITHER:
if (class == CLASS_CLERIC)
lvl += level;
else if (class == CLASS_DRUID)
lvl += level;
else if (class == CLASS_WIZARD && !class_level(ch, CLASS_CLERIC) && !class_level(ch, CLASS_DRUID))
lvl += level;
else if (class == CLASS_SORCERER && !class_level(ch, CLASS_CLERIC) && !class_level(ch, CLASS_PALADIN) && !class_level(ch, CLASS_CLERIC) && !class_level(ch, CLASS_DRUID))
lvl += level;
break;
case MANA_PRESTIGE_BOTH:
if (class == CLASS_CLERIC)
lvl += level;
else if (class == CLASS_DRUID)
lvl += level;
if (class == CLASS_WIZARD)
lvl += level;
else if (class == CLASS_SORCERER)
lvl += level;
break;
}
break; //because code only allows one prestige class for PC, break after finding a prestige class
}
lvl -= get_apply(ch, APPLY_LEVEL); // don't forget penalty for level drain!
pop_call();
return UMAX(1,lvl); // Min caster level even with level drains is 1st
}
/*
* returns the max spell circle castable
* by a PC's class level - Kregor 5/25/07
*/
int max_spell_circle( CHAR_DATA *ch, int class )
{
int circle, lvl;
push_call("max_spell_circle(%p.%p)",ch,class);
if ((lvl = UMIN(eff_caster_level(ch, class), 30)) < 1)
{
pop_call();
return -1;
}
switch (class_table[class].mana_table)
{
default:
circle = -1;
break;
case MANA_SORCERER:
circle = URANGE( 1, lvl / 2, 9);
break;
case MANA_WIZ_PRIEST:
circle = ROUNDUP((lvl - 1) / 2);
circle = UMIN(circle, 9);
break;
case MANA_BARD:
circle = URANGE(0, lvl / 2, 6);
break;
case MANA_PRESTIGE:
if (class == CLASS_BLACKGUARD)
lvl += class_level(ch,CLASS_PALADIN);
circle = UMIN((lvl + 3) / 3, 4);
break;
case MANA_WARRIOR:
circle = UMIN((lvl - 1) / 3, 4);
break;
// case MANA_PRESTIGE:
// circle = UMIN(lvl / 2, 4);
// break;
}
pop_call();
return UMIN(circle, 9);
}
/*
* The number of a given level of a spell character may prepare
* Simple, count the number of each slot at the caster level,
* and add the number of spell points needed to cast that many
* of a given slot number - Kregor
*/
int get_slot_count( CHAR_DATA *ch, int class, int level )
{
int count = 0;
int lvl = 0;
int cnt = 0;
push_call("get_slot_count(%p,%p,%p)",ch,class,level);
if (level < 0 || level > 9)
{
log_printf("get_slot_count: spell level out of range!");
pop_call();
return 0;
}
if ((lvl = eff_caster_level(ch, class)) <= 0)
{
pop_call();
return 0;
}
switch (class_table[class].mana_table)
{
default:
count = -1;
break;
case MANA_BARD:
count = bard_spell_table[lvl].spell_level[level];
break;
case MANA_WIZ_PRIEST:
count = spell_slot_table[lvl].spell_level[level];
break;
case MANA_PRESTIGE:
if (class == CLASS_BLACKGUARD)
lvl += class_level(ch,CLASS_PALADIN);
count = warrior_spell_table[lvl+5].spell_level[level];
break;
case MANA_WARRIOR:
count = warrior_spell_table[lvl].spell_level[level];
break;
case MANA_SORCERER:
count = sorcerer_spell_table[lvl].spell_level[level];
break;
}
if (count < 0)
{
pop_call();
return count;
}
switch (class_table[class].attr_prime)
{
default:
break;
case APPLY_WIS:
count += slot_bonus_table[ch->perm_wis].bonus[level];
break;
case APPLY_INT:
count += slot_bonus_table[ch->perm_int].bonus[level];
break;
case APPLY_CHA:
count += slot_bonus_table[ch->perm_cha].bonus[level];
break;
}
// if (class == CLASS_CLERIC && ch->pcdata->domains > 0)
// count += 1;
//
if (class == CLASS_WIZARD && get_school(ch) > 0)
count += 1;
if ((cnt = learned(ch, gsn_newfound_arcana)) > 0)
{
if (cnt >= 1 && level == 1)
count++;
if (cnt >= 2 && level == 2)
count++;
if (cnt >= 3 && level == 3)
count++;
}
pop_call();
return count;
}
/*
* Uses above functions to calculate the mana
* gained for a given class level - Kregor
*/
int get_max_mana( CHAR_DATA *ch, int class )
{
int mana, lev;
push_call("get_max_mana(%p)",ch);
if (!class_level(ch, class))
{
pop_call();
return 0;
}
if (class_table[class].mana_table == MANA_NONE)
{
pop_call();
return 0;
}
for (mana = lev = 0 ; lev <= max_spell_circle(ch, class) ; lev++)
{
mana += get_slot_count(ch, class, lev) * UMAX(0, lev * 2 - 1);
}
if (mana > 0)
{
mana += ch->apply[APPLY_MANA];
}
pop_call();
return(UMAX(0,mana));
}
/*
* The number of a given level of a spell
* spontaneous caster may learn - Kregor
*/
int can_learn_spells( CHAR_DATA *ch, int class, int level )
{
int count = 0;
int lvl = 0;
push_call("can_learn_spells(%p,%p,%p)",ch,class,level);
if (level < 0 || level > 9)
{
log_printf("can_learn_spells: spell level out of range!");
pop_call();
return 0;
}
if ((lvl = eff_caster_level(ch, class)) <= 0)
{
pop_call();
return 0;
}
if (class == CLASS_BARD && level > 6)
{
pop_call();
return 0;
}
switch (class_table[class].mana_table)
{
case MANA_BARD:
count = bard_known_table[lvl].spell_level[level];
break;
case CLASS_SORCERER:
count = sorcerer_known_table[lvl].spell_level[level];
break;
default:
count = 0;
}
pop_call();
return count;
}
/*
* Returns TRUE if the number above is met
* clears extra spells from preparation if
* it was exceeded. - Kregor
*/
int slots_full( CHAR_DATA *ch, int class, int level )
{
int sn, count;
push_call("slots_full(%p,%p,%p)",ch,class,level);
for (count = sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
{
if (!is_spell(sn))
continue;
if (prepared(ch, sn) == class && circle_by_class(ch, sn, class) == level)
count++;
if (count > get_slot_count(ch, class, level))
{
ch->pcdata->prepared[sn] = 0;
count--;
}
}
pop_call();
return count;
}
/*
* Returns number of spells learned of a given level
* for spontaneous casters - Kregor
*/
int slots_learned( CHAR_DATA *ch, int class, int level )
{
int sn, count, classes;
push_call("slots_learned(%p,%p,%p)",ch,class,level);
for (count = sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
{
if (!is_spell(sn))
continue;
if ((classes = learned(ch, sn)) <= 0)
continue;
if (!IS_SET(classes, 1 << class))
continue;
//don't count bloodline bonus spell in number learned
if (class == CLASS_SORCERER && skill_table[sn].bloodline[get_bloodline(ch)] == level)
continue;
if (skill_table[sn].skill_level[class] != level)
continue;
count++;
}
pop_call();
return count;
}
/*
* return TRUE if onlooker can see the spell being cast - Kregor
*/
bool can_see_casting(CHAR_DATA *ch, CHAR_DATA *caster, int sn)
{
int feats = caster->metamagic;
push_call("can_see_casting(%p,%p,%p)",ch,caster,sn);
if (!caster->casting)
{
pop_call();
return FALSE;
}
if (IS_SET(feats, METAMAGIC_DISGUISE))
{
pop_call();
return FALSE;
}
if (ch == NULL)
{
pop_call();
return FALSE;
}
if (IS_SET(skill_table[sn].flags, SF_VERBAL))
{
if (!IS_SET(feats, METAMAGIC_SILENT) && can_hear(ch, caster))
{
pop_call();
return TRUE;
}
}
if (IS_SET(skill_table[sn].flags, SF_SOMATIC))
{
if (!IS_SET(feats, METAMAGIC_STILL) && can_see(ch, caster))
{
pop_call();
return TRUE;
}
}
pop_call();
return FALSE;
}
/*
* Returns -1 if one cannot cast the spell, otherwise it returns the
* caster level. Modified to allow mobs with race or classes set
* cast based on their race and class specs, otherwise, generic
* mobs cast any spell at their level - Kregor 04/13/07
*/
int get_caster_level( CHAR_DATA *ch, int sn )
{
int level = -1;
int class;
push_call("get_caster_level(%p,%p)",ch,sn);
if (!is_spell(sn))
{
log_build_printf(ch->pIndexData->vnum, "get_caster_level: %s: not a spell", skill_table[sn].name);
pop_call();
return -1;
}
// Don't bother with all the below if it's already being cast.
if (ch->casting && ch->cast_sn == sn && ch->cast_level != -1)
{
pop_call();
return ch->cast_level;
}
if (IS_NPC(ch))
{
if (IS_CLASSED(ch))
{
if ((level = multi_caster_level(ch, sn)) != -1)
{
pop_call();
return(level);
}
}
if (get_race(ch) > RACE_NONE)
{
if (race_skill(ch, sn))
{
level = ch->level;
pop_call();
return(level);
}
else
{
log_build_printf(ch->pIndexData->vnum, "get_caster_level: %s: not valid spell for race or class", skill_table[sn].name);
pop_call();
return(-1);
}
}
else
{
pop_call();
return(UMIN(ch->level, 30));
}
pop_call();
return(level);
}
/* prevent clerics from casting opposing spells regardless of multiclass */
if (!IS_NPC(ch) && class_level(ch, CLASS_CLERIC))
{
if (opposing_domain(ch, sn))
{
send_to_char( "Your ethos prevents you from casting that spell.\n\r", ch );
pop_call();
return -1;
}
}
/* if not prepared, we fall back to spontaneous casting */
if ((class = prepared(ch, sn)) == -1)
{
if ((class = spontaneous_cast(ch, sn)) == -1)
{
if (!race_skill(ch, sn))
{
send_to_char( "You have not prepared that spell.\n\r", ch);
pop_call();
return -1;
}
else
{
pop_call();
return ch->level;
}
}
}
level = eff_caster_level(ch, class); //adds prestige classes that add caster levels
//caster level for Pally/Rgr is half actual level - Kregor
if (class_table[class].mana_table == MANA_WARRIOR)
{
level -= class_level(ch, class) / 2;
}
wiz_printf("Actual caster level: %d", level);
// Mystic Theurge Shared Circle ability - Kregor
if (class_level(ch, CLASS_MYSTIC_THEURGE))
{
if (circle_by_class(ch, sn, class) <= ROUNDUP(class_level(ch, CLASS_MYSTIC_THEURGE) / 2))
{
if (class == CLASS_CLERIC || class == CLASS_DRUID)
{
level += class_level(ch, CLASS_WIZARD) + class_level(ch, CLASS_SORCERER);
}
else if (class == CLASS_WIZARD || class == CLASS_SORCERER)
{
level += class_level(ch, CLASS_CLERIC) + class_level(ch, CLASS_DRUID);
}
}
}
if (class == CLASS_WIZARD && school_spell(ch, sn)) // specialist wizards cast school spells at +1 caster level
level++;
if (class == CLASS_SORCERER) // bloodline abilities which give caster level bonus
{
if (IS_SET(skill_table[sn].spell_desc, SDESC_AIR) && get_bloodline(ch) == BLOODLINE_AIR)
level++;
if (IS_SET(skill_table[sn].spell_desc, SDESC_EARTH) && get_bloodline(ch) == BLOODLINE_EARTH)
level++;
if (IS_SET(skill_table[sn].spell_desc, SDESC_FIRE) && get_bloodline(ch) == BLOODLINE_FIRE)
level++;
if (IS_SET(skill_table[sn].spell_desc, SDESC_WATER) && get_bloodline(ch) == BLOODLINE_WATER)
level++;
if (race_skill(ch, gsn_elemental_affinity))
{
if (ch->race == RACE_PLANETOUCHED_AIR && get_bloodline(ch) == BLOODLINE_AIR
&& skill_table[sn].bloodline[BLOODLINE_AIR] <= max_spell_circle(ch, CLASS_SORCERER))
{
level++;
}
if (ch->race == RACE_PLANETOUCHED_FIRE && get_bloodline(ch) == BLOODLINE_FIRE
&& skill_table[sn].bloodline[BLOODLINE_FIRE] <= max_spell_circle(ch, CLASS_SORCERER))
{
level++;
}
if (ch->race == RACE_PLANETOUCHED_EARTH && get_bloodline(ch) == BLOODLINE_EARTH
&& skill_table[sn].bloodline[BLOODLINE_EARTH] <= max_spell_circle(ch, CLASS_SORCERER))
{
level++;
}
if (ch->race == RACE_PLANETOUCHED_WATER && get_bloodline(ch) == BLOODLINE_WATER
&& skill_table[sn].bloodline[BLOODLINE_WATER] <= max_spell_circle(ch, CLASS_SORCERER))
{
level++;
}
}
else if (race_skill(ch, gsn_fiendish_affinity))
{
if (get_bloodline(ch) == BLOODLINE_ABYSSAL
&& skill_table[sn].bloodline[BLOODLINE_ABYSSAL] <= max_spell_circle(ch, CLASS_SORCERER))
{
level++;
}
else if (get_bloodline(ch) == BLOODLINE_INFERNAL
&& skill_table[sn].bloodline[BLOODLINE_INFERNAL] <= max_spell_circle(ch, CLASS_SORCERER))
{
level++;
}
}
if (race_skill(ch, gsn_celestial_affinity) && get_bloodline(ch) == BLOODLINE_CELESTIAL
&& skill_table[sn].bloodline[BLOODLINE_CELESTIAL] <= max_spell_circle(ch, CLASS_SORCERER))
{
level++;
}
if (race_skill(ch, gsn_shadow_affinity) && IS_SET(skill_table[sn].spell_desc, SDESC_DARKNESS))
{
level++;
}
}
if (class == CLASS_CLERIC) // domain benefits which give caster level bonus
{
if (has_domain(ch, DOMAIN_KNOWLEDGE) && IS_SET(skill_table[sn].spell_school, SCHOOL_DIVINATION))
level++;
if (has_domain(ch, DOMAIN_GOOD) && IS_SET(skill_table[sn].spell_desc, SDESC_GOOD))
level++;
if (has_domain(ch, DOMAIN_CHAOS) && IS_SET(skill_table[sn].spell_desc, SDESC_CHAOTIC))
level++;
if (has_domain(ch, DOMAIN_EVIL) && IS_SET(skill_table[sn].spell_desc, SDESC_EVIL))
level++;
if (has_domain(ch, DOMAIN_LAW) && IS_SET(skill_table[sn].spell_desc, SDESC_LAWFUL))
level++;
if (race_skill(ch, gsn_elemental_affinity))
{
if (ch->race == RACE_PLANETOUCHED_AIR && has_domain(ch, DOMAIN_AIR)
&& skill_table[sn].domains[DOMAIN_AIR] <= max_spell_circle(ch, CLASS_CLERIC))
{
level++;
}
if (ch->race == RACE_PLANETOUCHED_FIRE && has_domain(ch, DOMAIN_FIRE)
&& skill_table[sn].domains[DOMAIN_FIRE] <= max_spell_circle(ch, CLASS_CLERIC))
{
level++;
}
if (ch->race == RACE_PLANETOUCHED_EARTH && has_domain(ch, DOMAIN_EARTH)
&& skill_table[sn].domains[DOMAIN_EARTH] <= max_spell_circle(ch, CLASS_CLERIC))
{
level++;
}
if (ch->race == RACE_PLANETOUCHED_WATER && has_domain(ch, DOMAIN_WATER)
&& skill_table[sn].domains[DOMAIN_WATER] <= max_spell_circle(ch, CLASS_CLERIC))
{
level++;
}
}
if (race_skill(ch, gsn_fiendish_affinity) && has_domain(ch, DOMAIN_EVIL)
&& skill_table[sn].domains[DOMAIN_EVIL] <= max_spell_circle(ch, CLASS_CLERIC))
{
level++;
}
if (race_skill(ch, gsn_celestial_affinity) && has_domain(ch, DOMAIN_GOOD)
&& skill_table[sn].domains[DOMAIN_GOOD] <= max_spell_circle(ch, CLASS_CLERIC))
{
level++;
}
if (race_skill(ch, gsn_shadow_affinity) && has_domain(ch, DOMAIN_DARKNESS)
&& skill_table[sn].domains[DOMAIN_DARKNESS] <= max_spell_circle(ch, CLASS_CLERIC))
{
level++;
}
}
wiz_printf("Effective caster level: %d", level);
pop_call();
return(level);
}
/*
* returns the class CH can cast a spell spontaneously
* grabbing the first class that has mana to cast it,
* or -1 if cannot be spontaenously cast by CH in any class - Kregor
*/
int spontaneous_cast( CHAR_DATA *ch, int sn )
{
int circle, class, skill, cnt;
push_call("spontaneous_cast(%p,%p)",ch,sn);
circle = class = -1;
if (!is_spell(sn))
{
pop_call();
return -1;
}
if ((skill = learned(ch, sn)) <= 0)
{
pop_call();
return -1;
}
// spontaneous domain casting, instead of spontaneous cure
if (class_level(ch, CLASS_CLERIC) && IS_SHIFT(skill, CLASS_CLERIC))
{
for (cnt = 0 ; cnt < MAX_DOMAIN ; cnt++)
{
if (has_domain(ch, cnt))
{
if ((circle = skill_table[sn].domains[cnt]) <= max_spell_circle(ch, CLASS_CLERIC))
{
if (ch->mana[CLASS_CLERIC] >= get_mana(ch, sn, skill_table[sn].domains[cnt], CLASS_CLERIC))
{
class = CLASS_CLERIC;
}
}
}
}
}
// druids spontaneous Nature's Ally spells
if (class == -1)
{
if (class_level(ch, CLASS_DRUID) && IS_SHIFT(skill, CLASS_DRUID))
{
if (!str_prefix(skill_table[sn].name, "natures ally"))
{
if ((circle = circle_by_class(ch, sn, CLASS_DRUID)) != -1)
{
if (ch->mana[CLASS_DRUID] >= get_mana(ch, sn, circle, CLASS_DRUID))
{
class = CLASS_DRUID;
}
}
}
}
}
if (class == -1)
{
if (class_level(ch, CLASS_SORCERER) && IS_SHIFT(skill, CLASS_SORCERER))
{
if ((circle = circle_by_class(ch, sn, CLASS_SORCERER)) != -1)
{
if (ch->mana[CLASS_SORCERER] >= get_mana(ch, sn, circle, CLASS_SORCERER))
{
class = CLASS_SORCERER;
}
}
}
}
if (class == -1)
{
if (class_level(ch, CLASS_BARD) && IS_SHIFT(skill, CLASS_BARD))
{
if ((circle = circle_by_class(ch, sn, CLASS_BARD)) != -1)
{
if (ch->mana[CLASS_BARD] >= get_mana(ch, sn, circle, CLASS_BARD))
{
class = CLASS_BARD;
}
}
}
}
pop_call();
return class;
}
/*
* Revised to return only the highest caster level
* that could cast the spell - Kregor 4/13/07
*/
int multi_caster_level( CHAR_DATA *ch, int sn)
{
int cnt, mlv;
push_call("multi_caster_level(%p,%p)",ch,sn);
mlv = -1;
for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
{
if (!class_level(ch, cnt))
continue;
if (skill_table[sn].skill_level[cnt] < LEVEL_IMMORTAL && max_spell_circle(ch, cnt) >= skill_table[sn].skill_level[cnt])
{
mlv = UMAX(class_level(ch, cnt), mlv);
}
}
pop_call();
return(mlv);
}
/*
* Returns -1 if given class cannot cast a spell
* at the character's given class level, otherwise
* returns circle of spell. Assumes check already made
* for whether spell is known. - Kregor 10/9/07
*/
int circle_by_class( CHAR_DATA *ch, int sn, int class )
{
int level, cnt;
push_call("circle_by_class(%p,%p,%p)",ch,sn,class);
level = -1;
if (class == -1)
{
pop_call();
return(-1);
}
if (class == CLASS_CLERIC)
{
if (IS_GOOD(ch) && IS_SET(skill_table[sn].spell_desc, SDESC_EVIL) && !IS_SET(skill_table[sn].spell_desc, SDESC_GOOD))
{
pop_call();
return -1;
}
if (IS_EVIL(ch) && IS_SET(skill_table[sn].spell_desc, SDESC_GOOD) && !IS_SET(skill_table[sn].spell_desc, SDESC_EVIL))
{
pop_call();
return -1;
}
if (IS_CHAOTIC(ch) && IS_SET(skill_table[sn].spell_desc, SDESC_LAWFUL) && !IS_SET(skill_table[sn].spell_desc, SDESC_CHAOTIC))
{
pop_call();
return -1;
}
if (IS_LAWFUL(ch) && IS_SET(skill_table[sn].spell_desc, SDESC_CHAOTIC) && !IS_SET(skill_table[sn].spell_desc, SDESC_LAWFUL))
{
pop_call();
return -1;
}
for (cnt = 0 ; cnt < MAX_DOMAIN ; cnt++)
{
if (has_domain(ch, cnt))
{
if (max_spell_circle(ch, class) >= skill_table[sn].domains[cnt])
{
level = skill_table[sn].domains[cnt];
break;
}
}
}
}
if (level == -1 && max_spell_circle(ch, class) >= skill_table[sn].skill_level[class])
{
level = skill_table[sn].skill_level[class];
}
pop_call();
return(level);
}
/*
* Revised to return the highest spell circle if NPC,
* or the circle for the class prepared in if PC
* or the native spell circle if caster is NULL - Kregor 10/9/07
* Added reading casting data to get circle from cast spell - Kregor 11/6/10
*/
int get_spell_circle( CHAR_DATA *ch, int sn)
{
int class, mlv;
push_call("get_spell_circle(%p,%p)",ch,sn);
mlv = -1;
if (ch == NULL)
{
pop_call();
return skill_table[sn].native_level;
}
// logically, if casting this spell, then the spell circle is already known.
// if cast_circle is < 0, then it's an obj or race cast, which uses native circle.
if (ch->casting && ch->cast_sn == sn)
{
if (ch->cast_circle >= 0)
{
pop_call();
return (ch->cast_circle);
}
else
{
pop_call();
return (skill_table[sn].native_level);
}
}
if (IS_NPC(ch))
{
if (IS_CLASSED(ch))
{
if ((class = multi(ch, sn)) <= 0)
{
pop_call();
return -1;
}
mlv = skill_table[sn].skill_level[class];
}
else
{
mlv = skill_table[sn].native_level;
}
}
else
{
if ((class = prepared(ch, sn)) == -1)
{
if ((class = spontaneous_cast(ch, sn)) == -1)
{
if (!race_skill(ch, sn))
{
mlv = -1;
}
else
{
mlv = skill_table[sn].native_level;
}
}
}
if (class != -1)
{
mlv = circle_by_class(ch, sn, class);
}
}
if (ch != NULL)
wiz_printf("{058}get_spell_circle: %s circle %s", numbersuf(mlv), class > 0 ? class_types[class] : "");
pop_call();
return(mlv);
}
/*
* Return caster level of obj - Kregor 4/13/07
* Blank or insuffient value on objects
* is overridden by minimum level to cast.
*/
int item_caster_level( OBJ_DATA *obj, int sn )
{
int mlv;
push_call("item_caster_level(%p,%p)",obj,sn);
if (sn == -1 || !is_spell(sn))
{
pop_call();
return -1;
}
mlv = (get_spell_circle(NULL, sn) * 2) - 1;
if (IS_OBJ_TYPE(obj, ITEM_STAFF)
|| IS_OBJ_TYPE(obj, ITEM_WAND)
|| IS_OBJ_TYPE(obj, ITEM_POTION)
|| IS_OBJ_TYPE(obj, ITEM_PILL))
{
if (obj->value[0] > mlv)
mlv = obj->value[0];
}
pop_call();
return(mlv);
}
/*
* checks to see if specialist wizard has
* prepared a school spell in a given level
*/
bool prepared_school( CHAR_DATA *ch, int level )
{
int sn;
push_call("prepared_school(%p,%p)",ch,level);
if (IS_NPC(ch) || !class_level(ch, CLASS_WIZARD))
{
pop_call();
return FALSE;
}
for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
{
if (!is_spell(sn))
continue;
if (skill_table[sn].skill_level[CLASS_WIZARD] != level)
continue;
if (skill_table[sn].spell_school != get_school(ch))
continue;
if (prepared(ch, sn) == CLASS_WIZARD)
{
pop_call();
return TRUE;
}
}
pop_call();
return FALSE;
}
// /*
// * checks to see if a cleric has
// * prepared a domain spell in a given level
// */
// bool prepared_domain( CHAR_DATA *ch, int level )
// {
// int sn, dom;
//
// push_call("prepared_school(%p,%p)",ch,level);
//
// if (IS_NPC(ch) || !class_level(ch, CLASS_CLERIC))
// {
// pop_call();
// return FALSE;
// }
//
// for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
// {
// if (!is_spell(sn))
// continue;
//
// for (dom = 0 ; dom < MAX_DOMAIN ; dom++)
// {
// if (!ch->pcdata->domain[dom])
// continue;
//
// if (skill_table[sn].domains[dom] != level)
// continue;
//
// if (prepared(ch, sn) == CLASS_CLERIC)
// {
// pop_call();
// return TRUE;
// }
// }
// }
//
// pop_call();
// return FALSE;
// }
//
/*
* Answer me TRUE if you are a domain spell at X level
*/
bool domain_spell( CHAR_DATA *ch, int sn, int level )
{
int dom;
push_call("domain_spell(%p,%p,%p)",ch,sn,level);
if (!class_level(ch, CLASS_CLERIC))
{
pop_call();
return FALSE;
}
for (dom = 0 ; dom < MAX_DOMAIN ; dom++)
{
if (!has_domain(ch, dom))
continue;
if (skill_table[sn].domains[dom] != level)
continue;
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
/*
* Answer me TRUE if a spell is opposite cleric's alignment
*/
bool opposing_domain( CHAR_DATA *ch, int sn )
{
push_call("opposing_domain(%p,%p)",ch,sn);
if (!class_level(ch, CLASS_CLERIC))
{
pop_call();
return FALSE;
}
if (IS_GOOD(ch) && IS_SET(skill_table[sn].spell_desc, SDESC_EVIL) && !IS_SET(skill_table[sn].spell_desc, SDESC_GOOD))
{
pop_call();
return TRUE;
}
if (IS_EVIL(ch) && IS_SET(skill_table[sn].spell_desc, SDESC_GOOD) && !IS_SET(skill_table[sn].spell_desc, SDESC_EVIL))
{
pop_call();
return TRUE;
}
if (IS_CHAOTIC(ch) && IS_SET(skill_table[sn].spell_desc, SDESC_LAWFUL) && !IS_SET(skill_table[sn].spell_desc, SDESC_CHAOTIC))
{
pop_call();
return TRUE;
}
if (IS_LAWFUL(ch) && IS_SET(skill_table[sn].spell_desc, SDESC_CHAOTIC) && !IS_SET(skill_table[sn].spell_desc, SDESC_LAWFUL))
{
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
/*
* Caved in and went the way of NWN and 2E, made opposing schools
* automatic and fixed. Helps prevent school optimizing anyway - Kregor
*/
int opp_school( CHAR_DATA *ch )
{
int school;
push_call("opp_school(%p)",ch);
if (!class_level(ch, CLASS_WIZARD))
{
pop_call();
return -1;
}
switch (get_school(ch))
{
default:
school = -1;
break;
case SCHOOL_ABJURATION:
school = SCHOOL_TRANSMUTATION;
break;
case SCHOOL_TRANSMUTATION:
school = SCHOOL_ABJURATION;
break;
case SCHOOL_CONJURATION:
school = SCHOOL_NECROMANCY;
break;
case SCHOOL_DIVINATION:
school = SCHOOL_ILLUSION;
break;
case SCHOOL_ENCHANTMENT:
school = SCHOOL_EVOCATION;
break;
case SCHOOL_EVOCATION:
school = SCHOOL_ENCHANTMENT;
break;
case SCHOOL_ILLUSION:
school = SCHOOL_DIVINATION;
break;
case SCHOOL_NECROMANCY:
school = SCHOOL_CONJURATION;
break;
}
pop_call();
return school;
}
/*
* Answer me TRUE if a spell is in PC's specialty school - Kregor
*/
bool school_spell( CHAR_DATA *ch, int sn )
{
int school;
push_call("school_spell(%p,%p)",ch,sn);
if (IS_NPC(ch) || !class_level(ch, CLASS_WIZARD))
{
pop_call();
return FALSE;
}
if ((school = get_school(ch)) <= 0)
{
pop_call();
return FALSE;
}
if (school == skill_table[sn].spell_school)
{
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
/*
* Answer me TRUE if a spell is in PC's opposition schools - Kregor
*/
bool opposing_school( CHAR_DATA *ch, int sn )
{
int school;
push_call("opposing_school(%p,%p)",ch,sn);
if (IS_NPC(ch) || !class_level(ch, CLASS_WIZARD))
{
pop_call();
return FALSE;
}
if ((school = opp_school(ch)) == 0)
{
pop_call();
return FALSE;
}
if (school == skill_table[sn].spell_school)
{
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
/*
* Is a spell known in a given class?
* Support for d20 spell learning, because you
* can learn a spell that overlaps classes
* but only know one of the types. Solution
* is to set the bitvector of the class, since
* it will be base classes only - Kregor
*/
bool learned_in_class(CHAR_DATA *ch, int sn, int class)
{
push_call("learned_in_class(%p,%p,%p)",ch,sn,class);
if (IS_NPC(ch))
{
pop_call();
return FALSE;
}
if (IS_SET(learned(ch, sn), 1 << class))
{
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
/*
* Is a spell scribed into given spellbook?
* Support for d20 spell learning - Kregor
*/
bool spell_in_book(OBJ_DATA *obj, int sn)
{
push_call("spell_in_book(%p,%p)",obj,sn);
if (obj == NULL || !IS_OBJ_TYPE(obj, ITEM_SPELLBOOK))
{
pop_call();
return FALSE;
}
if (!is_spell(sn))
{
pop_call();
return FALSE;
}
if (obj->scribed[sn])
{
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
/*
* Calculate the range of a spell based on range setting
* and caster level of the spell - Kregor
*/
int get_spell_range( int level, int sn )
{
int range;
push_call("get_spell_range(%p,%p)",level,sn);
if (IS_SET(skill_table[sn].flags, SF_CLOSE_RANGE))
{
range = level / 2 * 5 + 25;
}
else if (IS_SET(skill_table[sn].flags, SF_MEDIUM_RANGE))
{
range = level * 10 + 100;
}
else if (IS_SET(skill_table[sn].flags, SF_LONG_RANGE))
{
range = level * 40 + 400;
}
else
{
pop_call();
return 0;
}
pop_call();
return UMAX(1, range / 30); // range in room count = feet / 30 ft.
}
/*
* Added value to Knowledge skills by granting
* synergy bonus to the maximum hit dice of
* assumed form based on the related knowledge skill - Kregor
*/
int polymorph_synergy( CHAR_DATA *ch, int race )
{
int skill, ranks;
push_call("polymorph_synergy()");
switch (race_table[race].type)
{
case RTYPE_ABERRATION:
case RTYPE_OOZE:
skill = gsn_know_dungeoneering;
break;
case RTYPE_CONSTRUCT:
case RTYPE_DRAGON:
case RTYPE_MAGICAL:
skill = gsn_know_arcana;
break;
case RTYPE_ANIMAL:
case RTYPE_FEY:
case RTYPE_MONSTROUS:
case RTYPE_PLANT:
skill = gsn_know_nature;
break;
case RTYPE_UNDEAD:
skill = gsn_know_religion;
break;
case RTYPE_OUTSIDER:
skill = gsn_know_planes;
break;
}
if ((ranks = learned(ch, skill)) < 5)
{
pop_call();
return 0;
}
pop_call();
return (ranks / 5 + 1);
}
/*
* Utter mystical words for an sn.
* Revamped to include support for silent spell
* and spells with no verbal component - Kregor
*/
void say_spell( CHAR_DATA *ch, int sn )
{
char buf [MAX_STRING_LENGTH];
char buf2 [MAX_STRING_LENGTH];
CHAR_DATA *rch;
OBJ_DATA *scroll;
char *pName;
int iSyl, length, DC, level;
bool spellcraft = FALSE;
bool silent = FALSE;
struct syl_type
{
char *old;
char *new;
};
static const struct syl_type syl_table[] =
{
{ " ", " " },
{ "ar", "abra" },
{ "au", "kada" },
{ "bless", "fido" },
{ "blind", "nose" },
{ "bur", "mosa" },
{ "cu", "judi" },
{ "de", "oculo" },
{ "en", "unso" },
{ "hance", "sch" },
{ "light", "dies" },
{ "lo", "hi" },
{ "mor", "zak" },
{ "move", "sido" },
{ "ob", "kn" },
{ "ness", "lacri" },
{ "ning", "illa" },
{ "per", "duda" },
{ "ra", "gru" },
{ "re", "candus" },
{ "son", "sabru" },
{ "tect", "infra" },
{ "tri", "cula" },
{ "ven", "nofo" },
{ "a", "a" }, { "b", "b" }, { "c", "q" }, { "d", "e" },
{ "e", "z" }, { "f", "y" }, { "g", "o" }, { "h", "p" },
{ "i", "u" }, { "j", "y" }, { "k", "t" }, { "l", "r" },
{ "m", "w" }, { "n", "i" }, { "o", "a" }, { "p", "s" },
{ "q", "d" }, { "r", "f" }, { "s", "g" }, { "t", "h" },
{ "u", "j" }, { "v", "z" }, { "w", "x" }, { "x", "n" },
{ "y", "l" }, { "z", "k" }, { "", "" }
};
push_call("say_spell(%p,%p)",ch,sn);
if (sn == gsn_recite_scroll)
{
if ((scroll = ch->reciting) == NULL)
{
bug("say_spell: NULL scroll", 0);
pop_call();
return;
}
sn = scroll->value[1];
}
level = ch->cast_circle;
buf[0] = '\0';
for (pName = skill_table[sn].name ; *pName != '\0' ; pName += length)
{
for (iSyl = 0 ; (length = strlen(syl_table[iSyl].old)) != 0 ; iSyl++)
{
if (!str_prefix(syl_table[iSyl].old, pName))
{
strcat(buf, syl_table[iSyl].new);
break;
}
}
if ( length == 0 )
{
length = 1;
}
}
sprintf( buf2, "$n utters the words, %s'%s'.", get_color_string(ch, COLOR_SPEECH, VT102_DIM), buf );
sprintf( buf, "$n utters the words, %s'%s'.", get_color_string(ch, COLOR_SPEECH, VT102_DIM), skill_table[sn].name );
/*
make wizcloaked gods even more invis,
their uttering cannot be heard...
*/
if (IS_PLR(ch, PLR_WIZCLOAK))
{
pop_call();
return;
}
if (!IS_SET(skill_table[sn].flags, SF_VERBAL)
|| IS_SET(ch->cast_feats, METAMAGIC_SILENT)
|| IS_SET(ch->cast_feats, METAMAGIC_DISGUISE))
{
silent = TRUE;
}
if (!silent)
act( "You utter the words, $t'$T'.", ch, get_color_string(ch, COLOR_SPEECH, VT102_DIM), skill_table[sn].name, TO_CHAR );
DC = 15 + level;
for (rch = ch->in_room->first_person ; rch ; rch = rch->next_in_room)
{
if (rch == ch)
continue;
if (!can_see_casting(rch, ch, sn))
continue;
if (IS_NPC(rch) || IS_PLR(rch, PLR_HOLYLIGHT) || spellcraft_check(rch, ch, sn, spellcraft_roll(rch), DC))
spellcraft = TRUE;
if (spellcraft)
act( "You guess that $n is casting $t.", ch, skill_table[sn].name, rch, TO_VICT);
if (silent)
continue;
if (spellcraft)
{
act( buf, ch, NULL, rch, TO_VICT);
}
else
{
act( buf2, ch, NULL, rch, TO_VICT);
}
}
pop_call();
return;
}
/*
* Look for components either in inventory, or in spellpouch,
* fCast FALSE checks for presence at the beginning of cast,
* TRUE decrements the component uses at release_cast - Kregor 3/2/10
*/
bool check_components( CHAR_DATA *ch, int sn, bool fCast )
{
OBJ_DATA *component, *cont;
int cnt, comp;
bool found = TRUE;
push_call("check_components(%p,%p,%p)",ch,sn,fCast);
if (sn <= 0)
{
pop_call();
return TRUE;
}
// imms and npcs don't need components
if (IS_NPC(ch) || IS_PLR(ch, PLR_HOLYLIGHT))
{
pop_call();
return TRUE;
}
for (cnt = 0 ; cnt < 5 ; cnt++)
{
component = NULL;
if ((comp = skill_table[sn].components[cnt]) <= 0) // if component is null, go no further
continue;
//skip component w/ eschew materials, if 1 gp or less
if (learned(ch, gsn_eschew_materials) && component_table[comp].cost <= 100)
continue;
if (IS_AFFECTED(ch, AFF_GASEOUS))
{
act("You cannot grab your components in your physical state.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
//keep from crashing if calls to NULL component table entry
if (!is_string(component_table[comp].name))
{
bug("check_components: %s bad component type %d", skill_table[sn].name, comp);
pop_call();
return FALSE;
}
for (component = ch->first_carrying ; component ; component = component->next_content)
{
if ((component->item_type == ITEM_COMPONENT && comp == component->value[0])
||(component->item_type == ITEM_TREASURE && comp == component->value[5]))
{
break;
}
if (component->item_type == ITEM_SPELLPOUCH && !IS_SET(component->value[1], CONT_CLOSED))
{
cont = component;
for (component = component->first_content ; component ; component = component->next_content)
{
if ((component->item_type == ITEM_COMPONENT && comp == component->value[0])
||(component->item_type == ITEM_TREASURE && comp == component->value[5]))
{
break;
}
}
if (component)
{
break;
}
else
{
component = cont;
}
}
}
if (component == NULL)
{
ch_printf_color(ch, "You are missing your %s.\n\r", component_table[comp].name);
found = FALSE;
continue;
}
if (fCast && --component->value[1] <= 0)
{
act("$p {108}is consumed in a whisp of smoke.", ch, NULL, NULL, TO_CHAR);
act("$p {108}is comsumed in a whisp of smoke.", ch, NULL, NULL, TO_ROOM);
junk_obj(component);
}
}
pop_call();
return found;
}
/*
* LEARN command for learning spells for any class
* that has to learn some or all of their spells.
* Also learning bard songs for bards.
* Wizards will have the requirement of a spellbook,
* Sorcerers and Bards have their number
* limited to their constant table - Kregor 12/3/07
*/
void do_learn( CHAR_DATA *ch, char *argument )
{
CHAR_DATA *mob = NULL;
OBJ_DATA *book, *scroll, *spellbook;
char arg[MAX_INPUT_LENGTH];
char classname[MAX_INPUT_LENGTH];
char spellname[MAX_INPUT_LENGTH];
char adj[MAX_INPUT_LENGTH];
int sn, class, slot, stat, cost, diceroll;
push_call("do_learn(%p)",ch,argument);
if (IS_NPC(ch))
{
pop_call();
return;
}
if (!is_caster(ch))
{
send_to_char("You don't have any spells to learn.\n\r", ch);
pop_call();
return;
}
if (argument[0] == '\0')
{
send_to_char("Syntax: learn <'spell name'> [class]\n\r", ch);
send_to_char("Syntax: learn <'song name'>\n\r", ch);
pop_call();
return;
}
argument = one_argument(argument, arg);
if ((sn = skill_lookup(arg)) == -1)
{
send_to_char("That is not a spell.\n\r", ch);
pop_call();
return;
}
if (skill_table[sn].skilltype == FSKILL_BARDSONG && !learned(ch, gsn_bardic_song))
{
send_to_char("You cannot learn any bardic songs.\n\r", ch);
pop_call();
return;
}
if (!is_spell(sn) && skill_table[sn].skilltype != FSKILL_BARDSONG)
{
send_to_char("That is not a spell or song.\n\r", ch);
pop_call();
return;
}
sprintf(spellname, "%s", skill_table[sn].name);
if (skill_table[sn].skilltype != FSKILL_BARDSONG)
{
if ((scroll = get_obj_char_type(ch, ITEM_SCROLL)) == NULL
|| scroll->value[1] <= 0 || skill_table[scroll->value[1]].skilltype != FSKILL_BARDSONG)
{
for (mob = ch->in_room->first_person ; mob ; mob = mob->next_in_room)
{
if (IS_NPC(mob) && IS_SET(mob->act, ACT_TRAIN))
{
break;
}
}
if (mob == NULL)
{
ch_printf(ch, "You need sheet music, or a teacher to learn %s from.\n\r", spellname);
pop_call();
return;
}
if (!learned(mob, sn))
{
act("$N does not know $t to teach it to you.", ch, spellname, mob, TO_CHAR);
pop_call();
return;
}
}
// adds a cost for learning from mobile
if (mob)
{
if ((cost = skill_table[sn].native_level * 10000) > ch->gold)
{
act("You need $t to learn that song from $N.", ch, format_coins(cost, TRUE), mob, TO_CHAR);
pop_call();
return;
}
}
if (learned(ch, sn))
{
ch_printf(ch, "You already know %s.\n\r", spellname);
pop_call();
return;
}
// must have enough perform ranks to learn it
if (skill_table[sn].native_level > learned(ch, gsn_perform))
{
ch_printf(ch, "%s is too powerful for you to perform.\n\r", spellname);
pop_call();
return;
}
ch->learned[sn] = 1;
act( "You learn to perform $t.", ch, spellname, NULL, TO_CHAR);
ch->pcdata->skill_level[ch->level][sn] = 1;
if (scroll)
{
act("{138}The staves on $p glow brightly, then vanish!", ch, scroll, NULL, TO_CHAR);
junk_obj(scroll);
}
pop_call();
return;
}
if (argument[0] == '\0')
{
if ((class = multi(ch, sn)) == -1)
{
ch_printf_color(ch, "You cannot learn %s in any of your classes.\n\r", spellname);
pop_call();
return;
}
}
else
{
if ((class = lookup_class(argument)) == -1)
{
send_to_char("That is not a class.\n\r", ch);
pop_call();
return;
}
}
if (learned_in_class(ch, sn, class))
{
ch_printf_color(ch, "You already know %s in that class.\n\r", spellname);
pop_call();
return;
}
sprintf(classname, "%s", class_table[class].who_name_long);
if ((slot = circle_by_class(ch, sn, class)) == -1
|| class_table[class].mana_table == MANA_NONE
|| !class_level(ch, class))
{
ch_printf_color(ch, "You cannot learn %s as a %s.\n\r", spellname, classname);
pop_call();
return;
}
switch (class_table[class].attr_prime)
{
case APPLY_WIS:
send_to_char("You are given spells by your diety. You don't need to learn.\n\r", ch);
pop_call();
return;
case APPLY_INT:
stat = get_curr_int(ch);
sprintf(adj, "intelligent");
break;
case APPLY_CHA:
stat = get_curr_cha(ch);
sprintf(adj, "charismatic");
break;
}
if (slot > stat - 10)
{
ch_printf_color(ch, "You are not %s enough to learn %s.\n\r", adj, spellname);
pop_call();
return;
}
if (max_spell_circle(ch, class) < slot)
{
ch_printf_color(ch, "Your %s level is not high enough to learn %s.\n\r", classname, spellname);
pop_call();
return;
}
if (class_table[class].attr_prime == APPLY_CHA)
{
if (slots_learned(ch, class, slot) >= can_learn_spells(ch, class, slot))
{
ch_printf_color(ch, "You cannot learn any more %d circle %s spells.\n\r", slot, classname);
pop_call();
return;
}
}
if (class == CLASS_WIZARD)
{
book = NULL;
scroll = NULL;
if ((spellbook = get_obj_wear_type(ch, ITEM_SPELLBOOK)) == NULL)
{
send_to_char("You are not holding your spellbook to scribe into.\r\n", ch);
pop_call();
return;
}
if (!IS_OWNER(spellbook, ch))
{
send_to_char("That is not your spellbook to scribe into.\r\n", ch);
pop_call();
return;
}
if (opposing_school(ch, sn))
{
send_to_char("You cannot scribe a spell of a prohibited school.\r\n", ch);
pop_call();
return;
}
cost = slot * 10000;
if (cost > ch->gold)
{
act("You need $t on hand to scribe $T into your spellbook.", ch, format_coins(cost, TRUE), spellname, TO_CHAR);
pop_call();
return;
}
if (!ch->pcdata->bonus_spells)
{
if ((scroll = get_obj_carry_type(ch, ITEM_SCROLL)) == NULL)
{
if ((book = get_obj_carry_type(ch, ITEM_SPELLBOOK)) == NULL || IS_WORN(book))
{
send_to_char("You are not carrying scroll or spellbook to learn from.\n\r", ch);
pop_call();
return;
}
}
if (!is_affected(ch, gsn_read_magic))
{
send_to_char("You must be affected by Read magic to transcribe a spell.\r\n", ch);
pop_call();
return;
}
if (scroll)
{
if (!scroll->identified)
{
send_to_char("You've not identified the writing on this scroll.\r\n", ch);
pop_call();
return;
}
if (scroll->value[1] != sn)
{
send_to_char("That spell is not contained on this scroll.\r\n", ch);
pop_call();
return;
}
}
else if (book)
{
if (!spell_in_book(scroll, sn))
{
send_to_char("That spell is not in this spellbook!\r\n", ch);
pop_call();
return;
}
}
diceroll = spellcraft_roll(ch);
if (spellcraft_check(ch, NULL, sn, diceroll, slot))
{
act( "You fail to sufficiently comprehend the writing on $p.", ch, scroll, NULL, TO_CHAR);
act( "$n tries to scribe $p on $P, but fails.", ch, scroll, spellbook, TO_ROOM);
ch->gold -= cost / 2;
act( "You waste $t in the failed scribing attempt.", ch, format_coins(cost/2, TRUE), NULL, TO_CHAR);
pop_call();
return;
}
}
else
{
if (get_school(ch) != SCHOOL_NONE && skill_table[sn].spell_school != get_school(ch))
{
act("Your bonus spells must come from your specialty school.", ch, NULL, NULL, TO_CHAR);
pop_call();
return;
}
}
act( "You scribe $T into $p.", ch, spellbook, spellname, TO_CHAR);
act( "$n scribes $T into $p.", ch, spellbook, spellname, TO_ROOM);
ch->gold -= cost;
act( "You spend $t in materials to scribe in your spellbook.", ch, format_coins(cost, TRUE), NULL, TO_CHAR);
if (scroll)
{
act( "The writing on $p glows brightly before fading away.", ch, scroll, NULL, TO_CHAR);
act( "The writing on $p glows brightly before fading away.", ch, scroll, NULL, TO_ROOM);
junk_obj(scroll);
}
else if (book)
{
act( "The writing on $p glows brightly before fading away.", ch, book, NULL, TO_CHAR);
act( "The writing on $p glows brightly before fading away.", ch, book, NULL, TO_ROOM);
book->scribed[sn] = 0;
}
spellbook->scribed[sn] = 1;
if (!spellbook->owned_by)
spellbook->owned_by = ch->pcdata->pvnum;
if (ch->pcdata->bonus_spells)
ch->pcdata->bonus_spells--;
}
// ch->learned[sn] += 1 << class;
SET_BIT(ch->learned[sn], 1 << class);
act( "You learn $t as a $T spell.", ch, spellname, classname, TO_CHAR);
SET_BIT(ch->pcdata->skill_level[ch->level][sn], 1 << class);
pop_call();
return;
}
/*
* Allows non-spontaneous casters to prepare
* their spells into slots - Kregor
*/
void do_prepare( CHAR_DATA *ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
char classname[MAX_INPUT_LENGTH];
char adj[MAX_INPUT_LENGTH];
int sn, class, slot, school, stat, cls;
push_call("do_prepare(%p)",ch,argument);
if (IS_NPC(ch))
{
pop_call();
return;
}
if (!is_caster(ch))
{
send_to_char("You don't have any spells to prepare.\n\r", ch);
pop_call();
return;
}
if (ch->position > POS_RESTING)
{
send_to_char("You must be resting to prepare spells.\n\r", ch);
pop_call();
return;
}
/*
* simple enough solution for regulating spell preparation,
* can only be done at max mana, thus, after a full 8-hour rest.
*/
for (cls = 0 ; cls < MAX_CLASS ; cls++)
{
if (!class_level(ch, cls))
continue;
if (ch->mana[cls] < get_max_mana(ch, cls))
{
send_to_char("You can only prepare spells when fully rested.\n\r", ch);
pop_call();
return;
}
}
if (argument[0] == '\0')
{
send_to_char("Syntax: prepare <'spell name'> [class]\n\r", ch);
pop_call();
return;
}
argument = one_argument(argument, arg);
if ((sn = skill_lookup(arg)) == -1 || !is_spell(sn))
{
send_to_char("That is not a spell.\n\r", ch);
pop_call();
return;
}
if (prepared(ch, sn) != -1)
{
ch_printf_color(ch, "That spell is already prepared as a %s spell.\n\r", class_table[prepared(ch, sn)].who_name_long);
send_to_char("You have to FORGET it first if you want to re-prepare it.\n\r", ch);
pop_call();
return;
}
if (argument[0] == '\0')
{
if ((class = multi(ch, sn)) == -1)
{
send_to_char("You cannot prepare that spell in any of your classes.\n\r", ch);
pop_call();
return;
}
}
else
{
if ((class = lookup_class(argument)) == -1)
{
send_to_char("That is not a class.\n\r", ch);
pop_call();
return;
}
}
if (!learned_in_class(ch, sn, class))
{
send_to_char("You don't know that spell in that class.\n\r", ch);
pop_call();
return;
}
if ((slot = circle_by_class(ch, sn, class)) == -1)
{
if (spontaneous_cast(ch, sn) != -1)
{
send_to_char("You cast that spell spontaneously. You don't need to prepare it.\n\r", ch);
pop_call();
return;
}
else
{
send_to_char("You cannot prepare that spell in that class.\n\r", ch);
pop_call();
return;
}
}
switch (class_table[class].attr_prime)
{
case APPLY_WIS:
stat = get_curr_wis(ch);
sprintf(adj, "wise");
break;
case APPLY_INT:
stat = get_curr_int(ch);
sprintf(adj, "intelligent");
break;
case APPLY_CHA:
stat = get_curr_cha(ch);
sprintf(adj, "charismatic");
break;
}
if (slot > stat - 10)
{
ch_printf_color(ch, "You are not %s enough to prepare that spell.\n\r", adj);
pop_call();
return;
}
if (max_spell_circle(ch, class) < slot)
{
send_to_char("Your class level is not high enough.\n\r", ch);
pop_call();
return;
}
if (slots_full(ch, class, slot) >= get_slot_count(ch, class, slot))
{
send_to_char("You cannot prepare any more spells of that level in that class.\n\r", ch);
pop_call();
return;
}
if (class == CLASS_WIZARD)
{
OBJ_DATA *spellbook;
if ((spellbook = get_obj_wear_type(ch, ITEM_SPELLBOOK)) == NULL || !IS_OWNER(spellbook, ch))
{
send_to_char("You are not holding your spellbook to prepare from.\r\n", ch);
pop_call();
return;
}
if (!spell_in_book(spellbook, sn))
{
send_to_char("That spell is not in your spellbook!\r\n", ch);
pop_call();
return;
}
if (opposing_school(ch, sn))
{
send_to_char("You cannot prepare a spell of your opposing school of magic.\r\n", ch);
pop_call();
return;
}
if ((school = get_school(ch)) > 0 && slot != 0 && skill_table[sn].spell_school != school)
{
if (slots_full(ch, class, slot) + 1 >= get_slot_count(ch, class, slot) && !prepared_school(ch, slot))
{
send_to_char("You must prepare at least one spell in your school for each spell level.\n\r", ch);
pop_call();
return;
}
}
}
ch->pcdata->prepared[sn] = class;
sprintf(classname, "%s", class_table[class].who_name_long);
ch_printf_color(ch, "You prepare %s as %s %s spell.\n\r",
skill_table[sn].name, a_an(classname), classname);
act( "$n meditates and prepares a spell.", ch, NULL, NULL, TO_ROOM);
pop_call();
return;
}
/*
* And... forgetting the spell from a prepared slot - Kregor
*/
void do_forget( CHAR_DATA *ch, char *argument )
{
int sn, class, level;
char arg[MAX_INPUT_LENGTH];
push_call("do_forget(%p,%p)",ch,argument);
sn = class = level = -1;
if (IS_NPC(ch))
{
pop_call();
return;
}
if (ch->position != POS_RESTING)
{
send_to_char("You must be resting to prepare spells.\n\r", ch);
pop_call();
return;
}
if (argument[0] == '\0')
{
send_to_char("Syntax forget <all|class|'spell name'> [circle]\n\r", ch);
pop_call();
return;
}
argument = one_argument(argument, arg);
if (!strcasecmp(arg, "all"))
{
send_to_char("You purge all your spells from memory.\n\r", ch);
for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
{
if (!is_spell(sn))
continue;
ch->pcdata->prepared[sn] = -1;
}
pop_call();
return;
}
else if ((class = lookup_class(arg)) != -1)
{
if (class_level(ch, class) <= 0)
{
ch_printf_color(ch, "You aren't a member of the %s class.\n\r", class_table[class].who_name_long);
pop_call();
return;
}
if (argument[0] != '\0')
{
if (!is_number(argument))
{
send_to_char("The second argument must be a number.\n\r", ch);
send_to_char("Syntax forget class [circle]\n\r", ch);
pop_call();
return;
}
if ((level = atol(argument)) < 0 || level > max_spell_circle(ch, class))
{
ch_printf_color(ch, "Value must be between 0 and %d.\n\r", max_spell_circle(ch, class));
level = -1;
pop_call();
return;
}
}
if (level == -1)
ch_printf_color(ch, "You purge all your %s spells from memory.\n\r", class_table[class].who_name_long);
else
ch_printf_color(ch, "You purge all your %s circle %s spells from memory.\n\r", numbersuf(level), class_table[class].who_name_long);
for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
{
if (!is_spell(sn))
continue;
if (prepared(ch, sn) != class)
continue;
if (level != -1 && circle_by_class(ch, sn, class) != level)
continue;
ch->pcdata->prepared[sn] = -1;
}
pop_call();
return;
}
else if ((sn = skill_lookup(arg)) == -1 || !is_spell(sn))
{
ch_printf_color(ch, "%s is not a spell.\n\r", arg);
pop_call();
return;
}
if (ch->pcdata->prepared[sn] <= 0)
{
ch_printf_color(ch, "You do not have %s prepared.\n\r", skill_table[sn].name);
pop_call();
return;
}
if ((class = prepared(ch, sn)) && !class_level(ch, class))
{
send_to_char("Something has gone wrong...\n\r", ch);
bug("do_forget: %s - forgetting spell %s in a class it doesn't have.\n\r", ch->name, skill_table[sn].name);
pop_call();
return;
}
ch_printf_color(ch, "You purge %s from your prepared %s spells.\n\r", skill_table[sn].name, class_table[class].who_name_long);
ch->pcdata->prepared[sn] = 0;
pop_call();
return;
}
/*
* Determines any metamagic which could not be applied to spell.
* Will alter current casting metamagic feats. fCasting FALSE
* will return the effective spell circle instead, used for get_mana
* calculations.
*/
int get_metamagic( CHAR_DATA *ch, int sn, int feats, int circle, int class, bool fCasting )
{
int eff_circle, flags, max_circle;
char buf[MAX_INPUT_LENGTH];
push_call("get_metamagic_level(%p,%p,%p,%p,%p)",ch,sn,feats,class,fCasting);
flags = skill_table[sn].flags;
sprintf(buf, "%s", skill_table[sn].name);
max_circle = max_spell_circle(ch, class);
if (IS_SET(feats, METAMAGIC_DISGUISE))
{
if ((eff_circle = circle + 1) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot disguise '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_DISGUISE);
}
else
{
circle += 1;
}
}
if (IS_SET(feats, METAMAGIC_EMPOWER))
{
if (IS_SET(flags, SF_NOVARIABLE))
{
if (fCasting)
ch_printf_color(ch, "Cannot empower '%s'; spell has no variable affect.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_EMPOWER);
}
else if (strstr(skill_table[sn].name, "cure") && learned(ch, gsn_empower_curing))
{
if (fCasting)
ch_printf_color(ch, "Cannot empower '%s'; does not stack with Empower Curing.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_EMPOWER);
}
else if (strstr(skill_table[sn].name, "inflict") && learned(ch, gsn_empower_infliction))
{
if (fCasting)
ch_printf_color(ch, "Cannot empower '%s'; does not stack with Empower Infliction.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_EMPOWER);
}
else if ((eff_circle = circle + 2) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot empower '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_EMPOWER);
}
else
{
circle += 2;
}
}
if (IS_SET(feats, METAMAGIC_ENLARGE))
{
if (!IS_SET(flags, SF_CLOSE_RANGE)
&& !IS_SET(flags, SF_MEDIUM_RANGE)
&& !IS_SET(flags, SF_LONG_RANGE))
{
if (fCasting)
ch_printf_color(ch, "Cannot enlarge '%s'; spell has no range.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_ENLARGE);
}
else if ((eff_circle = circle + 1) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot enlarge '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_ENLARGE);
}
else
{
circle += 1;
}
}
if (IS_SET(feats, METAMAGIC_PERSIST))
{
if (IS_SET(flags, SF_INSTANT))
{
if (fCasting)
ch_printf_color(ch, "Cannot persist '%s'; spell has no duration.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_PERSIST);
}
else if (!IS_SET(flags, SF_PERSONAL))
{
if (fCasting)
ch_printf_color(ch, "Cannot persist '%s'; it is not a personal spell.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_PERSIST);
}
else if ((eff_circle = circle + 6) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot persist '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_PERSIST);
}
else
{
circle += 6;
}
}
if (IS_SET(feats, METAMAGIC_EXTEND))
{
if (IS_SET(feats, METAMAGIC_PERSIST))
{
if (fCasting)
ch_printf_color(ch, "Persistent Spell overrides your Extension of '%s'.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_EXTEND);
}
else if (IS_SET(flags, SF_INSTANT))
{
if (fCasting)
ch_printf_color(ch, "Cannot extend '%s'; spell has no duration.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_EXTEND);
}
else if (IS_SET(skill_table[sn].spell_desc, SDESC_POLYMORPH) && get_bloodline(ch) == BLOODLINE_ABERRANT)
{
if (fCasting)
ch_printf_color(ch, "Cannot extend '%s'; does not stack with your bloodline power.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_EXTEND);
}
else if ((eff_circle = circle + 1) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot extend '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_EXTEND);
}
else
{
circle += 1;
}
}
if (IS_SET(feats, METAMAGIC_MAXIMIZE))
{
if (IS_SET(flags, SF_NOVARIABLE))
{
if (fCasting)
ch_printf_color(ch, "Cannot maximize '%s'; spell has no variable affect.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_MAXIMIZE);
}
else if (strstr(skill_table[sn].name, "cure") && domain_apotheosis(ch, DOMAIN_HEALING))
{
if (fCasting)
ch_printf_color(ch, "Cannot maximize '%s'; your domain already maximizes it.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_EMPOWER);
}
else if ((eff_circle = circle + 3) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot maximize '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_MAXIMIZE);
}
else
{
circle += 3;
}
}
if (IS_SET(feats, METAMAGIC_MERCIFUL))
{
if (skill_table[sn].dam_type == DAM_NONE)
{
if (fCasting)
ch_printf_color(ch, "Cannot make '%s' merciful; not a damaging spell.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_MERCIFUL);
}
else if (IS_SET(skill_table[sn].spell_desc, SDESC_DEATH))
{
if (fCasting)
ch_printf_color(ch, "Cannot make '%s' merciful; it's an instant death affect.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_MERCIFUL);
}
}
if (IS_SET(feats, METAMAGIC_QUICKEN))
{
if (skill_table[sn].beats <= CASTING_SWIFT)
{
if (fCasting)
ch_printf_color(ch, "Cannot quicken '%s'; it is already a swift action.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_QUICKEN);
}
else if (IS_SET(ch->action, ACTION_SWIFT))
{
if (fCasting)
ch_printf_color(ch, "Cannot quicken '%s'; you have already taken a swift action.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_QUICKEN);
}
else if ((eff_circle = circle + 4) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot quicken '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_QUICKEN);
}
else
{
circle += 4;
}
}
if (IS_SET(feats, METAMAGIC_REACH))
{
if (!IS_SET(flags, SF_TOUCH))
{
if (fCasting)
ch_printf_color(ch, "Cannot reach cast '%s'; it is not a touch spell.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_REACH);
}
else if ((eff_circle = circle + 2) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot reach cast '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_REACH);
}
else
{
circle += 2;
}
}
if (IS_SET(feats, METAMAGIC_REPEAT))
{
if (!IS_SET(flags, SF_CLOSE_RANGE)
&& !IS_SET(flags, SF_MEDIUM_RANGE)
&& !IS_SET(flags, SF_CLOSE_RANGE))
{
if (fCasting)
ch_printf_color(ch, "Cannot repeat '%s'; spell has no range.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_REPEAT);
}
else if ((eff_circle = circle + 3) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot repeat '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_REPEAT);
}
else
{
circle += 1;
}
}
if (IS_SET(feats, METAMAGIC_SACRED))
{
if (!IS_SET(skill_table[sn].dam_type, DAM_COLD)
&& !IS_SET(skill_table[sn].dam_type, DAM_ELECTRIC)
&& !IS_SET(skill_table[sn].dam_type, DAM_FIRE)
&& !IS_SET(skill_table[sn].dam_type, DAM_ACID)
&& !IS_SET(skill_table[sn].dam_type, DAM_SONIC))
{
if (fCasting)
ch_printf_color(ch, "Cannot make '%s' sacred; not a damaging energy spell.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_SACRED);
}
else if ((eff_circle = circle + 2) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot make '%s' sacred, as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_SACRED);
}
else
{
circle += 2;
}
}
if (IS_SET(feats, METAMAGIC_SILENT))
{
if (!IS_SET(flags, SF_VERBAL))
{
if (fCasting)
ch_printf_color(ch, "Cannot silence '%s'; it has no verbal component.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_SILENT);
}
else if (multi(ch, sn) == CLASS_BARD)
{
if (fCasting)
ch_printf_color(ch, "You cannot cast bardic magic silently.\n\r");
REMOVE_BIT(feats, METAMAGIC_SILENT);
}
else if ((eff_circle = circle + 1) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot silence '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_SILENT);
}
else
{
circle += 1;
}
}
if (IS_SET(feats, METAMAGIC_STILL))
{
if (!IS_SET(flags, SF_SOMATIC))
{
if (fCasting)
ch_printf_color(ch, "Cannot still '%s'; it has no somatic component.\n\r", buf);
REMOVE_BIT(feats, METAMAGIC_STILL);
}
else if ((eff_circle = circle + 1) > max_circle)
{
if (fCasting)
ch_printf_color(ch, "Cannot still '%s', as it would need a %s circle slot.\n\r", buf, numbersuf(eff_circle));
REMOVE_BIT(feats, METAMAGIC_STILL);
}
else
{
circle += 1;
}
}
if (fCasting)
{
pop_call();
return feats;
}
pop_call();
return circle;
}
/*
Bardic song ability by Kregor
Song defaults to morale song, with argument will call
bardic songs learned similar to spell funs.
*/
void do_sing (CHAR_DATA * ch, char *argument)
{
CHAR_DATA *victim;
void *vo = NULL;
char arg[MAX_INPUT_LENGTH];
int sn, level, diceroll, target;
push_call("do_sing(%p,%p)",ch,argument);
if (ch == NULL)
{
pop_call();
return;
}
if (!learned(ch, gsn_bardic_song))
{
send_to_char ("You do not possess bardic song ability.\n\r", ch);
pop_call();
return;
}
if (!CHECK_USES(ch, gsn_bardic_song))
{
pop_call();
return;
}
if (learned(ch, gsn_perform) < 3)
{
send_to_char ("You have to have at least 3 ranks in perform to sing a bard song.\n\r", ch);
pop_call();
return;
}
if (!IS_NPC(ch) && IS_SET(pvnum_index[ch->pcdata->pvnum]->flags, PVNUM_SILENCED))
{
send_to_char ("You cannot sing.\n\r", ch);
pop_call();
return;
}
if (!CAN_TALK(ch))
{
send_to_char ("You are unable to sing.\n\r", ch);
pop_call();
return;
}
one_argument(argument, arg);
if (arg[0] != '\0')
{
if ((sn = skill_lookup(arg)) < 0 || skill_table[sn].skilltype != FSKILL_BARDSONG)
{
send_to_char ("That is not a bard song.\n\r", ch);
pop_call();
return;
}
}
else
{
sn = gsn_song_of_inspiration;
}
if (!learned(ch, sn))
{
send_to_char ("You don't know that song.\n\r", ch);
pop_call();
return;
}
if (is_safe_magic(ch, NULL, sn))
{
pop_call();
return;
}
level = multi_skill_level(ch, gsn_bardic_song);
diceroll = perform_roll(ch);
if (learned(ch, gsn_empower_song))
diceroll += 4;
act( "{138}$n starts to sing...", ch, NULL, NULL, TO_ROOM );
act( "{138}You start to sing...", ch, NULL, NULL, TO_CHAR );
target = skill_table[sn].target;
switch (target)
{
default:
bug( "do_sing: bad target for sn %d.", sn );
pop_call();
return;
case TAR_IGNORE:
break;
case TAR_CHAR_OFFENSIVE:
if ((victim = who_fighting(ch)) == NULL)
{
send_to_char( "You're not fighting anyone.\n\r", ch );
pop_call();
return;
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return;
}
vo = (void *) victim;
break;
case TAR_CHAR_SELF:
case TAR_CHAR_DEFENSIVE:
vo = (void *) ch;
break;
}
(*skill_table[sn].spell_fun) (sn, level, ch, vo, target);
ch->uses[gsn_bardic_song]++;
if (learned(ch, gsn_magna_alumnus))
TAKE_ACTION(ch, ACTION_SWIFT);
else if (learned(ch, gsn_quicken_song))
TAKE_ACTION(ch, ACTION_MOVE);
else
TAKE_ACTION(ch, ACTION_STANDARD);
pop_call();
return;
}
/*
* check to see if a ranged spell can and
* does affect a door in given direction - Kregor
*/
bool check_cast_door( CHAR_DATA *ch, int dir, int sn, int level, bool ForReal )
{
EXIT_DATA *pExit, *pExit_rev;
ROOM_TIMER_DATA *rtd;
bool IsDoor = FALSE;
int hp, hardness, dam, maxdice, nodice, dam_type;
push_call("check_cast_door(%p,%p,%p,%p)",ch,dir,sn,ForReal);
if ((pExit = get_exit(ch->in_room->vnum, dir)) == NULL)
{
if (!ForReal)
act("There's no exit in that direction!", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if ((rtd = get_room_affect(ch->in_room, ROOM_BLOCK)) == NULL || (rtd->modifier != -1 && rtd->modifier != dir))
{
if ((rtd = get_room_affect(room_index[pExit->to_room], ROOM_BLOCK)) == NULL || (rtd->modifier != -1 && rtd->modifier != rev_dir[dir]))
{
if (IS_SET(pExit->exit_info, EX_BASHED) || !IS_SET(pExit->exit_info, EX_CLOSED))
{
if (!ForReal)
act("There's nothing blocking that direction!", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
else
{
IsDoor = TRUE;
}
}
}
if (skill_table[sn].target != TAR_CHAR_OFFENSIVE && sn != gsn_dispel_magic && sn != gsn_greater_dispel && sn != gsn_disjunction)
{
act("Your $t will have no effect on that barrier!", ch, skill_table[sn].noun_damage, NULL, TO_CHAR);
pop_call();
return FALSE;
}
dam_type = skill_table[sn].dam_type;
if ((!IS_SET(dam_type, DAM_PIERCE|DAM_SLASH|DAM_BASH|DAM_ACID|DAM_FIRE|DAM_FORCE|DAM_SONIC)
&& sn != gsn_disintegrate) || IS_SET(dam_type, DAM_NONLETHAL))
{
if ((!rtd && !IS_SET(pExit->exit_info, EX_MAGICAL_LOCK)) || (sn != gsn_dispel_magic && sn != gsn_greater_dispel && sn != gsn_disjunction))
{
if (!ForReal)
act("Your $t will have no effect on that barrier!", ch, skill_table[sn].noun_damage, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act("You really cast in that direction!", ch, NULL, NULL, TO_CHAR);
maxdice = UMAX(skill_table[sn].native_level, skill_table[sn].mana_move) * 2;
nodice = UMIN(level, maxdice);
if (sn == gsn_disintegrate)
dam = spell_dice(ch, sn, level * 2, 6);
else
{
dam = spell_dice(ch, sn, nodice, 6);
/*
* barrier is always an object, so here we calc different damage types rules vs. objects
*/
if (!IS_SET(dam_type, DAM_PHYSICAL|DAM_ACID|DAM_SONIC|DAM_FORCE)) // These do full damage to objects
{
if (IS_SET(dam_type, DAM_ELECTRIC|DAM_FIRE))
dam /= 2;
else
dam /= 4;
}
}
if (rtd)
{
bool Broken = FALSE;
if (sn != gsn_dispel_magic && sn != gsn_greater_dispel && sn != gsn_disjunction)
{
if (rtd->type == gsn_wall_of_ice)
{
hp = rtd->level * 3;
hardness = 0;
if (IS_SET(dam_type, DAM_FIRE))
dam *= 2;
}
else if (rtd->type == gsn_wall_of_stone)
{
hp = rtd->level * 15 / 4;
hardness = 8;
}
else if (rtd->type == gsn_wall_of_iron)
{
hp = rtd->level * 30 / 4;
hardness = 10;
}
else
{
send_to_char( "The barrier cannot be forced open.\n\r", ch );
pop_call();
return TRUE;
}
if (!IS_SET(dam_type, DAM_ACID|DAM_SONIC))
{
dam = UMAX(0, dam - hardness);
}
wiz_printf_room(ch, "Damage: %d vs. Hitpoints: %d\n\r", dam, hp);
if (dam >= hp)
{
act("{118}The $t is sundered by $n's $T!", ch, skill_table[rtd->type].noun_damage, skill_table[sn].noun_damage, TO_ROOM);
act("{118}The $t is sundered by your $T!", ch, skill_table[rtd->type].noun_damage, skill_table[sn].noun_damage, TO_CHAR);
Broken = TRUE;
}
else
{
act("{118}The $t stands firm against $n's $T!", ch, skill_table[rtd->type].noun_damage, skill_table[sn].noun_damage, TO_ROOM);
act("{118}The $t stands firm against your $T!", ch, skill_table[rtd->type].noun_damage, skill_table[sn].noun_damage, TO_CHAR);
pop_call();
return TRUE;
}
}
else
{
if (sn == gsn_disjunction || dice(1,20) + level >= 11 + rtd->level)
{
act("{178}The $t is dispelled from existence!", ch, skill_table[rtd->type].noun_damage, NULL, TO_ALL);
Broken = TRUE;
}
}
if (Broken)
{
del_room_timer(rtd->vnum, rtd->type);
}
}
if (IsDoor)
{
if (sn == gsn_dispel_magic && sn == gsn_greater_dispel && sn == gsn_disjunction)
{
if (!IS_SET(pExit->exit_info, EX_MAGICAL_LOCK))
{
act("Your $T has no effect on the $d", ch, pExit->keyword, skill_table[sn].noun_damage, TO_CHAR);
pop_call();
return TRUE;
}
else
{
REMOVE_BIT(pExit->exit_info, EX_MAGICAL_LOCK);
act("You dispel the arcane lock upon the $d.", ch, pExit->keyword, NULL, TO_CHAR);
pop_call();
return TRUE;
}
}
else
{
act("{118}BLAAAAM!!!{300}", ch, NULL, NULL, TO_CHAR);
act("{118}BLAAAAM!!!{300}", ch, NULL, NULL, TO_ROOM);
hp = 0;
if (IS_SET(pExit->exit_info, EX_BASHPROOF))
{
act("The $d stands firm against your $T.", ch, pExit->keyword, skill_table[sn].noun_damage, TO_CHAR);
act("The $d stands firm against $n's $T.", ch, pExit->keyword, skill_table[sn].noun_damage, TO_ROOM);
pop_call();
return TRUE;
}
else if (IS_SET(pExit->exit_info, EX_IRON_DOOR))
{
hp = UMAX(hp, 60);
hardness = 10;
}
else if (IS_SET(pExit->exit_info, EX_HEAVY_DOOR))
{
hp = UMAX(hp, 20);
hardness = 5;
}
else if (IS_SET(pExit->exit_info, EX_WEAK_DOOR))
{
hp = UMAX(hp, 10);
hardness = 5;
}
else
{
hp = UMAX(hp, 15);
hardness = 5;
}
if (!IS_SET(dam_type, DAM_ACID|DAM_SONIC))
{
dam = UMAX(0, dam - hardness);
}
wiz_printf_room(ch, "Damage: %d vs. Hitpoints: %d\n\r", dam, hp);
if (dam < hp)
{
act("The $d stands firm against your $t.", ch, skill_table[sn].noun_damage, pExit->keyword, TO_CHAR);
act("The $d stands firm against $n's $t.", ch, skill_table[sn].noun_damage, pExit->keyword, TO_ROOM);
}
else
{
act("The $d is blasted open by your $t.", ch, skill_table[sn].noun_damage, pExit->keyword, TO_CHAR);
act("The $d is blasted open by $n's $t.", ch, skill_table[sn].noun_damage, pExit->keyword, TO_ROOM);
REMOVE_BIT(pExit->exit_info, EX_CLOSED);
REMOVE_BIT(pExit->exit_info, EX_LOCKED);
SET_BIT( pExit->exit_info, EX_BASHED );
if ((pExit_rev = room_index[pExit->to_room]->exit[rev_dir[dir]]) != NULL
&& room_index[pExit_rev->to_room] == ch->in_room )
{
CHAR_DATA *rch;
REMOVE_BIT(pExit_rev->exit_info, EX_CLOSED);
REMOVE_BIT(pExit_rev->exit_info, EX_LOCKED);
SET_BIT( pExit_rev->exit_info, EX_BASHED );
for (rch = room_index[pExit->to_room]->first_person ; rch ; rch = rch->next_in_room)
{
act( "{118}BLAAAAM!!!{300}", rch, NULL, NULL, TO_CHAR);
act( "The $d is blasted open from the other side!", rch, NULL, pExit_rev->keyword, TO_CHAR);
}
}
}
}
pop_call();
return TRUE;
}
pop_call();
return TRUE;
}
/*
* Function used to recharge objects with
* storing properites in do_cast - Kregor
*/
bool recharge_obj( CHAR_DATA *ch, OBJ_DATA *obj, int sn )
{
CHAR_DATA *rch, *rch_next;
int val = 0;
push_call("recharge_obj(%p,%p,%p)",ch,obj,sn);
if (!is_spell(sn))
{
send_to_char("That is not a valid spell.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_OBJ_TYPE(obj, ITEM_TREASURE) || !IS_SET(obj->value[0], TFLAG_SPELL_STORING|TFLAG_COUNTERSPELL))
{
if (!IS_OBJ_TYPE(obj, ITEM_STAFF))
{
// act("$p cannot be recharged.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
act("You cast a $T upon $p.", ch, obj, skill_table[sn].name, TO_CHAR);
for (rch = ch->in_room->first_person ; rch != NULL ; rch = rch_next)
{
rch_next = rch->next_in_room;
if (!can_see_casting(rch, ch, sn))
continue;
act( "$n casts a spell on $p.", ch, obj, rch, TO_VICT);
}
if (IS_OBJ_TYPE(obj, ITEM_STAFF))
{
if (obj->value[2] >= obj->value[1])
{
act("$p is already fully charged.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
for (val = 3 ; val <= 7 ; val++)
{
if (val == 7)
{
act("That spell is not present upon $p.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!is_spell(obj->value[val]) || obj->value[val] != sn)
continue;
obj->value[2] = UMIN(obj->value[2] + UMAX(1, skill_table[sn].native_level * 2 / 3), obj->value[1]);
break;
}
}
else
{
for (val = 1 ; val <= 3 ; val++)
{
if (is_spell(obj->value[val]))
{
if (val == 1 && TREASURE_FLAG(obj, TFLAG_COUNTERSPELL))
{
act("There is a spell already stored upon $p.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (val == 3)
{
act("$p is already full of stored spells.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
continue;
}
obj->value[val] = sn;
break;
}
}
act("{138}$p glows briefly.", ch, obj, NULL, TO_ALL);
pop_call();
return TRUE;
}
/*
Apply deity favor for using spells attuned to deity's domains - Kregor
*/
void spell_favor(CHAR_DATA *ch, int sn)
{
push_call("spell_favor(%p,%p)",ch,sn);
if (IS_SET(skill_table[sn].spell_desc, SDESC_AIR))
gain_favor(ch, DOMAIN_AIR, 1);
if (IS_SET(skill_table[sn].spell_desc, SDESC_CHAOTIC))
gain_favor(ch, DOMAIN_CHAOS, 1);
if (IS_SET(skill_table[sn].spell_desc, SDESC_DARKNESS))
gain_favor(ch, DOMAIN_DARKNESS, 1);
if (IS_SET(skill_table[sn].spell_desc, SDESC_DEATH|SDESC_DISEASE|SDESC_POISON))
{
gain_favor(ch, DOMAIN_DEATH, 1);
gain_favor(ch, DOMAIN_DESTRUCTION, 1);
}
if (IS_SET(skill_table[sn].spell_desc, SDESC_EARTH))
gain_favor(ch, DOMAIN_EARTH, 1);
if (IS_SET(skill_table[sn].spell_desc, SDESC_EVIL))
gain_favor(ch, DOMAIN_EVIL, 1);
if (IS_SET(skill_table[sn].spell_desc, SDESC_FIRE))
{
gain_favor(ch, DOMAIN_FIRE, 1);
gain_favor(ch, DOMAIN_SUN, 1);
}
if (IS_SET(skill_table[sn].spell_desc, SDESC_GOOD))
gain_favor(ch, DOMAIN_GOOD, 1);
if (IS_SET(skill_table[sn].spell_desc, SDESC_HEALING))
{
gain_favor(ch, DOMAIN_HEALING, 1);
gain_favor(ch, DOMAIN_RENEWAL, 1);
}
if (IS_SET(skill_table[sn].spell_desc, SDESC_ILLUSION))
gain_favor(ch, DOMAIN_ILLUSION, 1);
if (IS_SET(skill_table[sn].spell_desc, SDESC_LAWFUL))
gain_favor(ch, DOMAIN_LAW, 1);
if (IS_SET(skill_table[sn].spell_desc, SDESC_LIGHT))
{
gain_favor(ch, DOMAIN_MOON, 1);
gain_favor(ch, DOMAIN_SUN, 1);
}
if (IS_SET(skill_table[sn].spell_desc, SDESC_MIND))
gain_favor(ch, DOMAIN_CHARM, 1);
if (IS_SET(skill_table[sn].spell_desc, SDESC_NEGATIVE))
{
gain_favor(ch, DOMAIN_DEATH, 1);
gain_favor(ch, DOMAIN_SUFFERING, 1);
}
if (IS_SET(skill_table[sn].spell_desc, SDESC_WATER))
gain_favor(ch, DOMAIN_WATER, 1);
if (skill_table[sn].spell_school == SCHOOL_ABJURATION)
{
gain_favor(ch, DOMAIN_PROTECTION, 1);
gain_favor(ch, DOMAIN_COMMUNITY, 1);
gain_favor(ch, DOMAIN_PLANNING, 1);
gain_favor(ch, DOMAIN_LIBERATION, 1);
}
if (skill_table[sn].spell_school == SCHOOL_EVOCATION)
{
gain_favor(ch, DOMAIN_DESTRUCTION, 1);
gain_favor(ch, DOMAIN_WRATH, 1);
gain_favor(ch, DOMAIN_WAR, 1);
}
if (skill_table[sn].spell_school == SCHOOL_ENCHANTMENT)
{
gain_favor(ch, DOMAIN_CHARM, 1);
gain_favor(ch, DOMAIN_MADNESS, 1);
}
if (skill_table[sn].spell_school == SCHOOL_ILLUSION)
{
gain_favor(ch, DOMAIN_ILLUSION, 1);
gain_favor(ch, DOMAIN_MADNESS, 1);
gain_favor(ch, DOMAIN_TRICKERY, 1);
}
if (skill_table[sn].spell_school == SCHOOL_NECROMANCY)
{
gain_favor(ch, DOMAIN_DEATH, 1);
gain_favor(ch, DOMAIN_REPOSE, 1);
}
if (skill_table[sn].spell_school == SCHOOL_DIVINATION)
{
gain_favor(ch, DOMAIN_KNOWLEDGE, 1);
gain_favor(ch, DOMAIN_PLANNING, 1);
}
gain_favor(ch, DOMAIN_MAGIC, 1);
pop_call();
return;
}
/*
The kludgy global is for spells who want more stuff from command line.
*/
char * target_name;
/*
* Thoroughly gutted do_cast to put the casting time on a spell.
* Now cues the spell and counts down the release of the spell.
* Also separated main function for use both as a racial cast
* and a normal cast with mana - Kregor
*/
bool cast_spell( CHAR_DATA *ch, char *argument, bool fRacecast )
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
char arg3[MAX_INPUT_LENGTH];
char adj[MAX_INPUT_LENGTH];
CHAR_DATA *victim;
CHAR_DATA *rch, *rch_next;
OBJ_DATA *obj, *symbol;
void *vo;
bool ranged = FALSE;
bool ProtTouch = FALSE;
int mana, sn, level, target, dir, timer, range, class, stat, feats, circle, favor;
push_call("cast_spell(%p,%p)",ch,argument);
if (ch->casting || ch->cast_timer > 0)
{
ch_printf_color(ch, "You are already casting %s. Use STOP to stop casting\n\r.", skill_table[ch->cast_sn].name);
pop_call();
return FALSE;
}
if (in_combat(ch) && !is_active(ch))
{
ch_printf_color(ch, "Just wait your turn!\n\r");
pop_call();
return FALSE;
}
argument = snarf_skill_name(argument, arg1);
target_name = argument;
argument = one_argument( argument, arg2 );
if (*arg1 == '\0')
{
if (fRacecast)
send_to_char( "Syntax: racecast <spell> [direction] [<target>]\n\r", ch );
else
send_to_char( "Syntax: cast <spell> [direction] [<target>]\n\r", ch );
pop_call();
return FALSE;
}
sn = skill_lookup( arg1 );
if (sn < 0 || !is_spell(sn))
{
if (!IS_NPC(ch) && ch->desc == NULL)
{
log_printf("[%u] casting unknown spell: %s", ch->pIndexData->vnum, arg1);
}
send_to_char( "That is not a spell.\n\r", ch );
pop_call();
return FALSE;
}
// Not sure why it wasn't done this way to begin with - Kregor
if (!skill_table[sn].spell_fun || skill_table[sn].spell_fun == spell_null)
{
ch_printf_color(ch, "OOC: That spell is not completed yet.\n\r");
pop_call();
return FALSE;
}
if (IS_SET(ch->action, ACTION_STANDARD) && skill_table[sn].beats >= CASTING_STANDARD)
{
ch_printf_color(ch, "You have already made a standard action this round.\n\r");
pop_call();
return FALSE;
}
if (IS_SET(ch->action, ACTION_SWIFT) && skill_table[sn].beats == CASTING_SWIFT)
{
ch_printf_color(ch, "You have already made a swift action this round.\n\r");
pop_call();
return FALSE;
}
if (fRacecast)
{
if (!race_skill(ch, sn))
{
send_to_char("You cannot use that as a spell-like ability.\n\r", ch);
pop_call();
return FALSE;
}
else
{
level = ch->level;
}
}
else
{
if ((level = get_caster_level(ch, sn)) == -1)
{
pop_call();
return FALSE;
}
}
if (is_safe_magic(ch, NULL, sn))
{
pop_call();
return FALSE;
}
/*
* Determine whether it's a ranged cast or not - Kregor 6/29/07
*/
if (*arg2 != '\0'
&& skill_table[sn].target != TAR_IGNORE
&& skill_table[sn].target != TAR_CHAR_SELF
&& skill_table[sn].target != TAR_OBJ_INV
&& skill_table[sn].target != TAR_OBJ_ROOM
&& skill_table[sn].target != TAR_OBJ_WIELD)
{
if ((dir = direction_door(arg2)) != -1)
{
ranged = TRUE;
target_name = argument;
argument = one_argument( argument, arg2 );
argument = one_argument( argument, arg3 );
}
}
else
{
argument = one_argument( argument, arg3 );
}
if (ranged)
{
if (!get_exit(ch->in_room->vnum, dir)
|| (is_string(arg2) && !is_valid_exit(ch, ch->in_room, dir)))
{
send_to_char( "You cannot cast in that direction.\n\r", ch );
pop_call();
return FALSE;
}
if ((range = get_spell_range(level, sn)) <= 0)
{
ch_printf_color(ch, "That spell cannot be cast at that range.\n\r");
pop_call();
return FALSE;
}
}
if (!fRacecast)
{
if ((circle = get_spell_circle(ch, sn)) < 0)
{
send_to_char("You cannot cast that spell.\n\r", ch);
if (IS_NPC(ch))
log_build_printf(ch->pIndexData->vnum, "do_cast: mobile gets -1 on get_spell_circle");
pop_call();
return FALSE;
}
if (IS_NPC(ch))
{
class = multi(ch, sn);
}
else
{
if ((class = prepared(ch, sn)) == -1)
{
if ((class = spontaneous_cast(ch, sn)) == -1)
{
send_to_char("You have not prepared that spell.\n\r", ch);
pop_call();
return FALSE;
}
}
}
if (!IS_SET(learned(ch, sn), 1 << class))
{
send_to_char("You do not know that spell.\n\r", ch);
pop_call();
return FALSE;
}
if (class == CLASS_DRUID && wears_metal(ch, FALSE))
{
send_to_char("You have displeased nature by wearing metal.\n\r", ch);
pop_call();
return FALSE;
}
switch (class_table[class].attr_prime)
{
case APPLY_WIS:
stat = get_curr_wis(ch);
sprintf(adj, "wise");
break;
case APPLY_INT:
stat = get_curr_int(ch);
sprintf(adj, "intelligent");
break;
case APPLY_CHA:
stat = get_curr_cha(ch);
sprintf(adj, "charismatic");
break;
}
if (circle > stat - 10)
{
ch_printf_color(ch, "You are not %s enough to cast that spell.\n\r", adj);
if (IS_NPC(ch))
log_build_printf(ch->pIndexData->vnum, "cast_spell: mobile stat too low to cast");
pop_call();
return FALSE;
}
if (!IS_NPC(ch) && !IS_GOD(ch) && class_table[class].attr_prime == APPLY_WIS)
{
if (IS_SET(skill_table[sn].flags, SF_DIVINEFOCUS))
{
if (ch->god <= GOD_NEUTRAL)
{
ch_printf_color(ch, "You have to be devoted to a deity to cast that!\n\r");
pop_call();
return FALSE;
}
if ((symbol = get_obj_wear_type(ch, ITEM_SYMBOL)) == NULL)
{
send_to_char( "You don't have your holy symbol.\n\r", ch);
pop_call();
return FALSE;
}
if (symbol->value[2] != ch->god)
{
send_to_char( "You need to be carrying your OWN deity's symbol!\n\r", ch);
pop_call();
return FALSE;
}
}
// Added check and cost of favor for divine spells - Kregor 10/30/13
if (!IS_NPC(ch) && !IS_GOD(ch))
{
switch (circle)
{
default:
favor = 0;
break;
case 7:
favor = 10;
break;
case 8:
favor = 20;
break;
case 9:
favor = 30;
break;
}
if (ch->pcdata->god_favor < favor)
{
send_to_char( "You lack enough favor to cast that!\n\r", ch);
pop_call();
return FALSE;
}
}
}
// process & adjust metamagic before checking set feats.
wiz_printf_room(ch, "cast_spell: metamagic feats set: %s\n\r", ch->metamagic == 0 ? "none" : flag_string(ch->metamagic, metamagic_flags));
feats = get_metamagic(ch, sn, ch->metamagic, circle, class, TRUE);
// circle = get_metamagic(ch, sn, ch->metamagic, circle, class, FALSE);
mana = get_mana(ch, sn, circle, class);
wiz_printf_room(ch, "cast_spell: metamagic feats set: %s\n\r", feats == 0 ? "none" : flag_string(feats, metamagic_flags));
if (ch->mana[class] < mana)
{
ch_printf(ch, "That would take %d mana; you only have %d to expend.\n\r", mana, ch->mana[class]);
pop_call();
return FALSE;
}
if (IS_SET(skill_table[sn].flags, SF_SOMATIC)
&& (hands_full(ch) || !is_handy(ch) || IS_AFFECTED(ch, AFF_GASEOUS))
&& !IS_SET(feats, METAMAGIC_STILL))
{
ch_printf_color(ch, "You have no free hand to cast with.\n\r");
if (IS_NPC(ch))
log_build_printf(ch->pIndexData->vnum, "cast_spell: mobile has no free hand to cast");
pop_call();
return FALSE;
}
if (IS_SET(skill_table[sn].flags, SF_VERBAL) && IS_AFFECTED(ch, AFF2_SILENCE) && !IS_SET(feats, METAMAGIC_SILENT))
{
send_to_char("You cannot seem to muster the words.\n\r", ch);
pop_call();
return FALSE;
}
if (ranged && IS_SET(feats, METAMAGIC_ENLARGE))
{
range *= 2;
}
if (!check_components(ch, sn, FALSE))
{
pop_call();
return FALSE;
}
}
else
{
if (IS_PLR(ch, PLR_WIZTIME))
ch_printf_color(ch, "{058}DEBUG: uses for %s: %d\n\r", skill_table[sn].name, ch->uses[sn]);
if (ch->uses[sn] >= race_skill(ch, sn))
{
send_to_char("You cannot use that ability again without resting.\n\r", ch);
pop_call();
return FALSE;
}
// race casting uses CHA to work, uses native spell level - Kregor
if (get_spell_circle(NULL, sn) > 10 + stat_bonus(TRUE, ch, APPLY_CHA))
{
send_to_char("You are not charismatic enough to use that spell.\n\r", ch);
pop_call();
return FALSE;
}
class = -2;
}
/*
Consider conditional limitations of spells - Kregor
*/
if (IS_SET(skill_table[sn].spell_desc, SDESC_FIRE|SDESC_AIR) && ch->in_room->sector_type == SECT_UNDER_WATER)
{
act("You cannot cast that spell underwater!", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
/*
Locate targets.
*/
victim = NULL;
obj = NULL;
vo = NULL;
target = skill_table[sn].target;
/*
* look for spell storing object cast upon first - Kregor
*/
if (!IS_NPC(ch) && !fRacecast)
{
if (*arg2 != '\0' && (obj = get_obj_list(ch, arg2, ch->first_carrying)) != NULL)
{
if (recharge_obj(ch, obj, sn))
{
ch->mana[class] -= mana;
if (!IS_SET(feats, METAMAGIC_QUICKEN) && skill_table[sn].beats != CASTING_SWIFT)
{
if (skill_table[sn].beats == CASTING_STANDARD)
TAKE_ACTION(ch, ACTION_STANDARD);
else if (skill_table[sn].beats == CASTING_ROUND)
TAKE_ACTION(ch, ACTION_FULL);
}
pop_call();
return TRUE;
}
}
}
if (ranged)
{
switch (target)
{
default:
send_to_char( "That spell cannot be cast into another room!\n\r", ch );
pop_call();
return FALSE;
case TAR_CHAR_OFFENSIVE:
case TAR_CHAR_DEFENSIVE:
case TAR_UNDEAD_OFF:
case TAR_UNDEAD_DEF:
case TAR_OBJ_CHAR_OFF:
case TAR_OBJ_CHAR_DEF:
break;
}
}
if (ranged && !is_string(arg2))
{
if (!check_cast_door(ch, dir, sn, level, FALSE))
{
pop_call();
return FALSE;
}
}
else
{
switch (target)
{
default:
bug( "cast_spell: bad target for sn %d.", sn );
pop_call();
return FALSE;
case TAR_IGNORE:
break;
case TAR_CHAR_OFFENSIVE:
if (arg2[0] == '\0')
{
if (who_fighting(ch) == NULL)
{
send_to_char( "Cast the spell on whom?\n\r", ch );
pop_call();
return FALSE;
}
victim = who_fighting(ch);
}
else
{
if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
{
send_to_char("Your target must have slipped out of sight!\n\r", ch);
pop_call();
return FALSE;
}
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
send_to_char( "Your target isn't here.\n\r", ch );
pop_call();
return FALSE;
}
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
break;
case TAR_UNDEAD_OFF:
if (arg2[0] == '\0')
{
if ((victim = who_fighting(ch)) == NULL || !IS_UNDEAD(who_fighting(ch)))
{
if (IS_UNDEAD(ch))
{
send_to_char( "Cast the spell on whom?\n\r", ch );
pop_call();
return FALSE;
}
else
{
victim = ch;
}
}
}
else
{
if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
{
send_to_char("Your target must have slipped out of sight!\n\r", ch);
pop_call();
return FALSE;
}
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
send_to_char( "Your target isn't here.\n\r", ch );
pop_call();
return FALSE;
}
}
if (IS_UNDEAD(victim) && is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
if (IS_UNDEAD(victim))
target = TAR_CHAR_OFFENSIVE;
else
target = TAR_CHAR_DEFENSIVE;
break;
case TAR_CHAR_DEFENSIVE:
if (arg2[0] == '\0')
{
victim = ch;
}
else
{
if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
{
send_to_char("Your target must have slipped out of sight!\n\r", ch);
pop_call();
return FALSE;
}
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
send_to_char( "Your target isn't here.\n\r", ch );
pop_call();
return FALSE;
}
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
break;
case TAR_UNDEAD_DEF:
if (arg2[0] == '\0')
{
if ((victim = who_fighting(ch)) == NULL || IS_UNDEAD(who_fighting(ch)))
{
if (!IS_UNDEAD(ch))
{
send_to_char( "Cast the spell on whom?\n\r", ch );
pop_call();
return FALSE;
}
else
{
victim = ch;
}
}
}
else
{
if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
{
send_to_char("Your target must have slipped out of sight!\n\r", ch);
pop_call();
return FALSE;
}
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
send_to_char( "Your target isn't here.\n\r", ch );
pop_call();
return FALSE;
}
}
if (!IS_UNDEAD(victim) && is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
if (!IS_UNDEAD(victim))
target = TAR_CHAR_OFFENSIVE;
else
target = TAR_CHAR_DEFENSIVE;
break;
case TAR_CHAR_SELF:
if (ranged)
{
send_to_char( "You cannot cast this spell at range.\n\r", ch );
pop_call();
return FALSE;
}
if (arg2[0] == '\0' || is_name_short(arg2, ch->name))
{
victim = ch;
}
else
{
if (!domain_skill(ch, gsn_protective_touch))
{
send_to_char( "You can only cast this spell upon yourself.\n\r", ch );
pop_call();
return FALSE;
}
else if (skill_table[sn].spell_school != SCHOOL_ABJURATION)
{
send_to_char( "You cannot cast that spell upon others.\n\r", ch );
pop_call();
return FALSE;
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
send_to_char( "Your target isn't here.\n\r", ch );
pop_call();
return FALSE;
}
ProtTouch = TRUE;
}
if (ch != victim && is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
break;
case TAR_OBJ_INV:
if (arg2[0] == '\0')
{
send_to_char( "What should the spell be cast upon?\n\r", ch );
pop_call();
return FALSE;
}
if ((obj = get_obj_carry(ch, arg2)) == NULL)
{
if ((obj = get_obj_wear(ch, arg2)) == NULL)
{
send_to_char( "You are not carrying that.\n\r", ch );
pop_call();
return FALSE;
}
}
vo = (void *) obj;
break;
case TAR_OBJ_WIELD:
if (arg2[0] == '\0')
{
if ((obj = get_wield(ch, FALSE)) == NULL)
{
send_to_char( "What should the spell be cast upon?\n\r", ch );
pop_call();
return FALSE;
}
}
if ((obj = get_obj_wear(ch, arg2)) == NULL)
{
send_to_char( "You are not holding that.\n\r", ch );
pop_call();
return FALSE;
}
vo = (void *) obj;
break;
case TAR_OBJ_ROOM:
if (arg2[0] == '\0')
{
send_to_char( "What should the spell be cast upon?\n\r", ch );
pop_call();
return FALSE;
}
if ((obj = get_obj_here(ch, arg2)) == NULL)
{
send_to_char( "That item does not seem to be here.\n\r", ch );
pop_call();
return FALSE;
}
vo = (void *) obj;
break;
case TAR_OBJ_CHAR_DEF:
if (arg2[0] == '\0')
{
victim = ch;
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
if ((obj = get_obj_carry(ch, arg2)) == NULL)
{
send_to_char( "Who or what should the spell be cast upon?\n\r", ch );
pop_call();
return FALSE;
}
}
if (victim)
{
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
target = TAR_CHAR_DEFENSIVE;
vo = (void *) victim;
}
else
{
if (ranged)
{
send_to_char( "That item does not seem to be here.\n\r", ch );
pop_call();
return FALSE;
}
target = TAR_OBJ_INV;
vo = (void *) obj;
}
break;
case TAR_OBJ_CHAR_OFF:
if (arg2[0] == '\0')
{
if (who_fighting(ch) == NULL)
{
send_to_char("Cast the spell on whom?\n\r", ch);
pop_call();
return FALSE;
}
victim = who_fighting(ch);
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
if ((obj = get_obj_carry(ch, arg2)) == NULL)
{
send_to_char( "Who or what should the spell be cast upon?\n\r", ch );
pop_call();
return FALSE;
}
}
if (victim)
{
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
target = TAR_CHAR_OFFENSIVE;
vo = (void *) victim;
}
else
{
if (ranged)
{
send_to_char( "That item does not seem to be here.\n\r", ch );
pop_call();
return FALSE;
}
target = TAR_OBJ_INV;
vo = (void *) obj;
}
break;
}
if (IS_SET(skill_table[sn].flags, SF_TOUCH))
{
if (victim == NULL && obj == NULL)
{
act("There's noone to touch.\n\r", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if ((IS_INCORPOREAL(ch) && !IS_INCORPOREAL(victim))
|| (!IS_INCORPOREAL(ch) && IS_INCORPOREAL(victim)))
{
act("You cannot touch $M them to cast that.\n\r", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
}
}
wiz_printf("cast stage 1...");
// allow pre-cast checking of spell_fun conditions
ForReal = FALSE;
argument = target_name; // cache back target_name for testing spell_fun
if (((*skill_table[sn].spell_fun) (sn, level, ch, vo, target)) == FALSE)
{
pop_call();
return FALSE;
}
BOOL_CHECK_TURN(ch, victim);
if (ranged && victim && findpath_search_victim(ch, victim, range) == -1)
{
send_to_char("That target is out of range of your spell.\n\r", ch);
pop_call();
return FALSE;
}
timer = skill_table[sn].beats;
if (victim)
{
if (target == TAR_CHAR_OFFENSIVE
|| (target == TAR_UNDEAD_OFF && IS_UNDEAD(victim))
|| (target == TAR_UNDEAD_DEF && !IS_UNDEAD(victim)))
{
if (!check_murder(ch, victim))
{
pop_call();
return FALSE;
}
}
}
ch->casting = TRUE;
ch->cast_timer = 0;
ch->casting_time = timer;
ch->cast_sn = sn;
ch->cast_level = level;
ch->cast_class = class;
ch->cast_dir = dir;
ch->cast_feats = fRacecast ? 0 : feats;
ch->cast_circle = fRacecast ? -2 : circle;
// because argument cached original target_name before spell_fun check
ch->target_name = STRALLOC(argument);
if (fRacecast)
{
act( "You begin to use a spell-like ability.", ch, NULL, NULL, TO_CHAR);
act( "$n starts to concentrate.", ch, NULL, NULL, TO_ROOM);
}
else if (class == CLASS_BARD)
{
act( "$n begins to sing...", ch, NULL, NULL, TO_ROOM);
act( "You begin to sing...", ch, NULL, NULL, TO_CHAR);
}
else
{
act( "You begin to cast a spell.", ch, NULL, NULL, TO_CHAR);
for (rch = ch->in_room->first_person ; rch != NULL ; rch = rch_next)
{
rch_next = rch->next_in_room;
if (!can_see_casting(rch, ch, sn))
continue;
act( "$n begins to cast a spell.", ch, NULL, rch, TO_VICT);
}
}
if (target == TAR_CHAR_OFFENSIVE
|| (target == TAR_UNDEAD_OFF && IS_UNDEAD(victim))
|| (target == TAR_UNDEAD_DEF && !IS_UNDEAD(victim)))
{
if (can_see_casting(victim, ch, sn))
make_char_fight_char( ch, victim );
}
if (fRacecast)
TAKE_ACTION(ch, ACTION_STANDARD);
else if (IS_SET(feats, METAMAGIC_QUICKEN) || skill_table[sn].beats == CASTING_SWIFT)
{
TAKE_ACTION(ch, ACTION_SWIFT);
release_cast(ch);
}
else if (skill_table[sn].beats == CASTING_STANDARD)
TAKE_ACTION(ch, ACTION_STANDARD);
else if (skill_table[sn].beats == CASTING_ROUND)
TAKE_ACTION(ch, ACTION_FULL);
else if (skill_table[sn].beats == CASTING_INSTANT)
release_cast(ch);
pop_call();
return TRUE;
}
void do_cast( CHAR_DATA *ch, char *argument )
{
push_call("do_cast(%p,%p)",ch,argument);
cast_spell(ch, argument, FALSE);
pop_call();
return;
}
void do_racecast( CHAR_DATA *ch, char *argument )
{
push_call("do_racecast(%p,%p)",ch,argument);
cast_spell(ch, argument, TRUE);
pop_call();
return;
}
/* The spell's release after the countdown - Kregor */
void release_cast( CHAR_DATA *ch )
{
char arg2[MAX_INPUT_LENGTH];
char arg3[MAX_INPUT_LENGTH];
char *argument;
CHAR_DATA *victim;
OBJ_DATA *obj, *vic_obj;
void *vo;
bool ranged = FALSE;
bool race = FALSE;
bool Turned = FALSE;
bool Fail = FALSE; // means the spell spoiled, but still costs.
int mana, sn, level, target, dir, diceroll, class;
push_call("release_cast(%p)",ch);
target_name = STRALLOC(ch->target_name);
argument = STRALLOC(ch->target_name);
if ((sn = ch->cast_sn) < 0 || !is_spell(sn))
{
bug( "release_cast(%s): %d not a spell.", ch->name, sn );
pop_call();
return;
}
if ((level = ch->cast_level) == -1)
{
if ((level = get_caster_level(ch, sn)) == -1)
{
pop_call();
return;
}
}
if (ch->cast_circle == -2)
{
if (!race_skill(ch, sn))
{
bug( "release_cast(%s): race cast of non-racial ability.", ch->name );
pop_call();
return;
}
ch->cast_circle = ch->level / 2;
race = TRUE;
}
if ((dir = ch->cast_dir) != -1)
{
ranged = TRUE;
}
argument = one_argument( argument, arg2 );
argument = one_argument( argument, arg3 );
value = -1; /* Default value */
if (is_number(arg2)) /* Special numbers only spell */
{
value = atol(arg2);
strcpy( arg2, "");
if (value < 1)
{
value = -1; /* Default value */
}
}
else if (arg3[0] != '\0' && is_number(arg3)) /* Read the extra value - Chaos 2/8/95 */
{
value = atol( arg3 );
if ( value < 1 )
{
value = -1; /* Default value */
}
}
else if (argument[0] != '\0' && is_number(argument)) /* Read the extra, extra value - Kregor 6/30/07 */
{
value = atol( argument );
if ( value < 1 )
{
value = -1; /* Default value */
}
}
if (is_safe_magic(ch, NULL, sn))
{
pop_call();
return;
}
if (!race)
{
if ((class = casting_class(ch, sn, TRUE)) == -1)
{
send_to_char("Wait a minute! You can't cast this spell!\n\r", ch);
bug ("release_cast: class = -1", 0);
pop_call();
return;
}
mana = get_mana(ch, sn, ch->cast_circle, class);
if (!IS_SET(ch->cast_feats, METAMAGIC_STILL)
&& IS_SET(skill_table[sn].flags, SF_SOMATIC))
{
switch (class)
{
default:
break;
case CLASS_WIZARD:
case CLASS_SORCERER:
case CLASS_BARD:
if (number_percent() < spell_failure(ch))
{
send_to_char_color("{138}Your encumberance has spoiled your casting!\n\r", ch);
Fail = TRUE;
break;
}
break;
}
}
}
if (!Fail)
{
diceroll = concentration_roll(ch);
if (IS_ENTANGLED(ch) || drunk_level(ch) >= DRUNK_TIPSY || is_affected(ch, gsn_insect_plague) || ch->grappling || ch->grappled_by)
{
int DC;
if (ch->grappled_by)
DC = 10 + combat_maneuver_bonus(ch->grappled_by) + ch->cast_circle;
else
DC = 15 + ch->cast_circle;
if (!concentration_check(ch, NULL, diceroll, DC))
{
send_to_char_color("{138}You lost your concentration!\n\r", ch);
Fail = TRUE;
}
}
}
// Here is where NO_ASTRAL flags spoil summons and teleports
if (IS_SET(ch->in_room->room_flags, ROOM_NO_ASTRAL))
{
if (!Fail && IS_SET(skill_table[sn].spell_desc, SDESC_SUMMONING))
{
act("Magical wards foil your summoning.", ch, NULL, NULL, TO_CHAR);
Fail = TRUE;
}
}
// Locate targets again, JUST in case something gets away! ;)
// but bypass if Fail already, because it doesn't matter.
victim = NULL;
obj = NULL;
vo = NULL;
target = skill_table[sn].target;
if (!Fail)
{
if (ranged && !is_string(arg2) && check_cast_door(ch, dir, sn, level, TRUE))
{
if (!race)
{
ch->mana[class] -= mana;
check_components(ch, sn, TRUE);
}
else
{
ch->uses[sn]++;
}
pop_call();
return;
}
switch (target)
{
default:
bug( "release_cast: bad target for sn %d.", sn );
pop_call();
return;
case TAR_IGNORE:
break;
case TAR_CHAR_OFFENSIVE:
if (arg2[0] == '\0')
{
if (who_fighting(ch) == NULL)
{
send_to_char( "Your target must have slipped away.\n\r", ch );
pop_call();
return;
}
victim = who_fighting(ch);
}
else
{
if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
{
send_to_char("Your target must have slipped out of sight!\n\r", ch);
pop_call();
return;
}
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
send_to_char( "Your target must have slipped away.\n\r", ch );
pop_call();
return;
}
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return;
}
vo = (void *) victim;
break;
case TAR_UNDEAD_OFF:
if (arg2[0] == '\0')
{
if ((victim = who_fighting(ch)) == NULL || !IS_UNDEAD(who_fighting(ch)))
{
if (IS_UNDEAD(ch))
{
send_to_char( "Your target must have slipped away.\n\r", ch );
pop_call();
return;
}
else
{
victim = ch;
}
}
}
else
{
if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
{
send_to_char("Your target must have slipped out of sight!\n\r", ch);
pop_call();
return;
}
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
send_to_char( "Your target must have slipped away.\n\r", ch );
pop_call();
return;
}
}
if (IS_UNDEAD(victim) && is_safe_magic(ch, victim, sn))
{
pop_call();
return;
}
vo = (void *) victim;
if (IS_UNDEAD(victim))
target = TAR_CHAR_OFFENSIVE;
else
target = TAR_CHAR_DEFENSIVE;
break;
case TAR_UNDEAD_DEF:
if (arg2[0] == '\0')
{
if ((victim = who_fighting(ch)) == NULL || IS_UNDEAD(who_fighting(ch)))
{
if (!IS_UNDEAD(ch))
{
send_to_char("Your target must have slipped out of sight!\n\r", ch);
pop_call();
return;
}
else
{
victim = ch;
}
}
}
else
{
if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
{
send_to_char("Your target must have slipped out of sight!\n\r", ch);
pop_call();
return;
}
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
send_to_char( "Your target must have slipped away.\n\r", ch );
pop_call();
return;
}
}
if (!IS_UNDEAD(victim) && is_safe_magic(ch, victim, sn))
{
pop_call();
return;
}
vo = (void *) victim;
if (!IS_UNDEAD(victim))
target = TAR_CHAR_OFFENSIVE;
else
target = TAR_CHAR_DEFENSIVE;
break;
case TAR_CHAR_DEFENSIVE:
if (arg2[0] == '\0')
{
victim = ch;
}
else
{
if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
{
send_to_char("Your target must have slipped out of sight!\n\r", ch);
pop_call();
return;
}
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
send_to_char( "Your target must have slipped away.\n\r", ch );
pop_call();
return;
}
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return;
}
vo = (void *) victim;
break;
case TAR_CHAR_SELF:
vo = (void *) ch;
break;
case TAR_OBJ_INV:
if (arg2[0] == '\0')
{
send_to_char( "Something must have gone wrong.\n\r", ch );
pop_call();
return;
}
if ((obj = get_obj_carry(ch, arg2)) == NULL)
{
if ((obj = get_obj_wear(ch, arg2)) == NULL)
{
send_to_char( "You are not carrying that.\n\r", ch );
pop_call();
return;
}
}
vo = (void *) obj;
break;
case TAR_OBJ_WIELD:
if (arg2[0] == '\0')
{
if ((obj = get_wield(ch, FALSE)) == NULL)
{
send_to_char( "Something must have gone wrong.\n\r", ch );
pop_call();
return;
}
}
if ((obj = get_obj_wear(ch, arg2)) == NULL)
{
send_to_char( "You are not holding that.\n\r", ch );
pop_call();
return;
}
vo = (void *) obj;
break;
case TAR_OBJ_ROOM:
if (arg2[0] == '\0')
{
send_to_char( "Something must have gone wrong.\n\r", ch );
pop_call();
return;
}
if ((obj = get_obj_here(ch, arg2)) == NULL)
{
send_to_char( "That does not seem to be here.\n\r", ch );
pop_call();
return;
}
vo = (void *) obj;
break;
case TAR_OBJ_CHAR_DEF:
if (arg2[0] == '\0')
{
victim = ch;
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
if ((obj = get_obj_carry(ch, arg2)) == NULL)
{
send_to_char( "Who or what should the spell be cast upon?\n\r", ch );
pop_call();
return;
}
}
if (victim)
{
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return;
}
target = TAR_CHAR_DEFENSIVE;
vo = (void *) victim;
}
else
{
target = TAR_OBJ_INV;
vo = (void *) obj;
}
break;
case TAR_OBJ_CHAR_OFF:
if (arg2[0] == '\0')
{
if (who_fighting(ch) == NULL)
{
send_to_char("Cast the spell on whom?\n\r", ch);
pop_call();
return;
}
victim = who_fighting(ch);
}
else if ((victim = get_char_room(ch, arg2)) == NULL)
{
if ((obj = get_obj_carry(ch, arg2)) == NULL)
{
send_to_char( "Who or what should the spell be cast upon?\n\r", ch );
pop_call();
return;
}
}
if (victim)
{
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return;
}
target = TAR_CHAR_OFFENSIVE;
vo = (void *) victim;
}
else
{
target = TAR_OBJ_INV;
vo = (void *) obj;
}
break;
}
}
if (!Fail)
{
if (victim != NULL && victim != ch
&& IS_SET(skill_table[sn].flags, SF_TOUCH)
&& !IS_SET(ch->cast_feats, METAMAGIC_REACH))
{
switch (target)
{
case TAR_CHAR_OFFENSIVE:
case TAR_OBJ_CHAR_OFF:
if(!check_hit(ch, victim, dice(1,20), 0, sn, NULL, TRUE, FALSE))
{
act( "You attempt to touch $N, but miss.", ch, NULL, victim, TO_CHAR);
act( "$n attempts to touch $N, but misses.", ch, NULL, victim, TO_NOTVICT);
act( "$n attempts to touch you, but misses.", ch, NULL, victim, TO_VICT);
Fail = TRUE;
}
break;
case TAR_CHAR_DEFENSIVE:
case TAR_OBJ_CHAR_DEF:
if((in_combat(victim) || in_combat(ch) || IS_AFFECTED(victim, AFF2_CONFUSION))
&& !check_hit(ch, victim, dice(1,20), 0, sn, NULL, TRUE, FALSE))
{
act( "You attempt to touch $N, but miss.", ch, NULL, victim, TO_CHAR);
act( "$n attempts to touch $N, but misses.", ch, NULL, victim, TO_NOTVICT);
act( "$n attempts to touch you, but misses.", ch, NULL, victim, TO_VICT);
Fail = TRUE;
}
break;
}
}
}
// Cannot turn or counterspell a racial ability.
if (!Fail && !race)
{
/*
* Treature flag support for counterspell flag
*/
if (victim && (vic_obj = get_obj_tflag(victim, TFLAG_COUNTERSPELL)) != NULL)
{
if (vic_obj->value[1] == sn)
{
act( "$n's magic dissipates as $p counters it.", ch, vic_obj, victim, TO_VICT);
act( "Your spell dissipates as $N counters it.", ch, NULL, victim, TO_CHAR);
act( "$n's spell dissipates as it reaches $N.", ch, NULL, victim, TO_NOTVICT);
vic_obj->value[1] = -1;
Fail = TRUE;
}
}
// Mud20 variant - Spell Turning = caster level check instead of level comp.
if (!Fail && victim && victim != ch && is_affected(victim, gsn_spell_turning))
{
if (dice(1,20) + level < 11 + get_affect_level(victim, gsn_spell_turning))
{
act( "White lightning surrounds you, reflecting $n's magic.", ch, NULL, victim, TO_VICT );
act( "White lightning surrounds $N, reflecting your magic.", ch, NULL, victim, TO_CHAR );
act( "White lightning surrounds $N, reflecting $n's magic.", ch, NULL, victim, TO_NOTVICT );
vo = (void *) ch;
ch = victim;
Turned = TRUE;
affect_strip(victim, gsn_spell_turning);
}
}
}
if (!Fail)
{
ForReal = TRUE; // set to make spell_fun actually run
// if the spell errors out, there's no cost and no prog trigger
if (((*skill_table[sn].spell_fun) (sn, level, ch, vo, target)) == FALSE)
{
pop_call();
return;
}
else
{
if (IS_SET(ch->cast_feats, METAMAGIC_REPEAT))
{
(*skill_table[sn].spell_fun) (sn, level, ch, vo, target);
}
if (!Turned) // for simplicity, no cast trigger on turned spells.
{
mprog_cast_trigger(ch, victim, sn);
oprog_cast_trigger(ch, obj, sn);
rprog_cast_trigger(ch, sn);
}
}
}
if (Turned) // make sure the right person pays the cost.
{
ch = (CHAR_DATA*) vo;
}
if (!race)
{
ch->mana[class] -= mana;
check_components(ch, sn, TRUE);
spell_favor(ch, sn);
}
else
{
ch->uses[sn]++;
}
pop_call();
return;
}
/*
* Controls when characters release their magic
* updated in main loop - Kregor
*/
void update_casting(void)
{
CHAR_DATA *ch;
CHAR_DATA *rch, *rch_next;
push_call("update_casting()");
for (ch = mud->f_char ; ch ; ch = mud->update_wch)
{
mud->update_wch = ch->next;
if (ch->casting)
{
if (ch->cast_sn != gsn_recite_scroll
&& (ch->cast_sn < 0 || !is_spell(ch->cast_sn)))
{
free_cast(ch);
}
if (in_combat(ch) && !is_active(ch))
continue;
ch->cast_timer++;
if (ch->cast_timer == 2)
say_spell(ch, ch->cast_sn);
/* NPC opponents might take opportunity if they perceive they can. */
if (ch->cast_timer == 5 && !learned(ch, gsn_warmage))
{
for (rch = ch->in_room->first_person ; rch ; rch = rch_next)
{
rch_next = rch->next_in_room;
if (ch == rch || is_same_group(ch, rch))
continue;
if (IS_NPC(rch))
{
if (wis_roll(rch) < 10) // avg NPC has a 50% chance of taking the opportunity
continue;
if (who_fighting(rch) && who_fighting(rch) == ch)
{
if (attack_of_opportunity(rch, ch))
continue;
}
if (counterspell(rch, ch, ch->cast_sn, ch->cast_level, FALSE))
{
if (ch->cast_sn == gsn_recite_scroll && ch->reciting)
junk_obj(ch->reciting);
free_cast(ch);
break;
}
}
}
}
if (!ch->casting)
continue;
if (ch->cast_timer == ch->casting_time)
{
if (ch->cast_sn == gsn_recite_scroll)
finish_reciting(ch);
else
release_cast(ch);
free_cast(ch);
SET_BIT(ch->attack, ATTACK_CAST);
turn_complete(ch);
continue;
}
else if (!ch->cast_timer || ch->cast_timer % 8 == 0)
{
if (in_combat(ch) && is_active(ch))
{
turn_end(ch->in_battle->turn_list, 200 - ch->initiative);
continue;
}
}
}
}
pop_call();
return;
}
/*
* Free up the spell casting cue
*/
void free_cast( CHAR_DATA *ch )
{
push_call("free_cast(%p)",ch);
ch->casting = FALSE;
ch->casting_time = 0;
ch->cast_timer = 0;
ch->cast_sn = -1;
ch->cast_level = -1;
ch->cast_circle = -1;
ch->cast_class = 0;
ch->cast_dir = -1;
ch->cast_feats = 0;
STRFREE(ch->target_name);
ch->reciting = NULL;
pop_call();
return;
}
/*
* Return TRUE if spell is on char's spell list,
* even if not high enough level to cast it, per d20 - Kregor
*/
bool can_brandish( CHAR_DATA *ch, int sn )
{
int cnt;
push_call("can_brandish(%p,%p)",ch,sn);
for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
{
if (class_level(ch, cnt) && skill_table[sn].skill_level[cnt] < LEVEL_IMMORTAL)
{
pop_call();
return TRUE;
}
}
pop_call();
return FALSE;
}
/*
* Rolling up all the little items into one global USE command
* includes support for multi-spell items, and ranged casting
* and even invoking obj progs with the use command - Kregor
*/
void do_use( CHAR_DATA *ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
OBJ_DATA *obj;
push_call("do_use(%p,%p)",ch,argument);
argument = one_argument(argument, arg);
if (arg[0] == '\0')
{
send_to_char("Use what?\n\r", ch);
pop_call();
return;
}
if ((obj = get_obj_wear(ch, arg)) == NULL)
{
send_to_char("You don't seem to be holding anything like that.\n\r", ch);
pop_call();
return;
}
/*
* note that putting a use trigger on an obj
* effectively makes other properties unusable - Kregor
*/
if (oprog_use_trigger(ch, obj))
{
pop_call();
return;
}
else if (IS_OBJ_TYPE(obj, ITEM_STAFF)
|| TREASURE_FLAG(obj, TFLAG_SPELL_STORING))
{
use_spell_item(ch, obj, argument);
}
else if (IS_OBJ_TYPE(obj, ITEM_WAND)
|| TREASURE_FLAG(obj, TFLAG_SPELL_RECAST)
|| TREASURE_FLAG(obj, TFLAG_SPELL_CHARGES))
{
use_item(ch, obj, argument);
}
else if (IS_OBJ_TYPE(obj, ITEM_SCROLL))
{
recite_scroll(ch, obj, argument);
}
else if (IS_OBJ_TYPE(obj, ITEM_POTION))
{
drink_obj(ch, obj);
}
else
{
act( "You attempt to call on the power of $p. Nothing happens.", ch, obj, NULL, TO_CHAR);
act( "$n attempts to call on the power of $p. Nothing happens.", ch, obj, NULL, TO_ROOM);
}
pop_call();
return;
}
void use_spell_item( CHAR_DATA *ch, OBJ_DATA *item, char *argument )
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
CHAR_DATA *victim;
OBJ_DATA *obj;
int sn, cnt, dir, val, level, range, cost, circle;
bool ranged = FALSE;
push_call("use_spell_item(%p,%p)",ch,argument);
if (IS_SET(ch->action, ACTION_STANDARD))
{
ch_printf_color(ch, "You have already made a standard action this round.\n\r");
pop_call();
return;
}
if (!item->identified)
{
send_to_char( "You have no idea what this can do!\n\r", ch );
pop_call();
return;
}
argument = one_argument( argument, arg1 );
target_name = argument;
argument = one_argument( argument, arg2 );
if (*arg1 == '\0')
{
act( "What spell from $p do you wish to use?", ch, item, NULL, TO_CHAR);
pop_call();
return;
}
if ((sn = skill_lookup(arg1)) == -1)
{
act( "$t is not a spell.", ch, arg1, NULL, TO_CHAR);
pop_call();
return;
}
if ((circle = get_spell_circle(NULL, sn)) < 0)
{
send_to_char( "There's a bug with this code, notify a GM!\n\r", ch );
bug("use_spell_item (%d): bad spell circle.", item->pIndexData->vnum);
pop_call();
return;
}
/*
* Determine whether it's a ranged cast or not - Kregor
*/
if (*arg2 != '\0'
&& skill_table[sn].target != TAR_IGNORE
&& skill_table[sn].target != TAR_CHAR_SELF
&& skill_table[sn].target != TAR_OBJ_INV
&& skill_table[sn].target != TAR_OBJ_WIELD)
{
if ((dir = direction_door(arg2)) != -1)
{
ranged = TRUE;
target_name = argument;
argument = one_argument( argument, arg2 );
}
}
val = 1;
switch (item->item_type)
{
case ITEM_STAFF:
for (cnt = 3 ; cnt <= 6 ; cnt++)
{
if (item->value[cnt] < 0)
continue;
if (!is_spell(item->value[cnt]) || skill_table[item->value[cnt]].spell_fun == 0)
{
bug( "use_spell_item in object %d: bad sn %d in obj value %d.", item->pIndexData->vnum, item->value[cnt], cnt );
pop_call();
return;
}
if (item->value[cnt] == sn)
{
val = cnt;
break;
}
}
break;
case ITEM_TREASURE:
if (TREASURE_FLAG(item, TFLAG_SPELL_STORING))
{
for (cnt = 1 ; cnt <= 3 ; cnt++)
{
if (item->value[cnt] < 0)
continue;
if (!is_spell(item->value[cnt]) || skill_table[item->value[cnt]].spell_fun == 0)
{
bug( "use_spell_item in object %d: bad sn %d in obj value %d.", item->pIndexData->vnum, item->value[cnt], cnt );
pop_call();
return;
}
if (item->value[cnt] == sn)
{
val = cnt;
break;
}
}
}
break;
}
if (val == -1)
{
act( "You attempt to call on the power of $p. Nothing happens.", ch, item, NULL, TO_CHAR);
act( "$n attempts to call on the power of $p. Nothing happens.", ch, item, NULL, TO_ROOM);
pop_call();
return;
}
level = item_caster_level(item, sn);
if (IS_OBJ_TYPE(item, ITEM_STAFF))
{
if ((cost = UMAX(1, circle * 2 / 3)) > item->value[2])
{
act( "There aren't enough charges left on $p.", ch, item, NULL, TO_CHAR);
act( "$n attempts to brandish $p... and nothing happens.", ch, item, NULL, TO_ROOM);
pop_call();
return;
}
}
level = UMAX(multi_caster_level(ch, sn), level);
if (ranged && (range = get_spell_range(level, sn)) <= 0)
{
ch_printf_color(ch, "That spell cannot be cast at range.\n\r");
pop_call();
return;
}
victim = NULL;
obj = NULL;
if (arg2[0] == '\0')
{
victim = ch;
}
else if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg2)) == NULL)
{
send_to_char("You cannot find your target.\n\r", ch);
pop_call();
return;
}
else if (findpath_search_victim(ch, victim, range) == -1)
{
send_to_char("That target is out of range.\n\r", ch);
pop_call();
return;
}
}
else
{
if ((victim = get_char_room (ch, arg2)) == NULL
&& (obj = get_obj_here(ch, arg2)) == NULL)
{
send_to_char("You cannot find your target.\n\r", ch);
pop_call();
return;
}
}
CHECK_TURN(ch, victim);
if (IS_OBJ_TYPE(item, ITEM_STAFF) && !can_brandish(ch, sn) && !use_magic_check(ch, NULL, use_magic_roll(ch) + synergy_bonus(ch, gsn_spellcraft), 20 + item->value[0]))
{
act( "You fail to invoke $p.", ch, item, NULL, TO_CHAR);
act( "$n attempts to brandish $p... and nothing happens.", ch, item, NULL, TO_ROOM);
TAKE_ACTION(ch, ACTION_STANDARD);
pop_call();
return;
}
act( "You brandish $p.", ch, item, NULL, TO_CHAR );
act( "$n brandishes $p.", ch, item, NULL, TO_ROOM );
if (obj_cast_spell(item->value[val], level, ch, victim, obj))
{
if (IS_OBJ_TYPE(item, ITEM_STAFF) && (item->value[2] -= cost) <= 0)
{
act( "$p blazes bright and loses its magical luster.", ch, item, NULL, TO_CHAR );
act( "$p blazes bright and loses its magical luster.", ch, item, NULL, TO_ROOM );
REMOVE_BIT(item->extra_flags, ITEM_MAGIC);
}
if (TREASURE_FLAG(item, TFLAG_SPELL_STORING))
{
item->value[val] = -1;
act( "The spell is discharged from $p", ch, item, NULL, TO_CHAR );
}
TAKE_ACTION(ch, ACTION_STANDARD);
}
pop_call();
return;
}
void use_item( CHAR_DATA *ch, OBJ_DATA *item, char *argument )
{
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *victim;
OBJ_DATA *obj;
int sn, level, dir, range;
bool ranged = FALSE;
push_call("use_item(%p,%p,%p)",ch,item,argument);
target_name = argument;
argument = one_argument( argument, arg );
if ((sn = item->value[3]) == -1 || !is_spell(sn))
{
act( "$p strangely fizzles.", ch, item, NULL, TO_CHAR);
bug( "use_item in object %d: bad sn %d.", item->pIndexData->vnum, item->value[3]);
pop_call();
return;
}
/*
* Determine whether it's a ranged cast or not
*/
if (*arg != '\0'
&& skill_table[sn].target != TAR_IGNORE
&& skill_table[sn].target != TAR_CHAR_SELF
&& skill_table[sn].target != TAR_OBJ_INV
&& skill_table[sn].target != TAR_OBJ_WIELD)
{
if ((dir = direction_door(arg)) != -1)
{
ranged = TRUE;
target_name = argument;
argument = one_argument( argument, arg );
}
}
level = item_caster_level(item, sn);
obj = NULL;
victim = NULL;
if (ranged && (range = get_spell_range(level, sn)) <= 0)
{
ch_printf_color(ch, "That spell cannot be cast at range.\n\r");
pop_call();
return;
}
if (arg[0] == '\0')
{
victim = ch;
}
else if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg)) == NULL)
{
send_to_char("You cannot find your target.\n\r", ch);
pop_call();
return;
}
else if (findpath_search_victim(ch, victim, range) == -1)
{
send_to_char("That target is out of range of that spell.\n\r", ch);
pop_call();
return;
}
}
else
{
if ((victim = get_char_room (ch, arg)) == NULL
&& (obj = get_obj_here(ch, arg)) == NULL)
{
send_to_char( "You cannot find it.\n\r", ch );
pop_call();
return;
}
}
CHECK_TURN(ch, victim);
if (item->value[2] == 0)
{
act( "$p has no charges left.", ch, item, NULL, TO_CHAR );
pop_call();
return;
}
if (IS_OBJ_TYPE(item, ITEM_WAND))
{
if (!can_brandish(ch, sn) && !use_magic_check(ch, NULL, use_magic_roll(ch) + synergy_bonus(ch, gsn_spellcraft), 20 + item->value[0]))
{
act( "You fail to invoke $p.", ch, item, NULL, TO_CHAR);
act( "$n attempts to brandish $p... and nothing happens.", ch, item, NULL, TO_ROOM);
TAKE_ACTION(ch, ACTION_STANDARD);
pop_call();
return;
}
}
act( "You brandish $p.", ch, item, NULL, TO_CHAR );
act( "$n brandishes $p.", ch, item, NULL, TO_ROOM );
if (obj_cast_spell(item->value[3], item->value[0], ch, victim, obj))
{
if (item->value[2] > 0)
{
if (--item->value[2] == 0 && IS_OBJ_TYPE(item, ITEM_WAND))
{
act( "$p turns into a simple stick.", ch, item, NULL, TO_CHAR );
act( "$p turns into a simple stick.", ch, item, NULL, TO_ROOM );
REMOVE_BIT(item->extra_flags, ITEM_MAGIC);
}
}
TAKE_ACTION(ch, ACTION_STANDARD);
}
pop_call();
return;
}
/*
* New recite for D20 scroll usage - Kregor 10/25/07
* folded into the do_use command - 12/28/07
*/
void recite_scroll( CHAR_DATA *ch, OBJ_DATA *scroll, char *argument )
{
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *victim;
OBJ_DATA *obj;
bool ranged = FALSE;
bool checked;
int sn, level, dir, range, class, eff_level;
push_call("recite_scroll(%p,%p)",ch,scroll,argument);
if (IS_SET(ch->action, ACTION_STANDARD))
{
ch_printf_color(ch, "You have already made a standard action this round.\n\r");
pop_call();
return;
}
target_name = argument;
argument = one_argument( argument, arg );
dir = -1;
/*
* Determine whether it's a ranged cast or not
*/
if (arg[0] != '\0')
{
ch_printf_color(ch, "finding direction: %s\n\r", arg);
if ((dir = direction_door(arg)) != -1)
{
ranged = TRUE;
target_name = argument;
argument = one_argument( argument, arg );
}
}
if (scroll->item_type != ITEM_SCROLL)
{
send_to_char( "You can recite only scrolls.\n\r", ch );
pop_call();
return;
}
if ((sn = scroll->value[1]) < 0 || !is_spell(sn))
{
if (sn > 0 && skill_table[sn].skilltype == FSKILL_BARDSONG)
{
send_to_char( "You cannot empower sheet music by reciting it.\n\r", ch );
pop_call();
return;
}
if (!IS_NPC(ch) && ch->desc == NULL)
{
log_printf("[%u] reciting unknown spell: %s", ch->pIndexData->vnum, arg);
}
send_to_char( "That is not a spell.\n\r", ch );
pop_call();
return;
}
if ((level = scroll->value[0]) <= 0)
{
log_printf("Bug: Reciting scroll with no level: %s", scroll->name);
send_to_char( "Something went wrong, notify an immortal.\n\r", ch );
pop_call();
return;
}
checked = use_magic_check(ch, NULL, use_magic_roll(ch) + synergy_bonus(ch, gsn_decipher_script) + is_affected(ch, gsn_read_magic), 20 + scroll->value[0]);
if ((class = multi(ch, sn)) == -1 && !checked)
{
send_to_char( "There is no spell upon the scroll you can recite.\n\r", ch);
pop_call();
return;
}
if (is_safe_magic(ch, NULL, sn))
{
pop_call();
return;
}
if (ranged && (range = get_spell_range(level, sn)) <= 0)
{
ch_printf_color(ch, "That spell cannot be cast at that range.\n\r");
pop_call();
return;
}
victim = NULL;
obj = NULL;
if (arg[0] == '\0')
{
victim = ch;
}
else if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg)) == NULL)
{
send_to_char("You cannot find your target.\n\r", ch);
pop_call();
return;
}
else if (findpath_search_victim(ch, victim, range) == -1)
{
send_to_char("That target is out of range of your spell.\n\r", ch);
pop_call();
return;
}
}
else
{
if ((victim = get_char_room (ch, arg)) == NULL
&& (obj = get_obj_here(ch, arg)) == NULL)
{
send_to_char("You cannot find your target.\n\r", ch);
pop_call();
return;
}
}
CHECK_TURN(ch, victim);
eff_level = multi_caster_level(ch, sn);
if (multi(ch, sn) == -1 && checked)
eff_level = multi_class_level(ch, gsn_use_magic);
ch->casting = TRUE;
ch->casting_time = 8;
ch->cast_sn = gsn_recite_scroll;
ch->cast_level = eff_level;
ch->cast_circle = get_spell_circle(NULL, sn);
ch->cast_dir = dir;
ch->cast_class = class;
ch->cast_feats = scroll->value[2];
ch->reciting = scroll;
ch->target_name = STRALLOC(target_name);
act( "You begin to recite $p.", ch, scroll, NULL, TO_CHAR );
act( "$n begins to recite $p.", ch, scroll, NULL, TO_ROOM );
pop_call();
return;
}
/*
* Release the spell from a scroll
*/
void finish_reciting( CHAR_DATA *ch )
{
char *argument;
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *victim, *vch, *vch_next;
OBJ_DATA *obj, *scroll;
bool ranged = FALSE;
int sn, diceroll, dc, level, dir, range;
push_call("finish_reciting(%p)",ch);
target_name = STRALLOC(ch->target_name);
argument = STRALLOC(ch->target_name);
if ((scroll = ch->reciting) == NULL || scroll->item_type != ITEM_SCROLL)
{
send_to_char("Um, where did your scroll go?\n\r", ch);
bug("finish_reciting: NULL scroll",0);
pop_call();
return;
}
if ((level = ch->cast_level) <= 0)
{
act( "Try as you might, you cannot seem to recite $p.", ch, scroll, NULL, TO_CHAR);
pop_call();
return;
}
if ((sn = scroll->value[1]) < 0 || !is_spell(sn))
{
if (!IS_NPC(ch) && ch->desc == NULL)
{
log_printf("[%u] reciting unknown spell: %s", ch->pIndexData->vnum, arg);
}
send_to_char( "That is not a spell.\n\r", ch );
pop_call();
return;
}
if ((dir = ch->cast_dir) != -1)
{
ranged = TRUE;
}
if (ranged && (range = get_spell_range(level, sn)) <= 0)
{
ch_printf_color(ch, "That spell cannot be cast at that range.\n\r");
pop_call();
return;
}
argument = one_argument( argument, arg );
/*
* find the target again, in case something gets away. :)
*/
victim = NULL;
obj = NULL;
if (arg[0] == '\0')
{
victim = ch;
}
else if (ranged)
{
if ((victim = find_char_dir(ch, dir, arg)) == NULL)
{
send_to_char("You cannot find your target.\n\r", ch);
pop_call();
return;
}
else if (findpath_search_victim(ch, victim, range) == -1)
{
send_to_char("That target is out of range of your spell.\n\r", ch);
pop_call();
return;
}
}
else
{
if ((victim = get_char_room (ch, arg)) == NULL
&& (obj = get_obj_here(ch, arg)) == NULL)
{
send_to_char("You cannot find your target.\n\r", ch);
pop_call();
return;
}
}
dc = scroll->value[0] + 1;
diceroll = dice(1,20) + level;
if (level < scroll->value[0])
{
if (diceroll < dc)
{
if ((diceroll = wis_roll(ch)) == 1 || diceroll < 5)
{
switch (number_bits(2))
{
case 0:
send_to_char("Something in your throat prevents you from reciting properly.\n\r", ch);
act( "$n recites $p, and nothing happens.", ch, scroll, NULL, TO_ROOM );
break;
case 1:
act( "You bumble your words causing the scroll to erupt in magical energy!\n\r", ch, NULL, NULL, TO_CHAR);
act( "$n bumbles reciting $p, and the scroll erupts in magical energy.", ch, scroll, NULL, TO_ROOM );
ch->hit -= dice(scroll->value[0], 6);
break;
case 2:
if (victim != ch)
victim = ch;
else
{
for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn) || is_same_group(ch, vch))
continue;
victim = vch;
break;
}
}
act( "You mispronounce a syllable, and something goes really wrong.\n\r", ch, NULL, NULL, TO_CHAR);
act( "$n recites $p, and things don't go quite right.", ch, scroll, NULL, TO_ROOM );
obj_cast_spell(scroll->value[1], scroll->value[0], ch, victim, obj);
break;
case 3:
send_to_char("You hesitate mid-way through the reciting and nothing happens.\n\r", ch);
act( "$n recites $p, and nothing happens.", ch, scroll, NULL, TO_ROOM );
break;
}
junk_obj(scroll);
TAKE_ACTION(ch, ACTION_STANDARD);
pop_call();
return;
}
send_to_char("You failed to recite the scroll properly.\n\r", ch);
act( "$n recites $p, and nothing happens.", ch, scroll, NULL, TO_ROOM );
TAKE_ACTION(ch, ACTION_STANDARD);
junk_obj(scroll);
pop_call();
return;
}
}
diceroll = concentration_roll(ch);
if (IS_ENTANGLED(ch) || drunk_level(ch) >= DRUNK_TIPSY || is_affected(ch, gsn_insect_plague) || ch->grappling || ch->grappled_by)
{
int DC;
if (ch->grappled_by)
DC = 10 + combat_maneuver_bonus(ch->grappled_by) + ch->cast_circle;
else
DC = 15 + ch->cast_circle;
if (!concentration_check(ch, victim, diceroll, DC))
{
send_to_char("{138}You lost your concentration, ruining the spell!\n\r", ch);
act( "Magical energy fizzles as $p vanishes from $n's hands!", ch, scroll, NULL, TO_ROOM);
junk_obj(scroll);
TAKE_ACTION(ch, ACTION_STANDARD);
pop_call();
return;
}
}
act( "You finish reciting $p.", ch, scroll, NULL, TO_CHAR );
act( "$n finishes reciting $p.", ch, scroll, NULL, TO_ROOM );
if (obj_cast_spell(sn, scroll->value[0], ch, victim, obj))
{
TAKE_ACTION(ch, ACTION_STANDARD);
junk_obj(scroll);
}
pop_call();
return;
}
/*
* Cast spells at targets using a magical object.
* revamped for D20 goodness, made bool instead of void
*/
bool obj_cast_spell( int sn, int level, CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj )
{
OBJ_DATA *vic_obj;
void *vo;
int target;
push_call("obj_cast_spell(%p,%p,%p,%p,%p)",sn,level,ch,victim,obj);
if (sn <= 0)
{
pop_call();
return FALSE;
}
if (is_safe_magic(ch, NULL, sn))
{
pop_call();
return FALSE;
}
if (!is_spell(sn) || skill_table[sn].spell_fun == 0)
{
if (obj != NULL)
{
log_printf("obj_cast_spell: Vnum %u bad sn %d.", obj->pIndexData->vnum, sn);
}
else
{
log_printf("Unknown item cast sn %d", sn);
}
pop_call();
return FALSE;
}
target = skill_table[sn].target;
switch (target)
{
default:
bug( "obj_cast_spell: bad target for sn %d.", sn );
pop_call();
return FALSE;
case TAR_IGNORE:
vo = NULL;
break;
case TAR_CHAR_OFFENSIVE:
if (victim == ch || victim == NULL)
{
victim = who_fighting(ch);
}
if (victim == NULL)
{
send_to_char( "Your target must have slipped away.\n\r", ch );
pop_call();
return FALSE;
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
break;
case TAR_UNDEAD_DEF:
case TAR_UNDEAD_OFF:
if (victim == ch || victim == NULL)
{
send_to_char( "Your must specify your target.\n\r", ch );
pop_call();
return FALSE;
}
if (target == TAR_UNDEAD_OFF && IS_UNDEAD(victim) && is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
if (target == TAR_UNDEAD_OFF)
target = TAR_CHAR_OFFENSIVE;
else
target = TAR_CHAR_DEFENSIVE;
break;
case TAR_CHAR_DEFENSIVE:
if (victim == NULL)
{
victim = ch;
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
break;
case TAR_CHAR_SELF:
if (victim == NULL)
{
victim = ch;
}
vo = (void *) ch;
break;
case TAR_OBJ_INV:
case TAR_OBJ_WIELD:
case TAR_OBJ_ROOM:
if (obj == NULL)
{
send_to_char( "Where is your target?\n\r", ch );
pop_call();
return FALSE;
}
vo = (void *) obj;
break;
case TAR_OBJ_CHAR_DEF:
if (victim)
{
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
target = TAR_CHAR_DEFENSIVE;
vo = (void *) victim;
}
else
{
target = TAR_OBJ_INV;
vo = (void *) obj;
}
break;
case TAR_OBJ_CHAR_OFF:
if (victim)
{
if (victim == ch && who_fighting(ch))
{
victim = who_fighting(ch);
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
target = TAR_CHAR_OFFENSIVE;
vo = (void *) victim;
}
else
{
target = TAR_OBJ_INV;
vo = (void *) obj;
}
break;
}
if (victim != NULL && victim != ch
&& IS_SET(skill_table[sn].flags, SF_TOUCH)
&& !IS_SET(ch->cast_feats, METAMAGIC_REACH))
{
// touch spells from or to incorporeals do not work - Kregor
if ((IS_INCORPOREAL(ch) && !IS_INCORPOREAL(victim))
|| (IS_INCORPOREAL(victim) && !IS_INCORPOREAL(ch)))
{
act("Your touch passes right through $N.", ch, NULL, victim, TO_CHAR);
act("$n's touch passes right through $N.", ch, NULL, victim, TO_NOTVICT);
act("$n's touch passes right through you.", ch, NULL, victim, TO_VICT);
pop_call();
return FALSE;
}
// if you don't hit with a touch attack, the spell is wasted
switch (target)
{
case TAR_CHAR_OFFENSIVE:
case TAR_OBJ_CHAR_OFF:
if (!can_melee_attack(ch, victim))
{
pop_call();
return TRUE;
}
if(!check_hit(ch, victim, dice(1,20), 0, sn, NULL, TRUE, FALSE))
{
act( "You attempt to touch $N, but miss.", ch, NULL, victim, TO_CHAR);
act( "$n attempts to touch $N, but misses.", ch, NULL, victim, TO_NOTVICT);
act( "$n attempts to touch you, but misses.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
break;
case TAR_CHAR_DEFENSIVE:
case TAR_OBJ_CHAR_DEF:
// must succeed a touch on ally if casting in melee - Kregor
if((in_combat(victim) || in_combat(ch)) && !check_hit(ch, victim, dice(1,20), 0, sn, NULL, TRUE, FALSE))
{
act( "You attempt to touch $N, but miss.", ch, NULL, victim, TO_CHAR);
act( "$n attempts to touch $N, but misses.", ch, NULL, victim, TO_NOTVICT);
act( "$n attempts to touch you, but misses.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
break;
}
}
if ((vic_obj = get_obj_tflag(ch, TFLAG_COUNTERSPELL)) != NULL)
{
if (vic_obj->value[1] == sn)
{
act( "$n's magic dissipates as $p counters it.", ch, vic_obj, victim, TO_VICT);
act( "Your spell dissipates as $N counters it.", ch, NULL, victim, TO_CHAR);
act( "$n's spell dissipates as it reaches $N.", ch, NULL, victim, TO_NOTVICT);
vic_obj->value[1] = -1;
pop_call();
return TRUE;
}
}
/*
* Mud20 variant - Spell Turning = caster level check
*/
if (victim && victim != ch && is_affected(victim, gsn_spell_turning))
{
if (dice(1,20) + level < 11 + get_affect_level(victim, gsn_spell_turning))
{
act( "White lightning surrounds you, reflecting $n's magic.", ch, NULL, victim, TO_VICT);
act( "White lightning surrounds $N, reflecting your magic.", ch, NULL, victim, TO_CHAR);
act( "White lightning surrounds $N, reflecting $n's magic.", ch, NULL, victim, TO_NOTVICT);
vo = (void *) ch;
// ch = victim;
affect_strip(victim, gsn_spell_turning);
}
}
if ((*skill_table[sn].spell_fun) ( sn, level, ch, vo, target ))
{
if (target == TAR_CHAR_OFFENSIVE)
{
if (can_see_casting(victim, ch, sn))
make_char_fight_char( ch, victim );
}
}
pop_call();
return TRUE;
}
/*
* For spell storing weapon flag
*/
bool weapon_cast_spell( int sn, int level, CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj )
{
OBJ_DATA *vic_obj;
void *vo;
int target;
push_call("obj_cast_spell(%p,%p,%p,%p,%p)",sn,level,ch,victim,obj);
if (obj == NULL)
{
pop_call();
return FALSE;
}
if (!WEAPON_FLAG(obj, WFLAG_SPELL_STORING))
{
pop_call();
return FALSE;
}
if (sn <= 0)
{
pop_call();
return FALSE;
}
if (is_safe_magic(ch, NULL, sn))
{
pop_call();
return FALSE;
}
if (!is_spell(sn) || skill_table[sn].spell_fun == 0)
{
if (obj != NULL)
{
log_printf("obj_cast_spell: Vnum %u bad sn %d.", obj->pIndexData->vnum, sn);
}
else
{
log_printf("Unknown item cast sn %d", sn);
}
pop_call();
return FALSE;
}
target = skill_table[sn].target;
switch (target)
{
default:
bug( "obj_cast_spell: bad target for sn %d.", sn );
pop_call();
return TRUE;
case TAR_IGNORE:
vo = NULL;
break;
case TAR_CHAR_OFFENSIVE:
if (victim == ch || victim == NULL)
{
victim = who_fighting(ch);
}
if (victim == NULL)
{
send_to_char( "Your target must have slipped away.\n\r", ch );
pop_call();
return TRUE;
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
break;
case TAR_UNDEAD_DEF:
case TAR_UNDEAD_OFF:
if (victim == ch || victim == NULL)
{
send_to_char( "Your must specify your target.\n\r", ch );
pop_call();
return TRUE;
}
if (target == TAR_UNDEAD_OFF && IS_UNDEAD(victim) && is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
if (target == TAR_UNDEAD_OFF)
target = TAR_CHAR_OFFENSIVE;
else
target = TAR_CHAR_DEFENSIVE;
break;
case TAR_CHAR_DEFENSIVE:
if (victim == NULL)
{
victim = ch;
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
vo = (void *) victim;
break;
case TAR_CHAR_SELF:
if (victim == NULL)
{
victim = ch;
}
vo = (void *) ch;
break;
case TAR_OBJ_CHAR_DEF:
if (victim)
{
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
target = TAR_CHAR_DEFENSIVE;
vo = (void *) victim;
}
else
{
bug( "obj_cast_spell: bad target for sn %d.", sn );
pop_call();
return TRUE;
}
break;
case TAR_OBJ_CHAR_OFF:
if (victim)
{
if (victim == ch && who_fighting(ch))
{
victim = who_fighting(ch);
}
if (is_safe_magic(ch, victim, sn))
{
pop_call();
return FALSE;
}
target = TAR_CHAR_OFFENSIVE;
vo = (void *) victim;
}
else
{
bug( "obj_cast_spell: bad target for sn %d.", sn );
pop_call();
return TRUE;
}
break;
}
if ((vic_obj = get_obj_tflag(ch, TFLAG_COUNTERSPELL)) != NULL)
{
if (vic_obj->value[1] == sn)
{
act( "$n's magic dissipates as $p counters it.", ch, vic_obj, victim, TO_VICT);
act( "Your spell dissipates as $N counters it.", ch, NULL, victim, TO_CHAR);
act( "$n's spell dissipates as it reaches $N.", ch, NULL, victim, TO_NOTVICT);
vic_obj->value[1] = -1;
pop_call();
return TRUE;
}
}
/*
* Mud20 variant - Spell Turning = caster level check
*/
if (victim && victim != ch && is_affected(victim, gsn_spell_turning))
{
if (dice(1,20) + level < 11 + get_affect_level(victim, gsn_spell_turning))
{
act( "White lightning surrounds you, reflecting $n's magic.", ch, NULL, victim, TO_VICT);
act( "White lightning surrounds $N, reflecting your magic.", ch, NULL, victim, TO_CHAR);
act( "White lightning surrounds $N, reflecting $n's magic.", ch, NULL, victim, TO_NOTVICT);
vo = (void *) ch;
// ch = victim;
affect_strip(victim, gsn_spell_turning);
}
}
(*skill_table[sn].spell_fun) ( sn, level, ch, vo, target );
pop_call();
return TRUE;
}
/*
Magical Totem casting spells on the room
*/
void totem_cast_spell( OBJ_DATA *obj )
{
CHAR_DATA *totem, *rch, *rch_next;
int sn, level, target;
push_call("totem_cast_spell(%p)",obj);
if (obj->in_room == NULL)
{
pop_call();
return;
}
if (obj->in_room->area->nplayer == 0 || obj->in_room->nplayer == 0)
{
pop_call();
return;
}
if ((totem = mob_index[MOB_VNUM_TOTEM]->first_instance) == NULL)
{
pop_call();
return;
}
target_name = "";
STRFREE(totem->short_descr);
totem->short_descr = STRDUPE(obj->short_descr);
char_to_room(totem, obj->in_room->vnum, FALSE);
act( "The air thickens with magic as $n starts to hum.", totem, NULL, NULL, TO_ROOM);
for (rch = obj->in_room->first_person ; rch ; rch = rch_next)
{
rch_next = rch->next_in_room;
if (rch == totem)
{
continue;
}
if (IS_NPC(rch) && IS_SET(rch->act, ACT_MOBINVIS))
{
continue;
}
sn = obj->value[number_range(0,3)];
if (!is_spell(sn))
{
continue;
}
level = obj->level;
target = skill_table[sn].target;
switch (target)
{
case TAR_OBJ_CHAR_OFF:
target = TAR_CHAR_OFFENSIVE;
break;
case TAR_OBJ_CHAR_DEF:
target = TAR_CHAR_DEFENSIVE;
break;
}
(*skill_table[sn].spell_fun) (sn, level, totem, rch, target);
}
char_to_room(totem, ROOM_VNUM_TOTEM, FALSE);
pop_call();
return;
}
/*
* dismiss a dismissable spell if you were the caster - Kregor 10/1/07
*/
void do_dismiss (CHAR_DATA *ch, char *argument)
{
AFFECT_DATA *paf, *paf_next;
CHAR_DATA *victim;
int paf_type, sn;
char arg1[MAX_INPUT_LENGTH];
push_call("do_dismiss(%p,%p)",ch,argument);
if (IS_NPC(ch))
{
send_to_char("You did not dismiss anything.\n\r", ch);
pop_call();
return;
}
argument = one_argument(argument, arg1);
if ((sn = skill_lookup(arg1)) == -1)
{
send_to_char("That is not a spell.\n\r", ch);
pop_call();
return;
}
if (argument[0] == '\0')
{
victim = ch;
}
else if ((victim = get_char_room(ch, argument)) == NULL)
{
send_to_char("That person is not here.\n\r", ch);
pop_call();
return;
}
for ( paf_type = 0, paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if( paf->type != sn )
continue;
if (!is_spell(paf->type))
continue;
if (!is_name(paf->caster, ch->name))
{
send_to_char("You can only dismiss spells cast by you.\n\r", ch);
continue;
}
if (paf->duration < 0)
{
send_to_char("You cannot dismiss permanent affects.\n\r", ch);
continue;
}
if (!IS_SET(skill_table[sn].flags, SF_DISMISSABLE))
{
send_to_char("That spell cannot be dismissed.\n\r", ch);
break;
}
if (paf->duration >= 0 && paf_type == 0)
{
if (skill_table[paf->type].msg_off)
{
act( skill_table[paf->type].msg_off, victim, NULL, NULL, TO_CHAR);
}
if (skill_table[paf->type].msg_off_room)
{
act( skill_table[paf->type].msg_off_room, victim, NULL, NULL, TO_ROOM);
}
}
paf_type = paf->type;
affect_from_char(victim, paf);
}
if (paf_type == 0)
{
send_to_char( "You did not dismiss anything.\n\r", ch );
pop_call();
return;
}
else if (victim != ch && !is_string(skill_table[paf->type].msg_off_room))
{
act( "You dismiss $t from $N.", ch, skill_table[sn].name, victim, TO_CHAR );
}
TAKE_ACTION(ch, ACTION_STANDARD);
pop_call();
return;
}
/*
Returns TRUE and gives appropriate spams if one cannot cast a spell
on the victim, if victim is NULL only room and ch based stuff is
checked - Scandum 01-04-2002
*/
bool is_safe_magic( CHAR_DATA *ch, CHAR_DATA *victim, int sn)
{
push_call("is_safe_magic(%p,%p)",ch,victim);
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
{
if (skill_table[sn].target == TAR_IGNORE)
{
if (skill_table[sn].minimum_position == POS_FIGHTING)
{
send_to_char( "Wards prevent you from doing that here.\n\r", ch);
pop_call();
return TRUE;
}
}
if (skill_table[sn].target == TAR_CHAR_OFFENSIVE
|| skill_table[sn].target == TAR_OBJ_CHAR_OFF)
{
send_to_char( "Wards prevent you from doing that here.\n\r", ch);
pop_call();
return TRUE;
}
}
//antimagic suppresses both spells and supernatural abilities - Kregor
if (is_spell(sn) || IS_SET(skill_table[sn].flags, SF_SUPERNATURAL|SF_SPELL_LIKE))
{
if (IS_SET(ch->in_room->room_flags, ROOM_NO_MAGIC))
{
send_to_char( "Your magic fizzles.\n\r",ch);
pop_call();
return TRUE;
}
// and is beyond the interest of transformed combatants.
if (is_affected(ch, gsn_transformation))
{
send_to_char( "You're too thrilled with battle right now!\n\r",ch);
pop_call();
return TRUE;
}
}
if (IS_SET(skill_table[sn].flags, SF_NONCOMBAT))
{
if (in_combat(ch))
{
send_to_char( "This effect cannot be cast in combat.\n\r", ch );
pop_call();
return TRUE;
}
}
if (victim == NULL)
{
pop_call();
return FALSE;
}
if (IS_OFFENSIVE(victim, sn) && !IS_NPC(ch) && !IS_NPC(victim) && IS_SET(ch->in_room->area->flags, AFLAG_NO_PVP))
{
send_to_char( "You are currently in a no-pvp area.\n\r", ch);
pop_call();
return TRUE;
}
// can't attack the supermob!
if (victim == supermob)
{
pop_call();
return TRUE;
}
if (is_affected(victim, gsn_time_stop))
{
act("You cannot affect $N while $E is frozen in time.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
if (victim == ch)
{
pop_call();
return FALSE;
}
if (IS_SET(skill_table[sn].flags, SF_NONCOMBAT))
{
if (in_combat(victim))
{
send_to_char( "This effect cannot be cast in combat.\n\r", ch );
pop_call();
return TRUE;
}
}
//hostile action removes fascination.
if (IS_OFFENSIVE(victim, sn))
{
if (IS_AFFECTED(victim, AFF2_FASCINATED))
{
AFFECT_STRIP(victim, AFF2_FASCINATED);
act("Your fascination is broken due to $N's actions.", victim, NULL, ch, TO_CHAR);
}
// victim's safe room must be taken into account as well
if (IS_SET(victim->in_room->room_flags, ROOM_SAFE))
{
send_to_char( "Wards prevent you from doing that here.\n\r", ch);
pop_call();
return TRUE;
}
// even an offensive spell can't be targeted against a sancted victim
// which is why this isn't in can_melee_attack instead
if (IS_AFFECTED(victim, AFF_SANCTUARY) && !IS_AREA_SPELL(sn))
{
if (!save_resist(ch, victim, gsn_sanctuary, get_affect_level(victim, gsn_sanctuary)))
{
send_to_char( "A magical force stays your hand.\n\r", ch);
pop_call();
return TRUE;
}
}
}
if ((is_spell(sn) || IS_SET(skill_table[sn].flags, SF_SUPERNATURAL|SF_SPELL_LIKE)) && victim->in_room && IS_SET(victim->in_room->room_flags, ROOM_NO_MAGIC))
{
send_to_char( "Nothing happens...\n\r",ch);
pop_call();
return TRUE;
}
if (who_fighting(ch) && who_fighting(ch) == victim)
{
pop_call();
return FALSE;
}
if (ch->in_room->area->low_r_vnum == ROOM_VNUM_ARENA)
{
pop_call();
return FALSE;
}
switch (skill_table[sn].target)
{
default:
bug( "is_safe_magic: bad target for sn %d.", sn );
pop_call();
return TRUE;
break;
case TAR_CHAR_OFFENSIVE:
case TAR_OBJ_CHAR_OFF:
if (ch->desc)
{
if (!IS_NPC(victim) && !check_murder(ch, victim))
{
pop_call();
return TRUE;
}
}
if (!IS_NPC(ch))
{
ch->pcdata->just_died_ctr = 0;
}
break;
case TAR_UNDEAD_OFF:
if (IS_UNDEAD(victim))
{
if (ch->desc)
{
if (!IS_NPC(victim) && !check_murder(ch, victim))
{
pop_call();
return TRUE;
}
}
if (!IS_NPC(ch))
{
ch->pcdata->just_died_ctr = 0;
}
break;
}
break;
case TAR_UNDEAD_DEF:
if (!IS_UNDEAD(victim))
{
if (ch->desc)
{
if (!IS_NPC(victim) && !check_murder(ch, victim))
{
pop_call();
return TRUE;
}
}
if (!IS_NPC(ch))
{
ch->pcdata->just_died_ctr = 0;
}
break;
}
break;
case TAR_CHAR_DEFENSIVE:
case TAR_OBJ_CHAR_DEF:
break;
}
pop_call();
return FALSE;
}
/*
true if victim is a legal target for a mass attack - Scandum 01/04/2002
*/
bool can_mass_cast( CHAR_DATA *ch, CHAR_DATA *victim, int sn )
{
push_call("can_mass_cast(%p,%p)",ch,victim);
CHAR_DATA *rch, *rch_next;
if (victim == ch)
{
pop_call();
return FALSE;
}
if (IS_SET(skill_table[sn].flags, SF_NONCOMBAT))
{
if (in_combat(victim))
{
pop_call();
return FALSE;
}
}
if (!IS_NPC(ch) && !IS_NPC(victim) && IS_SET(ch->in_room->area->flags, AFLAG_NO_PVP))
{
pop_call();
return FALSE;
}
if (who_fighting(victim))
{
if (who_fighting(victim) == ch)
{
pop_call();
return TRUE;
}
if (!is_same_group(ch, who_fighting(victim)))
{
pop_call();
return FALSE;
}
}
if (IS_NPC(victim) && IS_SET(victim->act, ACT_MOBINVIS))
{
pop_call();
return FALSE;
}
if (is_same_group(ch, victim))
{
pop_call();
return FALSE;
}
if (IS_NPC(victim) && (IS_AFFECTED(victim, AFF_DOMINATE) || IS_SET(ch->act, ACT_PET)) && victim->master != NULL)
{
if (victim->master == ch)
{
pop_call();
return FALSE;
}
for (rch = ch->in_room->first_person ; rch ; rch = rch_next)
{
rch_next = rch->next_in_room;
if (victim->master == rch)
{
pop_call();
return TRUE;
}
}
}
if (ch->in_room->area->low_r_vnum == ROOM_VNUM_ARENA)
{
pop_call();
return TRUE;
}
pop_call();
return TRUE;
}
int get_mana( CHAR_DATA *ch, int sn, int circle, int class )
{
int mana = 0, effcircle, maxcircle, diff;
push_call("get_mana(%p)", circle);
effcircle = get_metamagic(ch, sn, ch->metamagic, circle, class, FALSE);
switch (effcircle)
{
case 0:
break;
case 1:
mana = 1;
break;
case 2:
mana = 3;
break;
case 3:
mana = 5;
break;
case 4:
mana = 7;
break;
case 5:
mana = 9;
break;
case 6:
mana = 11;
break;
case 7:
mana = 13;
break;
case 8:
mana = 15;
break;
case 9:
mana = 17;
break;
default:
bug("get_mana: bad spell circle!",0);
break;
}
// no additional mana for scaling if the spell isn't scalable
if (IS_SET(skill_table[sn].flags, SF_SCALABLE))
{
maxcircle = UMIN(max_spell_circle(ch, class), skill_table[sn].mana_move);
diff = UMAX(0, maxcircle - circle);
mana += diff * 2;
}
wiz_printf("get_mana: effective circle = %d, mana cost = %d.", effcircle, mana);
pop_call();
return(mana);
}
bool is_spell_like( int sn )
{
push_call("is_spell(%p)",sn);
if (sn > 0 && sn < TYPE_HIT && is_string(skill_table[sn].name) && (skill_table[sn].skilltype == FSKILL_SPELL || IS_SET(skill_table[sn].flags, SF_SPELL_LIKE)))
{
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
bool is_spell( int sn )
{
push_call("is_spell(%p)",sn);
if (sn > 0 && sn < TYPE_HIT && is_string(skill_table[sn].name) && skill_table[sn].skilltype == FSKILL_SPELL)
{
pop_call();
return TRUE;
}
pop_call();
return FALSE;
}
/*
* d20 counterspelling w/ imp. counterspell support - Kregor
* Variant rule in play here as follows:
* Countering is an immediate action, so long as you haven't
* acted already in the round.
* Any attempt to counter a spell requires a spellcraft check
* opposed by a caster level check, both rolls modified by their
* respective spells' circle.
*
* 3/23/11 added Countersong ability support.
*/
bool counterspell(CHAR_DATA *ch, CHAR_DATA *caster, int sn, int level, bool CounterSong)
{
int snb, mana, class, circle, circleb, chroll, castroll;
push_call("counterspell(%p,%p,%p)",caster,ch,sn,level);
/* is immediate action so long as standard action hasn't been taken this round */
if (IS_SET(ch->action, ACTION_STANDARD))
{
act( "You've already acted in this round.", ch, NULL, caster, TO_CHAR);
if (IS_NPC(ch))
wiz_printf("counterspell(%d - %s): can't take an immediate action.", ch->pIndexData->vnum, ch->name);
pop_call();
return FALSE;
}
/* little checks so NPCs don't counter non-harmful spells */
if (IS_NPC(ch))
{
switch (skill_table[sn].target)
{
default:
pop_call();
return FALSE;
case TAR_CHAR_OFFENSIVE:
case TAR_OBJ_CHAR_OFF:
break;
case TAR_UNDEAD_OFF:
if (!IS_UNDEAD(ch))
{
pop_call();
return FALSE;
}
break;
}
}
circle = get_spell_circle(caster, sn);
castroll = dice(1,20) + circle + level;
if (learned(caster, gsn_furtive_spell) && !learned(ch, gsn_shadow_casting))
{
castroll += 4;
}
if (CounterSong)
{
if (!CHECK_USES(ch, gsn_bardic_song))
{
act("You have no bardic music left.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!IS_SET(skill_table[sn].flags, SF_AUDIBLE|SF_VERBAL))
{
act("That spell has no verbal or audible component.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
chroll = perform_roll(ch);
ch->uses[gsn_bardic_song]++;
}
else
{
/* First, without improved counterspell, must use same spell or dispel magic */
if (!learned(ch, gsn_imp_counterspell))
{
if ((circleb = get_spell_circle(ch, sn)) == -1)
{
if ((circleb = get_spell_circle(ch, gsn_dispel_magic)) == -1)
{
if ((circleb = get_spell_circle(ch, gsn_greater_dispel)) == -1)
{
act( "You do not have a spell ready to counter $N's.", ch, NULL, caster, TO_CHAR);
if (IS_NPC(ch))
wiz_printf("counterspell(%d - %s): tried to counter without imp. counterspell.", ch->pIndexData->vnum, ch->name);
pop_call();
return FALSE;
}
else
snb = gsn_greater_dispel;
}
else
snb = gsn_dispel_magic;
}
else
snb = sn;
}
/* next, look for a spell of the same school and at least the same level */
else
{
for (snb = 0 ; *skill_table[snb].name != '\0' ; snb++)
{
if (!is_spell(snb))
continue;
if (skill_table[sn].spell_school != skill_table[snb].spell_school)
continue;
if ((circleb = get_spell_circle(ch, snb)) >= circle)
break;
}
if (*skill_table[snb].name != '\0')
{
act( "You do not have a suitable counter to $N's spell.", ch, NULL, caster, TO_CHAR);
if (IS_NPC(ch))
wiz_printf("counterspell(%d - %s): tried to counter with imp. counterspell and failed.", ch->pIndexData->vnum, ch->name);
pop_call();
return FALSE;
}
}
if ((class = prepared(ch, snb)) == -1)
{
if ((class = spontaneous_cast(ch, snb)) == -1)
{
act( "You are not powerful enough to counter $N's spell.", ch, NULL, caster, TO_CHAR);
pop_call();
return FALSE;
}
}
/* If you haven't got the mana, you can't counter */
if ((mana = get_mana(ch, snb, circleb, class)) > ch->mana[class])
{
act( "You lack the mana to counter $N's spell.", ch, NULL, caster, TO_CHAR);
if (IS_NPC(ch))
wiz_printf("counterspell(%d - %s): tried to counter without enough mana.", ch->pIndexData->vnum, ch->name);
pop_call();
return FALSE;
}
chroll = spellcraft_roll(ch) + circleb;
ch->mana[class] -= mana;
}
if (chroll < castroll)
{
if (CounterSong
|| !arcane_mastery(ch, SCHOOL_ABJURATION)
|| spellcraft_roll(ch) + circleb < castroll)
{
act( "{168}$n tries to counter $N's spell and fails.", ch, NULL, caster, TO_NOTVICT);
act( "{168}$n tries to counter your spell and fails.", ch, NULL, caster, TO_VICT);
act( "{168}You try to counter $N's spell and fails.", ch, NULL, caster, TO_CHAR);
TAKE_ACTION(ch, ACTION_STANDARD);
pop_call();
return FALSE;
}
}
act( "{168}$N's magic dissipates as $n counters it.", ch, NULL, caster, TO_NOTVICT);
act( "{168}Your spell dissipates as $n counters it.", ch, NULL, caster, TO_VICT);
act( "{168}$N's spell dissipates as you counter it.", ch, NULL, caster, TO_CHAR);
TAKE_ACTION(ch, ACTION_STANDARD);
pop_call();
return TRUE;
}
void do_counterspell( CHAR_DATA *ch, char *argument )
{
CHAR_DATA *caster;
push_call("do_counterspell(%p,%p)",ch,argument);
if (IS_SET(ch->action, ACTION_STANDARD))
{
act("You have already made a standard action this round.", ch, NULL, NULL, TO_CHAR);
pop_call();
return;
}
if (*argument == '\0')
{
act("Counterspell whom?", ch, NULL, NULL, TO_CHAR);
pop_call();
return;
}
if ((caster = get_char_room(ch, argument)) == NULL)
{
act("There is no $t here.", ch, argument, NULL, TO_CHAR);
pop_call();
return;
}
if (!caster->casting || !is_spell(caster->cast_sn))
{
act("$N is not casting a spell.", ch, argument, NULL, TO_CHAR);
pop_call();
return;
}
if (counterspell(ch, caster, caster->cast_sn, caster->cast_level, FALSE))
{
free_cast(caster);
}
pop_call();
return;
}
ROOM_INDEX_DATA *get_rift_room( CHAR_DATA *ch, int rift_number)
{
ROOM_INDEX_DATA *rift_room;
push_call("get_rift_room(%p,%p)",ch,rift_number);
srand(value + ch->pcdata->pvnum + 1);
while (TRUE)
{
rift_room = get_room_index(rand() % 20000);
if (rift_room == NULL)
{
continue;
}
if (IS_SET(rift_room->room_flags, ROOM_SAFE))
{
continue;
}
if (IS_SET(rift_room->room_flags, ROOM_CLANHALL))
{
continue;
}
if (IS_SET(rift_room->room_flags, ROOM_PET_SHOP))
{
continue;
}
if (IS_SET(rift_room->room_flags, ROOM_PRIVATE))
{
continue;
}
if (IS_SET(rift_room->room_flags, ROOM_SOLITARY))
{
continue;
}
if (IS_SET(rift_room->room_flags, ROOM_NO_RECALL))
{
continue;
}
if (rift_room->sector_type == SECT_ETHEREAL)
{
continue;
}
if (rift_room->sector_type == SECT_ASTRAL)
{
continue;
}
if (IS_SET(rift_room->area->flags, AFLAG_NOTELEPORT))
{
continue;
}
if (IS_SET(rift_room->area->flags, AFLAG_NORECALL))
{
continue;
}
if (IS_SET(rift_room->area->flags, AFLAG_NORIP))
{
continue;
}
if (!IS_IMMORTAL(ch))
{
if (ch->level < rift_room->area->low_hard_range)
{
continue;
}
if (ch->level > rift_room->area->hi_hard_range)
{
continue;
}
}
break;
}
pop_call();
return rift_room;
}
/*
* Global save/resist check for all spells.
* Uses target mode of spell to determine whether save or resistance applies.
* Returns TRUE if completely resisted, PARTIAL if partially saved or
* FALSE if save and resistance failed.
*/
int save_resist(CHAR_DATA *ch, CHAR_DATA *victim, int sn, int level)
{
char name[MAX_INPUT_LENGTH];
bool area = FALSE;
bool fort = FALSE;
bool refl = FALSE;
bool will = FALSE;
int save = skill_table[sn].save;
push_call("save_resist(%p)",ch);
// If you REALLY want to cast that on yourself... - Kregor
if (ch == victim)
{
pop_call();
return FALSE;
}
// invulnerable to any affect while time stopped - Kregor
if (is_affected(victim, gsn_time_stop))
{
pop_call();
return TRUE;
}
//ethereal creatures cannot be affected by non-ethereal except for force affects & abjurations.
if (!CAN_ETHEREAL_WALK(ch) && CAN_ETHEREAL_WALK(victim))
{
if (skill_table[sn].spell_school != SCHOOL_ABJURATION && !IS_SET(skill_table[sn].spell_desc, SDESC_FORCE))
{
act("Only force affects and abjurations can affect ethereal creatures.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
if (!CAN_ETHEREAL_WALK(victim) && CAN_ETHEREAL_WALK(ch))
{
act("Your magic has no affect upon the material world.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (skill_table[sn].name)
strcpy(name, skill_table[sn].name);
else
strcpy(name, "spell");
switch (save)
{
case SAVE_FORT_HALF:
case SAVE_FORT_NONE:
fort = TRUE;
break;
case SAVE_REFL_HALF:
case SAVE_REFL_NONE:
refl = TRUE;
break;
case SAVE_WILL_HALF:
case SAVE_WILL_NONE:
will = TRUE;
break;
}
if (IS_AREA_SPELL(sn))
area = TRUE;
if (IS_SET(skill_table[sn].flags, SF_VISUAL) && IS_BLIND(victim))
{
act("$N can't seem to see your magic to fully appreciate it.", ch, NULL, victim, TO_CHAR);
act("$N can't seem to see $n's magic to fully appreciate it.", ch, NULL, victim, TO_NOTVICT);
pop_call();
return TRUE;
}
if (race_type(victim) == RTYPE_CONSTRUCT)
{
if (IS_SET(skill_table[sn].spell_desc, SDESC_HEALING|SDESC_NEGATIVE))
{
act("$N is unaffected by your magic.", ch, NULL, victim, TO_CHAR);
act("$N seems to be unaffected.", ch, NULL, victim, TO_NOTVICT);
pop_call();
return TRUE;
}
}
if (domain_apotheosis(victim, DOMAIN_REPOSE))
{
if (sn == gsn_enervation || sn == gsn_energy_drain)
{
act("$N is unaffected by your magic.", ch, NULL, victim, TO_CHAR);
act("$N seems to be unaffected.", ch, NULL, victim, TO_NOTVICT);
pop_call();
return TRUE;
}
}
if (skill_table[sn].skilltype == FSKILL_BARDSONG
&& is_affected(victim, gsn_bardic_song))
{
act("$N is already affected by bardic music.", ch, NULL, victim, TO_CHAR);
act("You are already under the affect of bardic music.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
if (IS_DEAF(victim) || IS_AFFECTED(victim, AFF2_SILENCE))
{
if (IS_SET(skill_table[sn].flags, SF_AUDIBLE|SF_LANGUAGE)
|| skill_table[sn].skilltype == FSKILL_BARDSONG
|| sn == gsn_bardic_song)
{
act("$N is unaffected by your spell.", ch, NULL, victim, TO_CHAR);
act("$N is unaffected by $n's spell.", ch, NULL, victim, TO_NOTVICT);
act("You are unaffected by $n's spell.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
}
if (IS_SET(skill_table[sn].spell_desc, SDESC_SONIC)
&& IS_AFFECTED(victim, AFF2_SILENCE))
{
act("$N is unaffected by your spell.", ch, NULL, victim, TO_CHAR);
act("$N is unaffected by $n's spell.", ch, NULL, victim, TO_NOTVICT);
act("You are unaffected by $n's spell.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
if (IS_SET(skill_table[sn].flags, SF_LANGUAGE)
&& !can_understand(victim, ch, TRUE))
{
act("$N cannnot understand your incantation.", ch, NULL, victim, TO_CHAR);
act("$n utters words you cannot understand.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
if (IS_SET(skill_table[sn].flags, SF_RANGED_TOUCH))
{
if (!check_hit(ch, victim, dice(1,20), 0, sn, NULL, TRUE, TRUE))
{
act( "Your $t misses $N.", ch, name, victim, TO_CHAR);
act( "$n's $t misses you.", ch, name, victim, TO_VICT);
act( "$n misses $N with $s $t.", ch, name, victim, TO_NOTVICT);
pop_call();
return TRUE;
}
}
//Adding globes of invuln, resists anything unless cast on self - Kregor
if (is_affected(victim, gsn_globe_of_invulnerability))
{
if (get_spell_circle(ch, sn) <= 4)
{
act("$N's shimmering aura absorbs your spell!", ch, NULL, victim, TO_CHAR);
act("$N's shimmering aura absorbs $n's spell!", ch, NULL, victim, TO_NOTVICT);
act("Your globe of invulnerability absorbs $n's spell!", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
}
else if (is_affected(victim, gsn_minor_globe))
{
if (get_spell_circle(ch, sn) <= 3)
{
act("$N's shimmering aura absorbs your spell!", ch, NULL, victim, TO_CHAR);
act("$N's shimmering aura absorbs $n's spell!", ch, NULL, victim, TO_NOTVICT);
act("Your globe of invulnerability absorbs $n's spell!", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
}
if (skill_table[sn].spell_school == SCHOOL_DIVINATION && check_nondetection(ch, victim, sn))
{
act("N's mind is closed off to you!", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
if (IS_OFFENSIVE(victim, sn))
{
if (area && !can_mass_cast(ch, victim, sn))
{
pop_call();
return TRUE;
}
if (check_spell_resist(victim, ch, sn, level))
{
pop_call();
return TRUE;
}
if (sn == gsn_undeath_ward && IS_UNDEAD(ch) && ch->level < level)
{
pop_call();
return FALSE;
}
if (save != SAVE_NONE && is_immune(victim, skill_table[sn].spell_desc))
{
pop_call();
return TRUE;
}
if (sn == gsn_magic_missile && is_affected(victim, gsn_shield))
{
act( "$n's magic missile dissipates as it reaches you!", ch, name, victim, TO_VICT);
act( "$n's magic missile dissipates as it reaches $N!", ch, name, victim, TO_NOTVICT);
act( "Your magic missile dissipates as it reaches $N!", ch, name, victim, TO_CHAR);
pop_call();
return TRUE;
}
if (refl)
{
if (refl_save(victim, ch, level, sn))
{
if (save == SAVE_REFL_NONE || learned(ch, gsn_evasion))
{
act( "You dodge aside from $n's $t.", ch, name, victim, TO_VICT);
act( "$N dodges aside from $n's $t.", ch, name, victim, TO_NOTVICT);
act( "$N dodges aside from your $t.", ch, name, victim, TO_CHAR);
pop_call();
return TRUE;
}
else
{
act( "You dodge the brunt of $n's $t.", ch, name, victim, TO_VICT);
act( "$N dodges the brunt of $n's $t.", ch, name, victim, TO_NOTVICT);
act( "$N dodges the brunt of your $t.", ch, name, victim, TO_CHAR);
pop_call();
return PARTIAL;
}
}
else
{
if (learned(ch, gsn_imp_evasion))
{
act( "{138}You evade the brunt of $n's $t.", ch, name, victim, TO_VICT);
act( "{138}$N evades the brunt of $n's $t.", ch, name, victim, TO_NOTVICT);
act( "{138}$N evades the brunt of your $t.", ch, name, victim, TO_CHAR);
pop_call();
return PARTIAL;
}
}
}
else if (fort && fort_save(victim, ch, level, sn))
{
if (save == SAVE_FORT_NONE || (learned(ch, gsn_mettle) && IS_AWAKE(ch)))
{
act( "You resist $n's $t.", ch, name, victim, TO_VICT);
act( "$N resists $n's $t.", ch, name, victim, TO_NOTVICT);
act( "$N resists your $t.", ch, name, victim, TO_CHAR);
pop_call();
return TRUE;
}
else
{
act( "You partially resist $n's $t.", ch, name, victim, TO_VICT);
act( "$N partially resists $n's $t.", ch, name, victim, TO_NOTVICT);
act( "$N partially resists your $t.", ch, name, victim, TO_CHAR);
pop_call();
return PARTIAL;
}
}
else if (will && will_save(victim, ch, level, sn))
{
if (save == SAVE_WILL_NONE || (learned(ch, gsn_mettle) && IS_AWAKE(ch)))
{
act( "You resist $n's $t.", ch, name, victim, TO_VICT);
act( "$N resists $n's $t.", ch, name, victim, TO_NOTVICT);
act( "$N resists your $t.", ch, name, victim, TO_CHAR);
pop_call();
return TRUE;
}
else
{
act( "You partially resist $n's $t.", ch, name, victim, TO_VICT);
act( "$N partially resists $n's $t.", ch, name, victim, TO_NOTVICT);
act( "$N partially resists your $t.", ch, name, victim, TO_CHAR);
pop_call();
return PARTIAL;
}
}
}
pop_call();
return FALSE;
}
/*
* Wrapping spells into universal functions - Kregor 3/10/08
*/
/*
* All standard damage spells should go thru this function
*/
void spell_damage(CHAR_DATA *ch, CHAR_DATA *victim, int dmg, int sn, int level)
{
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
ROOM_TIMER_DATA *rtd;
int dam, save;
bool area = FALSE;
push_call("spell_damage(%p)",ch);
if (IS_AREA_SPELL(sn))
{
area = TRUE;
// fire attacks remove swarms from the room - Kregor
if (IS_SET(skill_table[sn].spell_desc, SDESC_FIRE)
&& (rtd = get_room_affect(victim->in_room, ROOM_SWARM)) != NULL)
{
rtd->duration = 0;
}
}
if (IS_SET(skill_table[sn].flags, SF_RANGED_TOUCH))
{
if (!check_hit(ch, victim, dice(1,20), 0, sn, NULL, TRUE, TRUE))
{
damage( ch, victim, 0, sn, NULL );
pop_call();
return;
}
}
if (IS_SET(skill_table[sn].flags, SF_RANGED_TOUCH|SF_TOUCH))
{
if (can_backstab(ch, victim, sn) && number_percent() > get_apply(victim, APPLY_FORTIFICATION))
{
int bs_dice = ROUNDUP(multi_skill_level(ch, gsn_backstab) / 2);
int bs_dam = 0;
if (get_monk_style(ch) == STYLE_SLEEPING_TIGER && class_level(ch, CLASS_MONK) >= 12)
bs_dice++;
if (bs_dice > 0)
{
if (learned(ch, gsn_greater_sneak_attack))
{
bs_dam = dice(bs_dice, 8);
}
else
{
bs_dam = dice(bs_dice, 6);
}
}
dmg += bs_dam;
}
}
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
dam = dmg;
if (area && !can_mass_cast(ch, vch, sn))
continue;
if (!area && vch != victim)
continue;
if (area && IS_NPC(ch) && !is_same_group(victim, vch))
continue;
if ((save = save_resist(ch, vch, sn, level)) == TRUE)
{
continue;
}
if (save == PARTIAL)
{
switch (skill_table[sn].save)
{
case SAVE_FORT_QUARTER:
case SAVE_REFL_QUARTER:
case SAVE_WILL_QUARTER:
dam /= 4;
break;
case SAVE_FORT_NONE:
case SAVE_REFL_NONE:
case SAVE_WILL_NONE:
dam = 0;
break;
default:
dam /= 2;
break;
}
}
// side effects go before damage
if (sn == gsn_shout && !save)
{
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
af.duration = ROUNDUP(level/5);
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_DEAF;
af.level = level;
affect_to_char( ch, vch, &af );
}
if (sn == gsn_flamestrike)
{
dam /= 2;
damage( ch, vch, dam, gsn_divine_hit, NULL );
}
if (sn == gsn_ice_storm)
{
dam /= 2;
damage( ch, vch, dam, gsn_bash_hit, NULL );
}
damage( ch, vch, dam, sn, NULL );
/* end this loop if victim only */
if (!area)
break;
}
pop_call();
return;
}
void show_identify_string( OBJ_DATA *obj, CHAR_DATA *viewer)
{
char buf[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
AFFECT_DATA *paf;
int cnt;
push_call("show_identify_string(%p,%p)",obj,viewer);
buf2[0] = '\0';
if (is_string(obj->id_name))
cat_sprintf(buf2, "%s\n\r", obj->id_name);
if (is_string(obj->id_descr))
cat_sprintf(buf2, "%s\n\r", obj->id_descr);
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
{
cat_sprintf(buf2, "This item does have magical properties.\n\r");
}
else
{
cat_sprintf(buf2, "This item does not have any magical properties.\n\r");
send_to_char_color(buf2, viewer);
pop_call();
return;
}
switch ( obj->item_type )
{
case ITEM_SCROLL:
sprintf(buf, "It contains a level %d %s spell of:",
obj->value[0], obj->value[2] < 1 ? "arcane" : "divine");
cat_sprintf(buf, " '%s'", skill_name(obj->value[1]));
cat_sprintf(buf2, "%s\n\r", buf);
break;
case ITEM_POTION:
sprintf(buf, "It contains a level %d spell of:", obj->value[0]);
cat_sprintf(buf, " '%s'", skill_name(obj->value[1]));
cat_sprintf(buf2, "%s\n\r", buf);
break;
case ITEM_PILL:
sprintf(buf, "It contains level %d spells of:", obj->value[0]);
if (valid_skill(obj->value[1]))
{
cat_sprintf(buf, " '%s'", skill_table[obj->value[1]].name);
}
if (valid_skill(obj->value[2]))
{
cat_sprintf(buf, " '%s'", skill_table[obj->value[2]].name);
}
if (valid_skill(obj->value[3]))
{
cat_sprintf(buf, " '%s'", skill_table[obj->value[3]].name);
}
cat_sprintf(buf2, "%s\n\r", buf);
break;
case ITEM_WAND:
case ITEM_STAFF:
sprintf(buf, "Has %d of %d charges of level %d",
obj->value[2],
obj->value[1],
obj->value[0]);
if (valid_skill(obj->value[3]))
{
cat_sprintf(buf, " '%s'", skill_table[obj->value[3]].name);
}
cat_sprintf(buf2, "%s\n\r", buf);
break;
case ITEM_WEAPON:
case ITEM_AMMO:
for (cnt = 0 ; cnt < 29 ; cnt++)
{
if (IS_SET(obj->value[1], 1 << cnt))
{
cat_sprintf(buf2, "%s: %s", weapon_flags[cnt], weapon_flag_descs[cnt]);
if (1 << cnt == WFLAG_BANE || 1 << cnt == WFLAG_SLAYING)
{
if (obj->value[3])
{
cat_sprintf(buf2, " %s %s", flag_string(obj->value[3], race_specs), type_string(obj->value[2], rtype_flags));
}
else
{
cat_sprintf(buf2, " %s", type_string(obj->value[2], rtype_flags));
}
}
cat_sprintf(buf2, ".\n\r");
}
}
break;
case ITEM_ARMOR:
cat_sprintf(buf2, "Its armor bonus is %d.\n\r", armor_table[obj->value[0]].ac_bonus );
break;
case ITEM_CONTAINER:
if (IS_SET(obj->value[1], CONT_HOLDING))
{
cat_sprintf(buf2, "Bag of holding: holds %d lbs. for only %s lbs weight.\n\r", obj->value[0]/10, ROUNDUP(obj->value[0]/160));
}
break;
}
for (paf = obj->first_affect ; paf != NULL ; paf = paf->next)
{
switch (paf->location)
{
case APPLY_NONE:
break;
default:
cat_sprintf(buf2, "Affects %s by %d.\n\r", affect_loc_name(paf->location), paf->modifier);
break;
}
switch (paf->bittype)
{
case AFFECT_TO_NONE:
break;
case AFFECT_TO_CHAR:
if (paf->bitvector < 0)
cat_sprintf(buf2, "Affects wearer with %s.\n\r", flag_string(paf->bitvector, a2_flags));
else
cat_sprintf(buf2, "Affects wearer with %s.\n\r", flag_string(paf->bitvector, a_flags));
break;
case AFFECT_TO_OBJ:
cat_sprintf(buf2, "Affects object with %s.\n\r", flag_string(paf->bitvector, o_flags));
break;
}
}
send_to_char_color(buf2, viewer);
pop_call();
return;
}
/*
* Automatic actions for irresistible dance - Kregor 2/10/12
*/
void irresistible_dance(CHAR_DATA * ch)
{
CHAR_DATA *vch = NULL;
push_call("irresistible_dance(%p)",ch);
if (!IS_AWAKE(ch))
{
TAKE_ACTION(ch, ACTION_FULL);
pop_call();
return;
}
// select random dance partner!
for (vch = ch->in_room->first_person ; vch ; vch = vch->next)
{
if (number_bits(1) == 0)
{
break;
}
}
switch (number_range(1,4))
{
case 1:
act("{178}$n skips and prances to the music in $s head.", ch, NULL, NULL, TO_ROOM);
act("{178}You dance and skip to the music in your head.", ch, NULL, NULL, TO_CHAR);
break;
case 2:
if (vch != NULL)
{
act("{178}$n sweeps $N up into a romantic waltz!", ch, NULL, vch, TO_NOTVICT);
act("{178}You sweep $N up into a romantic waltz!", ch, NULL, vch, TO_CHAR);
act("{178}$n sweeps you up into a romantic waltz!", ch, NULL, vch, TO_CHAR);
}
else
{
act("{178}You dance a merry jig!", ch, NULL, NULL, TO_CHAR);
act("{178}$n dances a merry jig!", ch, NULL, NULL, TO_ROOM);
}
break;
case 3:
act("{178}You spin about in a graceful pirouette!", ch, NULL, NULL, TO_CHAR);
act("{178}$n spins about in a graceful pirouette!", ch, NULL, NULL, TO_ROOM);
break;
case 4:
act("{178}You mock a dance of the veils!", ch, NULL, NULL, TO_CHAR);
act("{178}$n mocks a dance of the veils!", ch, NULL, NULL, TO_ROOM);
break;
}
// draw AoO from hostiles
for (vch = ch->in_room->first_person ; vch ; vch = vch->next)
{
if (who_fighting(vch) && who_fighting(vch) == ch)
{
attack_of_opportunity(vch, ch);
}
}
TAKE_ACTION(ch, ACTION_FULL);
pop_call();
return;
}
/*
* Separated recall function from do_ function
* to allow use for many sources - Kregor
*/
bool recall( CHAR_DATA *ch, int vnum )
{
ROOM_INDEX_DATA *old_room;
CHAR_DATA *rch, *rch_next;
if (IS_NPC(ch))
{
pop_call();
return FALSE;
}
if (!is_room_good_for_teleport(ch, ch->in_room->vnum)
|| !is_room_good_for_teleport(ch, vnum))
{
act("You cannot reach that destination.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
old_room = ch->in_room;
if (ch->in_room->vnum == vnum)
{
send_to_char("You are already in your recall spot.\n\r", ch);
pop_call();
return FALSE;
}
act( "You pray for refuge!", ch, NULL, NULL, TO_CHAR );
act( "$n prays for refuge!", ch, NULL, NULL, TO_ROOM );
if (in_combat(ch))
{
int lose = 99 + ch->level * ch->level * 10;
gain_exp(ch, 0 - lose);
ch_printf_color( ch, "{138}You recall from combat! You lose %d experience points.\n\r", lose );
}
act( "$n disappears.", ch, NULL, NULL, TO_ROOM);
if (in_combat(ch))
withdraw_combat(ch);
char_to_room(ch, vnum, TRUE);
act( "$n appears in the room.", ch, NULL, NULL, TO_ROOM );
do_look(ch, "auto");
/*
Pets recall with char Chaos 12/6/93
*/
for (rch = old_room->first_person ; rch ; rch = rch_next)
{
rch_next = rch->next_in_room;
if (is_master(rch, ch))
{
act( "$n disappears.", rch, NULL, NULL, TO_ROOM);
char_to_room(rch, vnum, TRUE);
act( "$n appears in the room.", rch, NULL, NULL, TO_ROOM);
}
}
if (!IS_NPC(ch))
{
mprog_greet_trigger(ch);
oprog_greet_trigger(ch);
rprog_greet_trigger(ch);
}
pop_call();
return TRUE;
}
/*
* Consolidated support function
* for all shapechanging functions - Kregor 11/15/10
*/
bool morph( CHAR_DATA *ch, CHAR_DATA *victim, int race, int sn, int level )
{
OBJ_DATA *obj;
AFFECT_DATA af;
int duration = -1;
push_call("morph(%p,%p,%p,%p)",ch,victim,race,level);
if (!is_string(race_table[race].race_name))
{
bug("morph: invalid race no.",0);
pop_call();
return FALSE;
}
if (IS_SET(race_table[victim->race].flags, RSPEC_INCORPOREAL))
{
act("Incorporeal beings cannot be shapechanged.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
revert_morph(ch, FALSE);
if (sn != gsn_baleful_polymorph)
duration = turn * level;
else
duration = -1;
af.type = sn;
af.duration = duration;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.level = level;
af.location = APPLY_STR;
af.modifier = UMIN(race_table[race].race_mod[0] - race_table[victim->race].race_mod[0], level);
affect_to_char( ch, victim, &af);
af.location = APPLY_DEX;
af.modifier = UMIN(race_table[race].race_mod[1] - race_table[victim->race].race_mod[1], level);
affect_to_char( ch, victim, &af);
af.location = APPLY_CON;
af.modifier = UMIN(race_table[race].race_mod[2] - race_table[victim->race].race_mod[2], level);
affect_to_char( ch, victim, &af);
af.location = APPLY_RACE;
af.modifier = race - victim->race;
affect_to_char( ch, victim, &af);
af.location = APPLY_DISGUISE;
af.modifier = level <= 7 ? 10 : level <= 13 ? 15 : 20;
affect_to_char( ch, victim, &af);
// equip melds and is nonfunctional unless
// the form is the same type as the original.
// inverting wear locs to be restored later - Kregor
if (race_table[race].body_type != race_table[victim->race].body_type)
{
int iWear;
for (obj = victim->first_carrying ; obj ; obj = obj->next_content)
{
if (IS_WORN(obj))
{
iWear = obj->wear_loc;
unequip_char(ch, obj, FALSE);
obj->wear_loc = 0 - iWear;
}
}
}
char_reset(victim);
if (!IS_NPC(victim))
{
victim->pcdata->disguise_roll = dice(1,20);
}
if (ch == victim && arcane_mastery(ch, SCHOOL_TRANSMUTATION))
{
ch->hit = get_max_hit(ch);
}
act( "You slowly start to change into $t $T.", victim, a_an(race_table[get_race(victim)].race_name), race_table[get_race(victim)].race_name, TO_CHAR);
act( "$n slowly starts to change into $t $T.", victim, a_an(race_table[get_race(victim)].race_name), race_table[get_race(victim)].race_name, TO_ROOM);
pop_call();
return TRUE;
}
bool revert_morph( CHAR_DATA *ch, bool fDisplay )
{
OBJ_DATA *obj;
AFFECT_DATA *paf, *paf_next;
int paf_type, old_race;
push_call("morph(%p,%p)",ch,fDisplay);
if (!ch->apply[APPLY_RACE])
{
if (fDisplay)
act("You are in your original form already.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
old_race = get_race(ch);
for ( paf_type = 0, paf = ch->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (!IS_SET(skill_table[paf->type].spell_desc, SDESC_POLYMORPH) && paf->location != APPLY_RACE)
continue;
//can't willingly revert from baleful poly - Kregor
if (fDisplay && skill_table[paf->type].target == TAR_CHAR_OFFENSIVE)
continue;
paf_type = paf->type;
affect_strip(ch, paf_type);
}
if (!paf_type)
{
if (fDisplay)
act("You remain in your previous form.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
// equip added after a shapechange falls off unless same race type - Kregor
if (race_table[old_race].type != race_table[ch->race].type || race_table[old_race].type != RTYPE_HUMANOID)
{
for (obj = ch->first_carrying ; obj ; obj = obj->next_content)
{
if (IS_WORN(obj))
{
unequip_char(ch, obj, FALSE);
}
if (obj->wear_loc < WEAR_NONE)
{
equip_char(ch, obj, 0 - obj->wear_loc);
}
}
}
char_reset(ch);
if (!IS_NPC(ch))
{
ch->pcdata->disguise_roll = 0;
}
if (arcane_mastery(ch, SCHOOL_TRANSMUTATION))
{
ch->hit = get_max_hit(ch);
}
if (fDisplay)
{
act( "You slowly start to change into $t $T.", ch, a_an(race_table[get_race(ch)].race_name), race_table[get_race(ch)].race_name, TO_CHAR);
act( "$n slowly starts to change into $t $T.", ch, a_an(race_table[get_race(ch)].race_name), race_table[get_race(ch)].race_name, TO_ROOM);
}
pop_call();
return TRUE;
}
void do_revert( CHAR_DATA *ch, char *argument )
{
push_call("do_revert(%p,%p)",ch,argument);
if (!ch->apply[APPLY_RACE])
{
act("You are in your original form already.", ch, NULL, NULL, TO_CHAR);
pop_call();
return;
}
revert_morph(ch, TRUE);
TAKE_ACTION(ch, ACTION_STANDARD);
pop_call();
return;
}
/*
Bardic Songs
*/
DO_SONG(song_song_of_inspiration)
{
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int hitbonus, skillbonus, acbonus, diceroll, hpbonus;
push_call("song_song_of_inspiration(%p,%p,%p,%p)",sn,level,ch,vo);
diceroll = perform_roll(ch);
hitbonus = (level / 5) + 1;
skillbonus = level / 5;
acbonus = level / 10;
hpbonus = level / 10;
for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!is_same_group(ch, vch))
continue;
af.type = sn;
af.duration = 5 + level/5;
if (learned(ch, gsn_extend_song))
af.duration *= 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_MOR_TOHIT;
af.modifier = hitbonus;
affect_join( ch, vch, &af );
af.location = APPLY_MOR_DAMG;
af.modifier = hitbonus;
affect_join( ch, vch, &af );
af.location = APPLY_MOR_WILL;
af.modifier = hitbonus;
affect_join( ch, vch, &af );
if (diceroll >= 5)
{
af.location = APPLY_MOR_REFL;
af.modifier = hitbonus;
affect_join( ch, vch, &af );
}
if (diceroll >= 10)
{
af.location = APPLY_MOR_FORT;
af.modifier = hitbonus;
affect_join( ch, vch, &af );
}
if (skillbonus && diceroll >= 15)
{
af.location = APPLY_MOR_SKILL;
af.modifier = skillbonus;
affect_join( ch, vch, &af );
}
if (acbonus && diceroll >= 20)
{
af.location = APPLY_DODGE;
af.modifier = acbonus;
affect_join( ch, vch, &af );
}
if (level > 15 && diceroll >= 25)
{
af.location = APPLY_HIT;
af.modifier = dice(hpbonus, class_table[vch->class].hp_max);
affect_join( ch, vch, &af );
}
act( "{138}You are inspired by the song.", vch, NULL, NULL, TO_CHAR );
}
pop_call();
return TRUE;
}
DO_SONG(song_curse_song)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int hitbonus, skillbonus, acbonus, diceroll;
push_call("song_curse_song(%p,%p,%p,%p)",sn,level,ch,vo);
hitbonus = (level / 5) + 1;
skillbonus = level / 5;
acbonus = level / 10;
diceroll = perform_roll(ch);
for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!is_same_group(victim, vch))
continue;
if (is_affected(vch, gsn_bardic_song))
continue;
af.type = sn;
af.duration = 5 + (level / 5);
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_CURSE;
af.level = level;
af.location = APPLY_MOR_TOHIT;
af.modifier = 0-hitbonus;
affect_to_char( ch, vch, &af );
af.location = APPLY_MOR_DAMG;
af.modifier = 0-hitbonus;
affect_to_char( ch, vch, &af );
af.location = APPLY_MOR_WILL;
af.modifier = 0-hitbonus;
affect_to_char( ch, vch, &af );
if (diceroll >= 5)
{
af.location = APPLY_MOR_REFL;
af.modifier = 0-hitbonus;
affect_to_char( ch, vch, &af );
}
if (diceroll >= 10)
{
af.location = APPLY_MOR_FORT;
af.modifier = 0-hitbonus;
affect_to_char( ch, vch, &af );
}
if (skillbonus && diceroll >= 15)
{
af.location = APPLY_MOR_SKILL;
af.modifier = 0-skillbonus;
affect_to_char( ch, vch, &af );
}
if (skillbonus && diceroll >= 20)
{
af.location = APPLY_DODGE;
af.modifier = 0-acbonus;
affect_to_char( ch, vch, &af );
}
send_to_char_color( "{108}You feel crushed by sorrow.\n\r", victim );
}
pop_call();
return TRUE;
}
DO_SONG(song_song_of_courage)
{
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int diceroll;
push_call("song_song_of_courage(%p,%p,%p,%p)",sn,level,ch,vo);
diceroll = perform_roll(ch);
for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!is_same_group(ch, vch))
continue;
af.type = sn;
af.duration = 5 + level/5;
if (learned(ch, gsn_extend_song))
af.duration *= 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_SAVE_FEAR;
af.modifier = 1;
affect_join( ch, vch, &af );
af.location = APPLY_SAVE_CHARM;
af.modifier = diceroll / 5;
affect_join( ch, vch, &af );
act( "{138}You are filled with courage.", vch, NULL, NULL, TO_CHAR );
}
pop_call();
return TRUE;
}
DO_SONG(song_song_of_heroism)
{
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int diceroll;
push_call("song_song_of_heroism(%p,%p,%p,%p)",sn,level,ch,vo);
diceroll = perform_roll(ch);
for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!is_same_group(ch, vch))
continue;
af.type = sn;
af.duration = 5 + level/5;
if (learned(ch, gsn_extend_song))
af.duration *= 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_IMM_FEAR;
af.modifier = 1;
affect_join( ch, vch, &af );
af.location = APPLY_MOR_SAVES;
af.modifier = diceroll / 5;
affect_join( ch, vch, &af );
af.location = APPLY_DODGE;
af.modifier = diceroll / 5;
affect_join( ch, vch, &af );
act( "{138}You are inspired to great heroism.", vch, NULL, NULL, TO_CHAR );
}
pop_call();
return TRUE;
}
DO_SONG(song_dirge_of_doom)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int diceroll;
push_call("song_dirge_of_doom(%p,%p,%p,%p)",sn,level,ch,vo);
diceroll = perform_roll(ch);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!is_same_group(victim, vch))
continue;
if (is_immune(vch, SDESC_MIND))
continue;
if (is_immune(vch, SDESC_FEAR))
continue;
if (will_save(victim, ch, diceroll, sn))
continue;
af.type = sn;
af.duration = 5 + level/5;
if (learned(ch, gsn_extend_song))
af.duration *= 2;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_FEAR;
af.level = level;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
vch->fear_level = UMIN(vch->fear_level + URANGE(1, diceroll/10, 3), 3);
act( "{118}$n's song fills you with fear!", ch, NULL, vch, TO_CHAR );
}
pop_call();
return TRUE;
}
DO_SONG(song_song_of_fascination)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int diceroll;
push_call("song_song_of_fascination(%p,%p,%p,%p)",sn,level,ch,vo);
diceroll = perform_roll(ch);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!is_same_group(victim, vch))
continue;
if (save_resist(ch, vch, sn, level))
continue;
af.type = sn;
af.duration = 5 + level/5;
if (learned(ch, gsn_extend_song))
af.duration *= 2;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_FASCINATED;
af.level = level;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{178}You gaze at $N in fascination.", vch, NULL, ch, TO_CHAR );
}
pop_call();
return TRUE;
}
DO_SONG(song_song_of_freedom)
{
CHAR_DATA *vch, *vch_next;
AFFECT_DATA *paf, *paf_next;
int diceroll, cnt, count;
bool fCursed = FALSE;
int paf_type;
push_call("song_song_of_suggestion(%p,%p,%p,%p)",sn,level,ch,vo);
diceroll = perform_roll(ch);
count = diceroll / 5;
for (cnt = 0, vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (cnt >= count)
break;
if (!is_same_group(ch, vch))
continue;
if (vch == ch)
continue;
fCursed = FALSE;
for (paf_type = -1, paf = vch->first_affect ; paf ; paf = paf_next)
{
paf_next = paf->next;
if (skill_table[paf->type].skilltype == STYPE_CURSE)
{
fCursed = TRUE;
if (diceroll < paf->level)
continue;
if (paf->duration < 0)
continue;
if (skill_table[paf->type].msg_off)
{
act( skill_table[paf->type].msg_off, vch, NULL, NULL, TO_CHAR);
}
if (skill_table[paf->type].msg_off_room)
{
act( skill_table[paf->type].msg_off_room, vch, NULL, NULL, TO_ROOM);
}
paf_type = paf->type;
affect_from_char(vch, paf);
}
}
if (!fCursed)
continue;
cnt++;
if (paf_type == -1)
{
act("Nothing seems to happen.", ch, NULL, NULL, TO_CHAR);
}
}
pop_call();
return TRUE;
}
DO_SONG(song_song_of_soothing)
{
CHAR_DATA *vch, *vch_next;
AFFECT_DATA *paf, *paf_next;
AFFECT_DATA af;
int diceroll;
push_call("song_song_of_soothing(%p,%p,%p,%p)",sn,level,ch,vo);
diceroll = perform_roll(ch);
for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!is_same_group(ch, vch))
continue;
af.type = sn;
af.duration = 5 + level/5;
if (learned(ch, gsn_extend_song))
af.duration *= 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_FAST_HEALING;
af.modifier = diceroll / 5 + 1;
affect_join( ch, vch, &af );
if (diceroll >= 20)
{
for (paf = vch->first_affect ; paf ; paf = paf_next)
{
paf_next = paf->next;
if (IS_SET(paf->bitvector, AFF2_SICKENED) || (diceroll >= 30 && IS_SET(paf->bitvector, AFF2_NAUSEATED)))
{
if (paf->duration < 0)
continue;
if (skill_table[paf->type].msg_off)
{
act( skill_table[paf->type].msg_off, vch, NULL, NULL, TO_CHAR);
}
if (skill_table[paf->type].msg_off_room)
{
act( skill_table[paf->type].msg_off_room, vch, NULL, NULL, TO_ROOM);
}
affect_from_char(vch, paf);
}
}
}
vch->move = UMIN(vch->move + diceroll, get_max_move(vch));
act( "{138}$N's performance soothes your pain and fatigue.", ch, NULL, vch, TO_VICT );
}
pop_call();
return TRUE;
}
DO_SONG(song_song_of_sleep)
{
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int diceroll;
push_call("song_song_of_sleep(%p,%p,%p,%p)",sn,level,ch,vo);
diceroll = perform_roll(ch);
for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (is_same_group(ch, vch))
continue;
if (is_immune(vch, SDESC_SLEEP))
continue;
af.type = sn;
af.duration = 5 + level/5;
if (learned(ch, gsn_extend_song))
af.duration *= 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_SIGHT;
af.modifier = 0 - (diceroll / 5);
affect_join( ch, vch, &af );
af.location = APPLY_LISTEN;
af.modifier = 0 - (diceroll / 5);
affect_join( ch, vch, &af );
af.location = APPLY_SAVING_REFL;
af.modifier = 0 - (diceroll / 5);
affect_join( ch, vch, &af );
af.location = APPLY_SAVE_SLEEP;
af.modifier = 0 - (diceroll / 5);
affect_join( ch, vch, &af );
if (diceroll >= 25)
{
if (vch->level > level)
continue;
if (will_save(vch, ch, diceroll, sn))
continue;
af.type = sn;
af.duration = turn * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_SLEEP;
af.level = level;
affect_to_char( ch, vch, &af );
if (IS_AWAKE(vch))
{
/* Add to make fighting people stop fighting to sleep */
stop_fighting(vch, FALSE);
act( "You feel very sleepy ..... zzzzzz.", vch, NULL, NULL, TO_CHAR );
act( "$n closes $s eyes and drifts to sleep.", vch, NULL, NULL, TO_ROOM );
update_pos(vch, POS_RESTING);
}
}
if (IS_AWAKE(vch))
{
act( "{108}$N's performance makes your eyes feel heavy.", ch, NULL, vch, TO_VICT );
}
}
pop_call();
return TRUE;
}
DO_SONG(song_song_of_suggestion)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int diceroll, cnt, count;
push_call("song_song_of_suggestion(%p,%p,%p,%p)",sn,level,ch,vo);
diceroll = perform_roll(ch);
count = diceroll / 5;
for (cnt = 0, vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!is_same_group(victim, vch))
continue;
if (is_immune(vch, SDESC_MIND))
continue;
if (is_immune(vch, SDESC_CHARM))
continue;
if (IS_AFFECTED(vch, AFF2_CHARMED))
continue;
if (will_save(vch, ch, diceroll, sn))
continue;
if (cnt >= count)
break;
af.type = sn;
af.duration = 5 + level/5;
if (learned(ch, gsn_extend_song))
af.duration *= 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{138}You hang on $n's every word.", ch, NULL, vch, TO_CHAR );
cnt++;
}
pop_call();
return TRUE;
}
/*
Breath Spells
Do not need ForReal flags, because they're instant
*/
DO_SPELL(spell_acid_spittle)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int nodice;
act( "You spit a stream of acidic saliva.", ch, NULL, NULL, TO_CHAR);
act( "$n spits a stream of acidic saliva.", ch, NULL, NULL, TO_ROOM);
push_call("spell_acid_spittle(%p,%p,%p,%p)",sn,level,ch,vo);
nodice = ch->level + 1;
spell_damage(ch, victim, dice(nodice, 4), sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_acid_breath)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
int dam, nodice;
push_call("spell_acid_breath(%p,%p,%p,%p)",sn,level,ch,vo);
nodice = ch->level * 2 / 3;
act( "You breathe a cloud of caustic vapor.", ch, NULL, NULL, TO_CHAR);
act( "$n breathes a cloud of caustic vapor.", ch, NULL, NULL, TO_ROOM);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
dam = dice(nodice, 4);
if (!can_mass_cast(ch, vch, sn))
continue;
if (IS_NPC(ch) && !is_same_group(victim, vch))
continue;
if (refl_save(vch, ch, ch->level, sn))
{
if (can_evade(vch))
{
send_to_char_color( "{138}You quickly evade the acid blast.\n\r", vch );
dam = 0;
}
else
{
dam /= 2;
}
}
else
{
if (learned(vch, gsn_imp_evasion) && can_evade(vch))
{
send_to_char_color( "{138}You evade the brunt of the acid blast.\n\r", vch );
dam /= 2;
}
}
damage( ch, vch, dam, sn, NULL );
if (dam > 0)
{
AFFECT_DATA af;
af.type = sn;
af.duration = 1 + (level/3);
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_join( ch, vch, &af );
act( "{128}Caustic acid begins to eat away at $n.", vch, NULL, NULL, TO_ROOM);
act( "{128}Caustic acid begins to eat away at you!", vch, NULL, NULL, TO_CHAR);
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_fire_breath)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int nodice;
push_call("spell_fire_breath(%p,%p,%p,%p)",sn,level,ch,vo);
act( "A blast of fire spews from your maw.", ch, NULL, NULL, TO_CHAR);
act( "A blast of fire spews from $n's maw.", ch, NULL, NULL, TO_ROOM);
nodice = ch->level / 2;
spell_damage(ch, victim, dice(nodice, 10), sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_frost_breath)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int nodice;
push_call("spell_frost_breath(%p,%p,%p,%p)",sn,level,ch,vo);
act( "A cone of cold blasts from your maw.", ch, NULL, NULL, TO_CHAR);
act( "A cone of cold blasts from $n's maw.", ch, NULL, NULL, TO_ROOM);
nodice = ch->level / 3;
spell_damage(ch, victim, dice(nodice, 6), sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_gas_breath)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
int dam, nodice;
push_call("spell_gas_breath(%p,%p,%p,%p)",sn,level,ch,vo);
nodice = ch->level / 2;
act( "You breathe a cloud of noxious fumes.", ch, NULL, NULL, TO_CHAR);
act( "$n breathes a cloud of noxious fumes.", ch, NULL, NULL, TO_ROOM);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
dam = dice(nodice, 6);
if (!can_mass_cast(ch, vch, sn))
continue;
if (IS_NPC(ch) && !is_same_group(victim, vch))
continue;
if (refl_save(vch, ch, ch->level, sn))
{
if (can_evade(vch))
{
send_to_char_color( "{138}You quickly evade the cloud of gas.\n\r", vch );
dam = 0;
}
else
{
dam /= 2;
}
}
else
{
if (learned(vch, gsn_imp_evasion) && can_evade(vch))
{
send_to_char_color( "{138}You evade the brunt of the gas.\n\r", vch );
dam /= 2;
}
else
{
if (!fort_save(victim, ch, ch->level, sn))
{
AFFECT_DATA af;
af.type = gsn_poison;
af.location = APPLY_NONE;
af.modifier = 0;
af.duration = nodice;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_POISON;
af.level = level;
affect_join( ch, vch, &af );
send_to_char( "You choke and gag in the cloud of poison gas.\n\r", vch );
act( "$n chokes and gags in the cloud of poison gas.\n\r", vch, NULL, NULL, TO_ROOM );
}
}
}
damage( ch, vch, dam, sn, NULL );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_lightning_breath)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int nodice;
push_call("spell_lightning_breath(%p,%p,%p,%p)",sn,level,ch,vo);
act( "Bolts of lightning streak from your maw.", ch, NULL, NULL, TO_CHAR);
act( "Bolts of lightning streak from $n's maw.", ch, NULL, NULL, TO_ROOM);
nodice = ch->level / 3;
spell_damage(ch, victim, dice(nodice, 8), sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_psionic_shockwave)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_psionic_shockwave(%p,%p,%p,%p)",sn,level,ch,vo);
dam = dice(level, 10);
spell_damage(ch, victim, dam, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_sonic_blast)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int nodice;
push_call("spell_sonic_blast(%p,%p,%p,%p)",sn,level,ch,vo);
nodice = ch->level / 3;
act( "A shrill blast emits from you.", ch, NULL, NULL, TO_CHAR);
act( "A shrill blast emits from $n.", ch, NULL, NULL, TO_ROOM);
spell_damage(ch, victim, dice(nodice, 8), sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_weakness_gas)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int nodice;
push_call("spell_weakness_gas(%p,%p,%p,%p)",sn,level,ch,vo);
nodice = ch->level / 4;
act( "A cloud of gas plumes from your nostrils.", ch, NULL, NULL, TO_CHAR);
act( "A cloud of gas plumes from $n's nostrils.", ch, NULL, NULL, TO_ROOM);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if (IS_NPC(ch) && !is_same_group(victim, vch))
continue;
if (save_resist(ch, vch, sn, level))
continue;
af.type = sn;
af.location = APPLY_STR;
af.modifier = 0-nodice;
af.duration = dice(1, level/4);
af.bittype = AFF_NONE;
af.bitvector = AFF_NONE;
af.level = level;
affect_to_char( ch, vch, &af );
send_to_char_color( "{118}You feel the gas sapping your strength.\n\r", vch );
act( "$n {118}'s strength saps away in the gas.", vch, NULL, NULL, TO_ROOM);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_paralysis_gas)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
push_call("spell_paralysis_gas(%p,%p,%p,%p)",sn,level,ch,vo);
act( "A cloud of gas plumes from your nostrils.", ch, NULL, NULL, TO_CHAR);
act( "A cloud of gas plumes from $n's nostrils.", ch, NULL, NULL, TO_ROOM);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if (IS_NPC(ch) && !is_same_group(victim, vch))
continue;
if (save_resist(ch, vch, sn, level))
continue;
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
af.duration = dice(1, level/4);
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_PARALYSIS;
af.level = level;
affect_to_char( ch, vch, &af );
send_to_char_color( "{118}The cloud of gas leaves you helpless!\n\r", vch );
act( "$n {118}is helpless in a cloud of gas!", vch, NULL, NULL, TO_ROOM);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_fear_gas)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
push_call("spell_fear_gas(%p,%p,%p,%p)",sn,level,ch,vo);
act( "A cloud of gas plumes from your nostrils.", ch, NULL, NULL, TO_CHAR);
act( "A cloud of gas plumes from $n's nostrils.", ch, NULL, NULL, TO_ROOM);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if (IS_NPC(ch) && !is_same_group(victim, vch))
continue;
if (save_resist(ch, vch, sn, level))
continue;
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
af.duration = dice(1, level/4);
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_FEAR;
af.level = level;
affect_to_char( ch, vch, &af );
vch->fear_level += UMIN(vch->fear_level + 2, 3);
if (IS_NPC(vch))
{
if (!IS_SET(vch->act, ACT_WIMPY))
SET_BIT(vch->act, ACT_WIMPY);
}
send_to_char_color( "{118}You try to run away from your attacker!\n\r", vch );
act( "$n {118}tries to run away from $s attacker!", vch, NULL, NULL, TO_ROOM);
do_withdraw(ch, NULL);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_slow_gas)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
push_call("spell_slow_gas(%p,%p,%p,%p)",sn,level,ch,vo);
act( "A cloud of gas plumes from your nostrils.", ch, NULL, NULL, TO_CHAR);
act( "A cloud of gas plumes from $n's nostrils.", ch, NULL, NULL, TO_ROOM);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if (IS_NPC(ch) && !is_same_group(victim, vch))
continue;
if (save_resist(ch, vch, sn, level))
continue;
if (is_affected(vch, gsn_haste))
{
affect_strip(vch, gsn_haste);
continue;
}
af.type = gsn_slow;
af.duration = level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_STAGGERED;
af.level = level;
affect_join( ch, vch, &af);
af.location = APPLY_DODGE;
af.modifier = -1;
affect_join( ch, vch, &af);
af.location = APPLY_SAVING_REFL;
af.modifier = -1;
affect_join( ch, vch, &af);
af.location = APPLY_COMP_TOHIT;
af.modifier = -1;
affect_join( ch, vch, &af);
send_to_char_color( "{118}The cloud of gas slows you down!\n\r", vch );
act( "$n {118}is slowed in the cloud of gas!", vch, NULL, NULL, TO_ROOM);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_euphoria_gas)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
push_call("spell_euphoria_gas(%p,%p,%p,%p)",sn,level,ch,vo);
act( "{158}A cloud of gas plumes from your nostrils.", ch, NULL, NULL, TO_CHAR);
act( "{158}A cloud of gas plumes from $n's nostrils.", ch, NULL, NULL, TO_ROOM);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if (save_resist(ch, vch, sn, level))
continue;
af.type = sn;
af.duration = level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_STAGGERED;
af.level = level;
affect_join( ch, vch, &af);
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_SICKENED;
affect_join( ch, vch, &af);
af.location = APPLY_IMM_FEAR;
af.modifier = 1;
affect_join( ch, vch, &af);
send_to_char_color( "{158}OOoooh! Pretty colors....\n\r", vch );
act( "$n {158}suddenly seems light headed and giddy.", vch, NULL, NULL, TO_ROOM);
}
pop_call();
return TRUE;
}
/*
* Spell functions for current spells
*/
/*
* All standard affecting spells should go thru this function
* uses target mode of spell to determine whether save or resistance applies.
*/
DO_SPELL(spell_affect)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int cnt, save;
bool area = FALSE;
push_call("spell_affect(%p,%p,%p,%p)",sn,level,ch,vo);
if (is_affected(victim, gsn_time_stop))
{
act("You cannot affect $n.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (IS_AREA_SPELL(sn))
area = TRUE;
for (cnt = 0, vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (is_affected(vch, gsn_time_stop))
{
act("You cannot affect $n.", ch, NULL, vch, TO_CHAR);
break;
}
if (!area && vch != victim)
continue;
if (cnt && cnt >= level)
break;
if (IS_OFFENSIVE(vch, sn))
{
if (area && IS_NPC(ch) && !is_same_group(victim, vch))
continue;
}
else if (sn != gsn_prayer)
{
if (area && !is_same_group(victim, vch))
continue;
}
if ((save = save_resist(ch, vch, sn, level)) == TRUE)
continue;
af.type = sn;
af.level = level;
if (sn == gsn_foresight)
{
af.duration = turn * 2 * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_INS_AC;
af.modifier = 2;
affect_join( ch, vch, &af);
af.location = APPLY_INS_REFL;
af.modifier = 2;
affect_join( ch, vch, &af);
act( "{138}You feel keenly aware to the dangers around you.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n grows keenly aware of $s surroundings.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_good_hope)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_MOR_TOHIT;
af.modifier = 2;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_DAMG;
af.modifier = 2;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_SAVES;
af.modifier = 2;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_SKILL;
af.modifier = 2;
affect_join( ch, vch, &af);
act( "{138}You feel a rush of confidence and hope.", vch, NULL, NULL, TO_CHAR);
}
if (sn == gsn_crushing_despair)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_MOR_TOHIT;
af.modifier = -2;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_DAMG;
af.modifier = -2;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_SAVES;
af.modifier = -2;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_SKILL;
af.modifier = -2;
affect_join( ch, vch, &af);
act( "{108}You feel weighted with despair.", vch, NULL, NULL, TO_CHAR);
}
if (sn == gsn_prayer)
{
if (is_same_group(vch, victim))
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_LUCK_TOHIT;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_LUCK_SAVES;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_LUCK_DAMG;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_LUCK_SKILL;
af.modifier = 1;
affect_join( ch, vch, &af);
act( "{138}Divine favor fills you.", vch, NULL, NULL, TO_CHAR);
act( "{138}Divine favor fills $n.", vch, NULL, NULL, TO_ROOM);
}
else
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_LUCK_TOHIT;
af.modifier = -1;
affect_join( ch, vch, &af);
af.location = APPLY_LUCK_SAVES;
af.modifier = -1;
affect_join( ch, vch, &af);
af.location = APPLY_LUCK_DAMG;
af.modifier = -1;
affect_join( ch, vch, &af);
af.location = APPLY_LUCK_SKILL;
af.modifier = -1;
affect_join( ch, vch, &af);
act( "{108}You feel divine wrath upon you!", vch, NULL, NULL, TO_CHAR);
}
}
if (sn == gsn_aid)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_MOR_TOHIT;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_WILL;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_HIT;
af.modifier = spell_dice(ch, sn, 1, 8) + UMIN(level, 10);
affect_join( ch, vch, &af);
act( "{138}Your spirits feel lifted.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n's spirits seem lifted.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_bless)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.location = APPLY_MOR_TOHIT;
af.modifier = 1;
affect_join( ch, vch, &af );
af.location = APPLY_SAVE_FEAR;
af.modifier = 1;
affect_join( ch, vch, &af );
act( "{138}A divine blessing is laid upon $n.", vch, NULL, NULL, TO_ROOM );
act( "{138}A divine blessing is laid upon you.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_bane)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.location = APPLY_MOR_TOHIT;
af.modifier = -1;
affect_join( ch, vch, &af );
af.location = APPLY_SAVE_FEAR;
af.modifier = -1;
affect_join( ch, vch, &af );
act( "{138}A divine banality is laid upon $n.", vch, NULL, NULL, TO_ROOM );
act( "{138}A divine banality is laid upon you.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_symbol_of_pain)
{
if (!cnt)
{
act("{138}A bright, glowing rune radiates around $n.", ch, NULL, NULL, TO_ROOM);
act("{138}A bright, glowing rune radiates around you.", ch, NULL, NULL, TO_ROOM);
}
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.location = APPLY_MOR_TOHIT;
af.modifier = -4;
affect_join( ch, vch, &af );
af.location = APPLY_MOR_SKILL;
af.modifier = -4;
affect_join( ch, vch, &af );
act( "{118}$n cringes in pain!.", vch, NULL, NULL, TO_ROOM );
act( "{118}You are wracked with pain as you glimpse the symbol!", vch, NULL, NULL, TO_CHAR );
cnt++;
}
if (sn == gsn_blindness)
{
af.duration = -1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_BLIND;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{108}You blink, and cannot see a thing!", vch, NULL, NULL, TO_CHAR );
act( "{108}$n blinks, and cannot see!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_silence)
{
af.duration = level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_SILENCE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{108}You open your mouth, and nothing comes out!", vch, NULL, NULL, TO_CHAR );
act( "{108}$n can't make a sound.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_web)
{
af.duration = turn*level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_ENTANGLED;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{108}You are covered in sticky webs!", vch, NULL, NULL, TO_CHAR );
act( "{108}$n is covered in sticky webs!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_daze)
{
af.duration = 2;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_DAZED;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{300}You think to yourself, {200}'What was I doing again?'", vch, NULL, NULL, TO_CHAR );
act( "{178}$n stands in a daze.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_festering_wounds)
{
if (vch->hit >= get_max_hit(vch))
{
act("There are no wounds on $N to fester", ch, NULL, vch, TO_CHAR);
continue;
}
af.duration = save == PARTIAL ? 1 : -1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_CURSE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{118}Your skin erupts into festers!", vch, NULL, NULL, TO_CHAR );
act( "{118}$n's skin erupts into festers!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_bleeding_wounds)
{
if (vch->hit >= get_max_hit(vch))
{
act("There are no wounds on $N to bleed", ch, NULL, vch, TO_CHAR);
continue;
}
af.duration = -1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_BLEEDING;
af.location = APPLY_NONE;
af.modifier = UMAX(1, ROUNDUP(4 - vch->hit * 4 / get_max_hit(vch)));
affect_join( ch, vch, &af );
act( "{118}Your wounds bleed copiously!", vch, NULL, NULL, TO_CHAR );
act( "{118}$n's wounds bleed copiously!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_drown)
{
if (!must_breathe(vch))
{
act("$N does not have to breathe.", ch, NULL, vch, TO_CHAR);
continue;
}
af.duration = -1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_DROWNING;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{168}Your lungs fill with water!", vch, NULL, NULL, TO_CHAR );
act( "{118}$n starts to gasp for air!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_irresistible_dance)
{
if (!IS_AWAKE(vch))
{
act("$N is in no condition for dancing.", ch, NULL, vch, TO_CHAR);
continue;
}
if (is_mounting(vch))
do_dismount(vch, "");
else
do_stand(vch, "");
af.duration = save == PARTIAL ? 1 : dice(1,4) + 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.location = APPLY_SAVING_REFL;
af.modifier = -10;
affect_join( ch, vch, &af );
af.location = APPLY_DODGE;
af.modifier = -4;
affect_join( ch, vch, &af );
act( "{138}$n begins to shuffle $s feet.", vch, NULL, NULL, TO_ROOM );
act( "{138}You start to dance uncontrollably.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_comprehend_languages)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_UNDERSTAND;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{178}You start understanding everyone.", vch, NULL, NULL, TO_CHAR);
act( "{178}$n's face brightens with understanding.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_darkvision)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_DARKVISION;
af.modifier = 60;
affect_join( ch, vch, &af );
act( "{108}Your eyes adjust to see clearly in the darkness.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_disguise_self)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_DISGUISE;
af.modifier = 10;
affect_join( ch, vch, &af );
act( "{108}Your gain an illusory enhancement to your disguise.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_delay_poison)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_IMM_POISON;
af.modifier = 1;
affect_join( ch, vch, &af );
act( "{128}You feel a ward against poison fill your body.", vch, NULL, NULL, TO_CHAR );
if ( ch != vch )
act( "{128}$N is filled with a ward against poisons.", ch, NULL, vch, TO_CHAR );
}
if (sn == gsn_detect_invis)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_DETECT_INVIS;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{178}Your eyes fixate as they gain the ability to see the unseen.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_detect_magic)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{148}Traces of blue radiate from things magical.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_detect_secret)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_DETECT_HIDDEN;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{148}Traces of blue radiate from things magical.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_detect_traps)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_DETECT_TRAPS;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{178}Your senses are heightened to detect traps.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_detect_thoughts)
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{068}Random thoughts in your vicinity trickle into your mind.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_bestow_grace)
{
if (IS_GOOD(vch))
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{138}You radiate with divine grace!", vch, NULL, NULL, TO_CHAR );
act( "{138}$n radiates with divine grace!", vch, NULL, NULL, TO_ROOM );
}
}
if (sn == gsn_repel_metal)
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "Metal begins to repel away from you!", vch, NULL, NULL, TO_CHAR );
act( "Metal begins to repel away from $n!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_entropic_shield)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{158}A c{118}ha{038}ot{138}ic {128}fi{168}el{148}d o{058}f m{158}ul{118}ti{038}co{138}lo{128}re{168}d h{148}ue{058}s {158}surrounds $n.", vch, NULL, NULL, TO_ROOM );
act( "{158}A c{118}ha{038}ot{138}ic {128}fi{168}el{148}d o{058}f m{158}ul{118}ti{038}co{138}lo{128}re{168}d h{148}ue{058}s {158}surrounds you.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_flesh_to_stone)
{
af.duration = -1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_PETRIFICATION;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{108}You quickly freeze in your tracks!", vch, NULL, NULL, TO_CHAR );
act( "{108}$n turns into a stone statue!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_astral_projection)
{
af.duration = hr * (domain_apotheosis(ch, DOMAIN_TRAVEL) ? level * 2 : level);
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_ASTRAL;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "$n steps outside of $s body.", vch, NULL, NULL, TO_ROOM );
act( "You step outside your body.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_ethereal)
{
af.duration = turn * (domain_apotheosis(ch, DOMAIN_TRAVEL) ? level * 2 : level);
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_ETHEREAL;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "$n partially fades out.", vch, NULL, NULL, TO_ROOM );
act( "You become ethereal.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_empty_body)
{
af.duration = level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_ETHEREAL;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "$n partially fades out.", vch, NULL, NULL, TO_ROOM );
act( "You become ethereal.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_hallucinate)
{
if (IS_AFFECTED(vch, AFF_TRUESIGHT))
continue;
af.duration = level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_HALLUCINATE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
af.location = APPLY_SAVING_REFL;
af.modifier = -2;
affect_join( ch, vch, &af);
af.location = APPLY_SIGHT;
af.modifier = -2;
affect_join( ch, vch, &af);
act( "Things don't appear to be the way they were...", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_mind_blank)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_MIND_BLANK;
af.location = APPLY_SAVE_MIND;
af.modifier = 8;
affect_join( ch, vch, &af );
act( "{138}Your mind withdraws from detection.", vch, NULL, NULL, TO_CHAR );
if ( ch != vch )
act( "{138}$N's mind withdraws from detection.", ch, NULL, vch, TO_CHAR );
}
if (sn == gsn_mirror_image)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = UMIN(spell_dice(ch, sn, 1,4) + (level/3), 8);
affect_join( ch, vch, &af );
act( "{168}Several images of you step out and away from you.", vch, NULL, NULL, TO_CHAR );
act ("{168}Several images of $n step out and away from $m.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_haste)
{
if (is_affected(vch, gsn_slow))
{
affect_strip(vch, gsn_slow);
continue;
}
af.duration = level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_HASTE;
af.location = APPLY_DODGE;
af.modifier = 1;
affect_join( ch, vch, &af );
af.location = APPLY_SAVING_REFL;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_COMP_TOHIT;
af.modifier = 1;
affect_join( ch, vch, &af);
act( "{138}You speed up.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n speeds up.", vch, NULL, NULL, TO_ROOM);
cnt++;
}
if (sn == gsn_freedom_of_movement)
{
af.duration = 5 * turn * level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_FREEDOM;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{138}You are free from any restraints.", vch, NULL, NULL, TO_CHAR );
act( "{138}$N moves about freely.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_vigilance)
{
af.duration = hr;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_LISTEN;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_SIGHT;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_SENSE_MOT;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_SAVE_SLEEP;
af.modifier = 1;
affect_join( ch, vch, &af);
act( "{138}Your alertness sharpens.", vch, NULL, NULL, TO_CHAR);
cnt++;
}
if (sn == gsn_nondetection)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_NONDETECTION;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{138}You are warded against divination.", vch, NULL, NULL, TO_CHAR );
if ( ch != vch )
act( "{138}$N is warded against divination.", ch, NULL, vch, TO_CHAR );
}
if (sn == gsn_pass_door)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_GASEOUS;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
af.location = APPLY_DR_MAGIC;
af.modifier = 10;
affect_join( ch, vch, &af );
af.location = APPLY_FORTIFICATION;
af.modifier = 100;
affect_join( ch, vch, &af );
act( "{108}$n's form turns translucent.", vch, NULL, NULL, TO_ROOM );
act( "{108}$Your form turns translucent.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_pass_without_trace)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{138}$n suddenly leaves no trail of $s passing.", vch, NULL, NULL, TO_ROOM );
act( "{138}You suddenly leave to trail of your passing.", vch, NULL, NULL, TO_CHAR );
cnt++;
}
if (sn == gsn_read_magic)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
send_to_char_color( "{138}Your mind now comprehends arcane writings.\n\r", vch );
}
if (sn == gsn_guidance)
{
af.duration = turn;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.location = APPLY_COMP_SKILL;
af.modifier = 1;
affect_join( ch, vch, &af );
act( "{138}You are touched with divine guidance.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n is touched with divine guidance.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_sanctuary)
{
af.duration = level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_SANCTUARY;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{178}$n is surrounded by a white aura.", vch, NULL, NULL, TO_ROOM );
act( "{178}You are surrounded by a white aura.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_spell_immunity)
{
af.duration = level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_IMMUNE_SPELL;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "{138}A powerful antimagic ward surrounds $n", vch, NULL, NULL, TO_ROOM );
act( "{138}A powerful antimagic aura surrounds you!", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_shield)
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_SHIELD;
af.modifier = 4;
affect_join( ch, vch, &af );
act( "{178}A hovering shield of force forms in front of $n.", vch, NULL, NULL, TO_ROOM );
act( "{178}A hovering shield of force forms in front of you.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_spell_turning)
{
af.duration = 5 * turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = spell_dice(ch,sn,1,4) + 6;
affect_join( ch, vch, &af );
act( "A shield of reflective magic coalesces around $n.", vch, NULL, NULL, TO_ROOM );
act( "A shield of reflective magic coalesces around you.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_status)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af );
act( "You attune your mind to your comrades.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_stone_skin)
{
af.duration = 2 * turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_DR_ADAMANTINE;
af.modifier = 10;
affect_join( ch, vch, &af );
vch->absorption[af.location] = UMIN(10 * level, 150);
act( "{108}$n's skin turns to malleable stone.", vch, NULL, NULL, TO_ROOM );
act( "{108}Your skin turns to malleable stone.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_iron_body)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_DR_ADAMANTINE;
af.modifier = 15;
affect_join( ch, vch, &af );
af.location = APPLY_IMM_DISEASE;
af.modifier = 1;
affect_join( ch, vch, &af );
af.location = APPLY_IMM_POISON;
af.modifier = 1;
affect_join( ch, vch, &af );
af.location = APPLY_FORTIFICATION;
af.modifier = 100;
affect_join( ch, vch, &af );
af.location = APPLY_STR;
af.modifier = 6;
affect_join( ch, vch, &af );
act( "{108}$n's body turns into living iron!", vch, NULL, NULL, TO_ROOM );
act( "{108}Your body turns into living iron!", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_identify)
{
af.duration = 3*level;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_to_char( ch, vch, &af );
send_to_char_color( "{148}Your perception of magical properties grows keen.\n\r", vch );
}
if (sn == gsn_clairvoyance)
{
af.duration = level;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_to_char( ch, vch, &af );
send_to_char_color( "{138}Your eyes focus upon a distance.\n\r", vch );
}
if (sn == gsn_ray_of_enfeeblement)
{
af.duration = level * turn;
af.location = APPLY_STR;
af.modifier = 0 - (spell_dice(ch, sn, 1,6) + UMIN(level/2, 5));
if (save == -1)
af.modifier /= 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af );
act( "Your strength flows out of your body.", vch, NULL, NULL, TO_CHAR );
act( "$n suddenly seems much weaker.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_touch_of_idiocy)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.location = APPLY_INT;
af.modifier = 0 - spell_dice(ch, sn, 1, 6);
affect_join( ch, vch, &af);
af.location = APPLY_WIS;
af.modifier = 0 - spell_dice(ch, sn, 1, 6);
affect_join( ch, vch, &af);
af.location = APPLY_CHA;
af.modifier = 0 - spell_dice(ch, sn, 1, 6);
affect_join( ch, vch, &af);
act( "$s seems to grow a bit duller.", vch, NULL, NULL, TO_ROOM );
act( "Your mind no longer feels very sharp.", vch, NULL, NULL, TO_CHAR);
}
if (sn == gsn_feeblemind)
{
af.duration = -1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.location = APPLY_INT;
af.modifier = -1 * (vch->perm_int - 1);
affect_join( ch, vch, &af);
af.location = APPLY_CHA;
af.modifier = -1 * (vch->perm_cha - 1);
affect_join( ch, vch, &af);
act( "$s begins to babble incoherently.", vch, NULL, NULL, TO_ROOM );
act( "Your mind clouds and you babble incoherently.", vch, NULL, NULL, TO_CHAR);
}
if (sn == gsn_curse)
{
af.duration = -1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_CURSE;
af.location = APPLY_LUCK_SAVES;
af.modifier = -4;
affect_to_char( ch, vch, &af );
af.location = APPLY_LUCK_TOHIT;
af.modifier = -4;
affect_to_char( ch, vch, &af );
af.location = APPLY_LUCK_SKILL;
af.modifier = -4;
affect_to_char( ch, vch, &af );
act( "{108}A powerful curse befalls $n.", vch, NULL, NULL, TO_ROOM);
act( "{108}A powerful curse befalls you.", vch, NULL, NULL, TO_CHAR);
}
if (sn == gsn_bears_endurance || sn == gsn_mass_bears_endurance)
{
af.location = APPLY_CON;
af.duration = level * 10;
af.modifier = spell_dice(ch, sn, 1, 4) + 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af);
cnt++;
act("{138}You feel the endurance of a bear.", vch, NULL, NULL, TO_CHAR );
act( "$n {138}flexes with renewed endurance.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_bulls_strength || sn == gsn_mass_bulls_strength)
{
af.location = APPLY_STR;
af.duration = level * 10;
af.modifier = spell_dice(ch, sn, 1, 4) + 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af);
cnt++;
send_to_char_color( "{138}You feel the strength of a bull ripple through your muscles.\n\r", vch );
act( "$n {138}flexes with renewed strength.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_animal_growth)
{
if (!IS_ANIMAL(vch))
continue;
af.location = APPLY_SIZE;
af.duration = level * turn;
af.modifier = 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af);
af.location = APPLY_NATURAL_AC;
af.modifier = 2;
affect_join( ch, vch, &af);
cnt++;
send_to_char_color( "{138}You quickly grow to twice your size!\n\r", vch );
act( "{138}$n quickly grows to twice $s size!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_reduce_animal)
{
if (!IS_ANIMAL(vch))
continue;
if (!is_same_group(ch, vch))
{
act("$N is not a willing recipient.", ch, NULL, vch, TO_CHAR);
continue;
}
af.location = APPLY_SIZE;
af.duration = level * hr;
af.modifier = 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af);
send_to_char_color( "{138}You rapidly shrink to half your size!\n\r", vch );
act( "{138}$n rapidly shrinks to half $s size!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_enlarge_person || sn == gsn_mass_enlarge_person)
{
if (!IS_HUMANOID(vch))
continue;
af.location = APPLY_SIZE;
af.duration = level * turn;
af.modifier = 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af);
cnt++;
send_to_char_color( "{138}You quickly grow to twice your size!\n\r", vch );
act( "{138}$n quickly grows to twice $s size!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_reduce_person || sn == gsn_mass_reduce_person)
{
if (!IS_HUMANOID(vch))
continue;
af.location = APPLY_SIZE;
af.duration = level * turn;
af.modifier = 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af);
cnt++;
send_to_char_color( "{138}You rapidly shrink to half your size!\n\r", vch );
act( "{138}$n rapidly shrinks to half $s size!", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_cats_grace || sn == gsn_mass_cats_grace)
{
af.location = APPLY_DEX;
af.duration = level * 10;
af.modifier = spell_dice(ch, sn, 1, 4) + 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af);
cnt++;
send_to_char_color( "{138}You feel agile and flexible as the a cat's grace fills you.\n\r", vch);
act( "$n {138}looks more agile.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_eagles_splendour || sn == gsn_mass_eagles_splendour)
{
af.location = APPLY_CHA;
af.duration = level * 10;
af.modifier = spell_dice(ch, sn, 1, 4) + 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af);
cnt++;
send_to_char_color( "{138}You beam with raidance as an eagle's spendour surrounds you.\n\r", vch);
act( "$n {138}beams with radiance and charisma.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_foxs_cunning || sn == gsn_mass_foxs_cunning)
{
af.location = APPLY_INT;
af.duration = level * 10;
af.modifier = spell_dice(ch, sn, 1, 4) + 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af);
cnt++;
send_to_char_color( "{138}Your eyes shine brightly as a fox's cunning sharpens your mind.\n\r", vch);
act( "$n's {138}eyes shine brightly.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_owls_wisdom || sn == gsn_mass_owls_wisdom)
{
af.location = APPLY_INT;
af.duration = level * 10;
af.modifier = spell_dice(ch, sn, 1, 4) + 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af);
cnt++;
send_to_char_color( "{138}Your eyes shine sagaciously as an owl's wisdom lights your path.\n\r", vch);
act( "$n's {138}eyes shine sagaciously.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_divine_favor)
{
af.duration = turn;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_LUCK_TOHIT;
af.modifier = UMIN(level/3, 3);
affect_join( ch, vch, &af);
af.location = APPLY_LUCK_DAMG;
af.modifier = UMIN(level/3, 3);
affect_join( ch, vch, &af);
act( "{138}You are filled with the favor of your deity.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n is filled with the favor of $s deity.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_divine_power)
{
af.duration = turn;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_LUCK_TOHIT;
af.modifier = UMIN(level/3, 6);
affect_join( ch, vch, &af);
af.location = APPLY_LUCK_DAMG;
af.modifier = UMIN(level/3, 6);
affect_join( ch, vch, &af);
af.location = APPLY_LUCK_SKILL;
af.modifier = UMIN(level/3, 6);
affect_join( ch, vch, &af);
af.location = APPLY_HIT;
af.modifier = level;
affect_join( ch, vch, &af);
act( "{138}You are filled with the power of your deity.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n is filled with the power of $s deity.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_unholy_aura || sn == gsn_shield_of_law || sn == gsn_holy_aura || sn == gsn_cloak_of_chaos)
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_DEFLECT;
af.modifier = 4;
affect_join( ch, vch, &af);
af.location = APPLY_RES_SAVES;
af.modifier = 4;
affect_join( ch, vch, &af);
af.location = APPLY_SAVE_MIND;
af.modifier = 8;
affect_join( ch, vch, &af);
if (sn == gsn_unholy_aura)
af.location = APPLY_SR_GOOD;
else if (sn == gsn_holy_aura)
af.location = APPLY_SR_EVIL;
else if (sn == gsn_cloak_of_chaos)
af.location = APPLY_SR_LAW;
else
af.location = APPLY_SR_CHAOS;
af.modifier = 25;
affect_join( ch, vch, &af);
if (sn == gsn_unholy_aura)
{
af.location = APPLY_TURN_RESIST;
af.modifier = 4;
}
else if (sn == gsn_holy_aura)
{
af.location = APPLY_SAVE_NEGATIVE;
af.modifier = 4;
}
else if (sn == gsn_cloak_of_chaos)
{
af.location = APPLY_CONCEALMENT;
af.modifier = 25;
}
else
{
af.location = APPLY_FORTIFICATION;
af.modifier = 25;
}
affect_join( ch, vch, &af);
if (sn == gsn_cloak_of_chaos)
{
act( "{058}A random pattern of color surrounds you.", vch, NULL, NULL, TO_CHAR);
act( "{058}A random pattern of color surrounds $n.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_unholy_aura)
{
act( "{108}You are shrouded in a malevolent darkness.", vch, NULL, NULL, TO_CHAR);
act( "{108}A malavolent darkness ensrouds $n.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_holy_aura)
{
act( "{178}A brilliant, divine radiance surrounds you.", vch, NULL, NULL, TO_CHAR);
act( "{178}A brilliant, divine radiance surrounds $n.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_shield_of_law)
{
act( "{148}You are covered in a dim, blue aura.", vch, NULL, NULL, TO_CHAR);
act( "{148}A dim blue aura radiates around $n.", vch, NULL, NULL, TO_ROOM);
}
cnt++;
}
if (sn == gsn_transformation)
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_STR;
af.modifier = 4;
affect_join( ch, vch, &af);
af.location = APPLY_DEX;
af.modifier = 4;
affect_join( ch, vch, &af);
af.location = APPLY_CON;
af.modifier = 4;
affect_join( ch, vch, &af);
af.location = APPLY_NATURAL_AC;
af.modifier = 4;
affect_join( ch, vch, &af);
af.location = APPLY_COMP_FORT;
af.modifier = 4;
affect_join( ch, vch, &af);
act( "{138}Your muscles ripple as you thirst for battle!", vch, NULL, NULL, TO_CHAR);
act( "{138}$n's muscles ripple as $e thirsts for battle!", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_heroism)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_MOR_TOHIT;
af.modifier = 2;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_SAVES;
af.modifier = 2;
affect_join( ch, vch, &af);
af.location = APPLY_SAVE_FEAR;
af.modifier = 2;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_SKILL;
af.modifier = 2;
affect_join( ch, vch, &af);
act( "{138}You brim with morale and bravery.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n brims with morale and bravery.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_greater_heroism)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_MOR_TOHIT;
af.modifier = 4;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_SAVES;
af.modifier = 4;
affect_join( ch, vch, &af);
af.location = APPLY_MOR_SKILL;
af.modifier = 4;
affect_join( ch, vch, &af);
af.location = APPLY_IMM_FEAR;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_HIT;
af.modifier = level;
affect_join( ch, vch, &af);
act( "{138}You brim with morale and bravery.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n brims with morale and bravery.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_rage)
{
if (IS_AFFECTED(vch, AFF2_BERSERK))
{
act("$N is already enraged.", ch, NULL, vch, TO_CHAR);
continue;
}
af.duration = level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_BERSERK;
af.location = APPLY_STR;
af.modifier = UMIN(level/5+2, 4);
affect_join( ch, vch, &af);
af.location = APPLY_CON;
affect_to_char( ch, vch, &af );
af.modifier = af.modifier / 2;
af.location = APPLY_MOR_WILL;
affect_to_char( ch, vch, &af );
af.modifier = -2;
af.location = APPLY_DODGE;
affect_to_char( ch, vch, &af );
act( "{118}You are filled with a seething rage!",vch, NULL, NULL, TO_CHAR);
act( "$n {118}is filled with a seething rage!",vch, NULL, NULL, TO_ROOM);
cnt += 3;
}
if (sn == gsn_protection_evil || sn == gsn_circle_against_evil)
{
af.duration = sn == gsn_circle_against_evil ? 5*turn*level : turn*level;
af.location = APPLY_RES_EVIL;
af.modifier = 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af );
af.location = APPLY_SAVE_MIND;
af.modifier = 4;
affect_join( ch, vch, &af);
act( "{138}You feel protected from evil.", vch, NULL, NULL, TO_CHAR );
act( "{138}$n is shielded with a ward against evil.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_protection_good || sn == gsn_circle_against_good)
{
af.duration = sn == gsn_circle_against_good ? 5*turn*level : turn*level;
af.location = APPLY_RES_GOOD;
af.modifier = 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af );
af.location = APPLY_SAVE_MIND;
af.modifier = 4;
affect_join( ch, vch, &af);
act( "{118}You feel protected from good.", vch, NULL, NULL, TO_CHAR );
act( "$n {118}is shielded with a ward against good.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_protection_law || sn == gsn_circle_against_law)
{
af.duration = sn == gsn_circle_against_law ? 5*turn*level : turn*level;
af.location = APPLY_RES_LAW;
af.modifier = 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af );
af.location = APPLY_SAVE_MIND;
af.modifier = 4;
affect_join( ch, vch, &af);
act( "{158}You feel protected from order.", vch, NULL, NULL, TO_CHAR );
act( "{158}$n is shielded with a ward against order.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_protection_chaos || sn == gsn_circle_against_chaos)
{
af.duration = sn == gsn_circle_against_chaos ? 5*turn*level : turn*level;
af.location = APPLY_RES_CHAOS;
af.modifier = 2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af );
af.location = APPLY_SAVE_MIND;
af.modifier = 4;
affect_join( ch, vch, &af);
act( "{178}You feel protected from chaos.", vch, NULL, NULL, TO_CHAR );
act( "{178}$n is shielded with a ward against chaos.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_undeath_ward)
{
af.duration = turn * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
affect_join( ch, vch, &af );
act( "{178}A veil of positive energy surrounds you.", vch, NULL, NULL, TO_CHAR );
act( "{178}$n is veiled in positive energy.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_protection_spells)
{
af.duration = hr * level;
af.location = APPLY_RES_SPELL;
af.modifier = 8;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af );
act( "{138}You are warded against magical spells.", vch, NULL, NULL, TO_CHAR );
if ( ch != vch )
act( "{138}$N is warded against magical spells.", ch, NULL, vch, TO_CHAR );
cnt++;
cnt++;
cnt++;
}
if (sn == gsn_missile_deflection)
{
af.duration = turn * level;
af.location = APPLY_NONE;
af.modifier = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af );
act( "{138}You are warded against normal missiles.", vch, NULL, NULL, TO_CHAR );
if ( ch != vch )
act( "{138}$N is warded against normal missiles.", ch, NULL, vch, TO_CHAR );
}
if (sn == gsn_repulsion)
{
af.duration = level;
af.location = APPLY_NONE;
af.modifier = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af );
act( "{138}You are warded against physical contact.", vch, NULL, NULL, TO_CHAR );
if ( ch != vch )
act( "{138}$N is warded against physical contact.", ch, NULL, vch, TO_CHAR );
}
if (sn == gsn_resistance)
{
af.duration = turn;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.location = APPLY_RES_SAVES;
af.modifier = 1;
affect_join( ch, vch, &af );
act( "{138}A magical ward surrounds $n.", vch, NULL, NULL, TO_ROOM );
act( "{138}A magical ward surrounds you.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_slow)
{
if (is_affected(vch, gsn_haste))
{
affect_strip(vch, gsn_haste);
cnt++;
continue;
}
af.duration = level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_STAGGERED;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
af.location = APPLY_DODGE;
af.modifier = -1;
affect_join( ch, vch, &af);
af.location = APPLY_SAVING_REFL;
af.modifier = -1;
affect_join( ch, vch, &af);
af.location = APPLY_COMP_TOHIT;
af.modifier = -1;
affect_join( ch, vch, &af);
act( "You slow down.", vch, NULL, NULL, TO_CHAR );
act( "$n slows down.", vch, NULL, NULL, TO_ROOM );
cnt++;
}
if (sn == gsn_virtue)
{
af.duration = turn;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_HIT;
af.modifier = spell_dice(ch, sn, 1, 3);
affect_join( ch, vch, &af);
act( "{138}A boon of virtue comes over $n.", vch, NULL, NULL, TO_ROOM );
act( "{138}A boon of virtue comes over you.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_confusion || sn == gsn_lesser_confusion || sn == gsn_insanity || sn == gsn_symbol_of_insanity)
{
af.duration = sn == gsn_confusion ? level : sn == gsn_lesser_confusion ? 1 : -1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_CONFUSION;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
send_to_char_color( "Your eyes glaze over in a confused stare.\n\r", vch );
act ("$n's eyes glaze over with a confused stare.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_armor)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_ARMOR;
af.modifier = UMIN(level/3 + 1, 5);
affect_join( ch, vch, &af);
act( "{068}$n is encased in a {078}sh{068}im{078}me{068}ri{078}ng {068}au{078}ra {068}of magical armor.", vch, NULL, NULL, TO_ROOM );
act( "{068}You are encased in a {078}sh{068}im{078}me{068}ri{078}ng {068}au{078}ra {068}of magical armor.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_dimensional_anchor)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
act( "{128}$n is covered in a shimmering emerald field.", vch, NULL, NULL, TO_ROOM );
act( "{128}You are covered in a shimmering emerald field.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_shield_of_faith)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_DEFLECT;
af.modifier = UMIN(level/6 + 2, 5);
affect_join( ch, vch, &af);
act( "{178}$n is surrounded by a deflective aura.", vch, NULL, NULL, TO_ROOM );
act( "{178}You are surrounded by a deflective aura.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_armor_of_darkness)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_DEFLECT;
af.modifier = 3 + UMIN(level/4, 5);
affect_join( ch, vch, &af);
af.location = APPLY_SAVE_LIGHT;
af.modifier = 2;
affect_join( ch, vch, &af);
af.location = APPLY_DARKVISION;
af.modifier = 60;
affect_join( ch, vch, &af);
act( "{108}A shroud of shadows envelops $n.", vch, NULL, NULL, TO_ROOM );
act( "{108}You are enveloped in a shroud of shadow.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_barkskin)
{
af.level = 10 * turn * level;
af.duration = turn;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NATURAL_AC;
af.modifier = UMIN(level/3 + 1, 5);
affect_join( ch, vch, &af);
act( "{038}$n's skin thickens into the texture of bark.", vch, NULL, NULL, TO_ROOM );
act( "{038}Your skin thickens into the texture of bark.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_true_seeing)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_TRUESIGHT;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
send_to_char_color( "{138}Your eyes gain the ability to see through the facades over reality.\n\r", vch );
}
if (sn == gsn_feather_fall)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_FEATHER_FALL;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
send_to_char_color( "{178}You feel light as a feather.\n\r", vch );
act( "{178}$n becomes light as a feather.", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_globe_of_invulnerability || sn == gsn_minor_globe)
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
act( "{178}A {078}sh{178}im{078}me{178}ri{078}ng {178}g{078}lo{178}be {078}forms around you.\n\r", vch, NULL, NULL, TO_CHAR );
act( "{178}A {078}sh{178}im{078}me{178}ri{078}ng {178}g{078}lo{178}be {078}forms around $n.\n\r", vch, NULL, NULL, TO_ROOM );
}
if (sn == gsn_analyze_dweomer)
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
send_to_char_color( "{148}Your eyes attune to all things magical.\n\r", vch );
}
if (sn == gsn_leap)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_JUMP;
af.modifier = UMIN(9 + level, 20);
affect_join( ch, vch, &af);
act( "{138}Your legs grow stronger.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n's legs grow stronger.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_spider_climb)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_CLIMB;
af.modifier = UMIN(9 + level, 20);
affect_join( ch, vch, &af);
act( "{138}You gain the ability to walk on walls.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n gains the ability to walk on walls.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_moment_of_prescience)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_INS_SKILL;
af.modifier = UMIN(level, 25);
affect_join( ch, vch, &af);
act( "{138}Your mind is guided by a powerful insight.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n's face radiates with powerful insight.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_true_strike)
{
af.duration = turn;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_INS_TOHIT;
af.modifier = 20;
affect_join( ch, vch, &af);
act( "{138}Your aim becomes deadly.", vch, NULL, NULL, TO_CHAR);
if (ch != vch)
act( "{138}$N's aim becomes deadly.", ch, NULL, vch, TO_CHAR);
}
if (sn == gsn_wraith_form)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_DR_MAGIC;
af.modifier = 5;
affect_join( ch, vch, &af);
act( "{108}$n's visage assumes a ghostly form.", vch, NULL, NULL, TO_ROOM );
act( "{108}Your visage assumes a ghostly form.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_displacement)
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_CONCEALMENT;
af.modifier = 50;
affect_join( ch, vch, &af);
act( "{168}$n's image shifts two feet away.", vch, NULL, NULL, TO_ROOM );
act( "{168}Your image is displaced.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_blur)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_CONCEALMENT;
af.modifier = 20;
affect_join( ch, vch, &af);
act( "{108}$n's image blurs and distorts.", vch, NULL, NULL, TO_ROOM );
act( "{108}Your image becomes blurred.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_spell_resistance)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_SPELL_RES;
af.modifier = 12 + level;
affect_join( ch, vch, &af);
act( "{138}An anti-magical ward glows around $n.", vch, NULL, NULL, TO_ROOM );
act( "{138}An anti-magical ward glows around you.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_tree_stride)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
act( "{128}You gain the ability to walk the trees.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_detect_scrying)
{
af.duration = hr * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
act( "{178}Your mind awakens to prying eyes.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_discern_lies)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_SENSE_MOT;
af.modifier = level / 2;
affect_join( ch, vch, &af);
act( "{178}Your eyes better perceive the truth.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_speak_w_animals)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_HANDLE_ANIM;
af.modifier = level / 5 + 4;
affect_join( ch, vch, &af);
act( "{178}Your mind opens to the fauna around you.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_regenerate)
{
af.duration = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_REGENERATION;
af.modifier = level / 5 + 3;
affect_join( ch, vch, &af);
act( "{138}$n's wounds start to knit themselves.", vch, NULL, NULL, TO_ROOM );
act( "{138}Your wounds start to knit rapidly.", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_death_ward || sn == gsn_mass_death_ward)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_SAVE_DEATH;
af.modifier = 4 + UMIN(level/4, 4);
affect_join( ch, vch, &af );
af.location = APPLY_IMM_NEGATIVE;
af.modifier = 1;
affect_join( ch, vch, &af );
cnt++;
act( "{108}$n is warded against the sting of death.", vch, NULL, NULL, TO_ROOM );
act( "{108}You are warded against the sting of death.", vch, NULL, NULL, TO_CHAR );
}
// Add here because damage shields should not stack - Kregor
if (!is_affected(vch, gsn_blade_barrier) && !is_affected(vch, gsn_fire_shield)
&& !is_affected(vch, gsn_thorn_body) && !is_affected(vch, gsn_aura_of_retribution)
&& !is_affected(vch, gsn_death_armor))
{
if (sn == gsn_blade_barrier)
{
af.duration = turn * level;
af.location = APPLY_DEFLECT;
af.modifier = 4;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af );
act( "{178}Blades of force whirl around $n!", vch, NULL, NULL, TO_ROOM );
act( "{178}You are surrounded by whirling blades of force!", vch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_fire_shield)
{
af.duration = turn * level;
af.location = APPLY_DR_FIRE;
af.modifier = 10;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af );
act( "$n {118}is enveloped in a shield of flames!", vch, NULL, NULL, TO_ROOM );
send_to_char_color( "{118}You are enveloped in a shield of flames!\n\r", vch );
}
if (sn == gsn_thorn_body)
{
af.duration = turn * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af );
act( "{038}Thorns sprout from $n's body!", vch, NULL, NULL, TO_ROOM );
send_to_char_color( "{038}Thorns sprout from your body!\n\r", vch );
}
if (sn == gsn_aura_of_retribution)
{
af.duration = turn * level;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af );
act( "$n {138}is enveloped in a rediating aura.", vch, NULL, NULL, TO_ROOM );
send_to_char_color( "{138}You are enveloped in radiating aura.\n\r", vch );
}
if (sn == gsn_death_armor)
{
af.duration = turn * level;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af );
act( "$n {108}is enveloped in a black aura!", vch, NULL, NULL, TO_ROOM );
send_to_char_color( "{108}You are enveloped in a black aura!\n\r", vch );
}
}
if (sn == gsn_spirit_of_triumph)
{
af.duration = level;
af.location = APPLY_LUCK_TOHIT;
af.modifier = level/2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, vch, &af );
af.location = APPLY_LUCK_DAMG;
af.modifier = level/2;
affect_join( ch, vch, &af );
af.location = APPLY_LUCK_SAVES;
af.modifier = level/2;
affect_join( ch, vch, &af );
af.location = APPLY_LUCK_SKILL;
af.modifier = level/2;
affect_join( ch, vch, &af );
act( "$n {178}is empowered by a blessing of great favor!", vch, NULL, NULL, TO_ROOM );
send_to_char_color( "{178}You are empowered by a blessing of great favor!\n\r", vch );
}
if (sn == gsn_magic_fang)
{
if (!has_natural_weapon(vch) && !learned(ch, gsn_martial_arts))
{
act( "$N has no natural weapons to enhance.", ch, NULL, vch, TO_CHAR);
pop_call();
return FALSE;
}
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_HITROLL;
af.modifier = URANGE(1, level/4, 5);
affect_join( ch, vch, &af);
af.location = APPLY_DAMROLL;
af.modifier = URANGE(1, level/4, 5);
affect_join( ch, vch, &af);
act( "{138}Your natural weapons glow faintly.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n's natural weapons glow faintly.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_stone_fist)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
act( "{108}Your limbs harden like stone.", vch, NULL, NULL, TO_CHAR);
act( "{108}$n's limbs become stoney.", vch, NULL, NULL, TO_ROOM);
}
if (sn == gsn_undeaths_eternal_foe)
{
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_IMM_NEGATIVE;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_IMM_POISON;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_IMM_DISEASE;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_IMM_PARALYSIS;
af.modifier = 1;
affect_join( ch, vch, &af);
af.location = APPLY_SAVE_DEATH;
af.modifier = 4 + UMIN(level/4, 4);
affect_join( ch, vch, &af );
act( "{138}You are wrapped in an aura of positive energy.", vch, NULL, NULL, TO_CHAR);
act( "{138}$n is is wrapped in an aura of positive energy.", vch, NULL, NULL, TO_ROOM);
}
if (!area)
break;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_acid_arrow)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
int dam;
push_call("spell_acid_arrow(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = spell_dice(ch, sn, 2, 4);
if (valid_victim(victim) && !save_resist(ch, victim, sn, level))
{
damage( ch, victim, dam, sn, NULL );
af.type = sn;
af.duration = 1 + (level/3);
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_to_char( ch, victim, &af );
act( "{128}Caustic acid begins to eat away at $n.", victim, NULL, NULL, TO_ROOM);
act( "{128}Caustic acid begins to eat away at you!", victim, NULL, NULL, TO_CHAR);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_acid_splash)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_acid_splash(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{128}A tiny orb of acid shoots from $n's hand.", ch, NULL, NULL, TO_ROOM );
act( "{128}A tiny orb of acid shoots from your hand.", ch, NULL, NULL, TO_CHAR );
dam = spell_dice(ch, sn, 1,4) + UMIN(level/2, 5);
spell_damage(ch, victim, dam, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_admonishing_ray)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int count;
push_call("spell_admonishing_ray(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (count = 0; count <= UMIN(level, 11); count++)
{
if ( count == 1 || (count - 3) % 4 == 0 )
{
act( "{118}A ray of force shoots from $n's finger.", ch, NULL, NULL, TO_ROOM );
act( "{118}A ray of force shoots from your finger.", ch, NULL, NULL, TO_CHAR );
spell_damage(ch, victim, spell_dice(ch, sn, 4, 6), sn, level);
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_align_weapon)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
int alignment = 0;
push_call("spell_align_weapon(%p,%p,%p,%p)",sn,level,ch,vo);
if (obj->item_type != ITEM_WEAPON)
{
act( "You can only imbue weapons with this blessing.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (IS_UNCONCERNED(ch) && IS_NEUTRAL(ch))
{
send_to_char("You lack any moral or ethic to align a weapon.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (IS_CHAOTIC(ch) && !IS_OBJ_CHAOTIC(obj))
SET_BIT(alignment, ITEM_CHAOTIC);
if (IS_LAWFUL(ch) && !IS_OBJ_LAWFUL(obj))
SET_BIT(alignment, ITEM_LAWFUL);
if (IS_GOOD(ch) && !IS_OBJ_GOOD(obj))
SET_BIT(alignment, ITEM_GOOD);
if (IS_EVIL(ch) && !IS_OBJ_EVIL(obj))
SET_BIT(alignment, ITEM_EVIL);
if (alignment == 0)
{
act("You failed to add any moral taint to $p.", ch, obj, NULL, TO_CHAR);
pop_call();
return TRUE;
}
act( "{178}Divine power radiates from $p.", ch, obj, NULL, TO_ALL);
af.type = sn;
af.duration = level;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_OBJ;
af.bitvector = alignment;
af.level = level;
affect_to_obj( ch,obj, &af);
pop_call();
return TRUE;
}
DO_SPELL(spell_animate_dead)
{
CHAR_DATA *mh;
MOB_INDEX_DATA *mob;
OBJ_DATA *obj;
push_call("spell_animate_dead(%p,%p,%p,%p)",sn,level,ch,vo);
for (obj = ch->in_room->first_content ; obj ; obj = obj->next_content)
{
if (obj->item_type == ITEM_CORPSE_NPC && obj->level <= level)
{
break;
}
}
if (obj == NULL)
{
send_to_char( "You find no suitable corpse.\n\r", ch);
pop_call();
return FALSE;
}
if ((mob = get_mob_index(obj->value[4])) == NULL)
{
send_to_char( "You cannot animate that corpse.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (mob->level > level)
{
send_to_char( "You are not strong enough to animate that corpse.\n\r", ch);
pop_call();
return FALSE;
}
mh = create_mobile(mob_index[MOB_VNUM_ZOMBIE]);
char_to_room( mh, ch->in_room->vnum, TRUE );
if (race_table[mob->race].body_type != BTYPE_BIPEDAL)
{
mh->race = RACE_ZOMBIE_ANIMAL;
}
mh->level = race_table[mob->race].hit_dice;
mh->size = mob->size;
mh->perm_dex = mob->perm_dex - 2;
mh->perm_str = mob->perm_str + 2;
mh->max_hit = mh->level * dice(1,8);
if (arcane_mastery(ch, SCHOOL_NECROMANCY))
{
mh->perm_str += 4;
mh->max_hit += mh->level * 2;
AFFECT_DATA af;
af.type = sn;
af.duration = -1;
af.location = APPLY_TURN_RESIST;
af.modifier = 4;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_to_char( ch, mh, &af );
}
mh->hit = get_max_hit(mh);
switch(mh->size)
{
case SIZE_SMALL:
mh->nat_armor += 1;
break;
case SIZE_MEDIUM:
mh->nat_armor += 2;
mh->level += 1;
break;
case SIZE_LARGE:
mh->nat_armor += 3;
mh->level += 2;
break;
case SIZE_HUGE:
mh->nat_armor += 4;
mh->level += 4;
break;
case SIZE_GARGANTUAN:
mh->nat_armor += 7;
mh->level += 6;
break;
case SIZE_COLOSSAL:
mh->nat_armor += 11;
mh->level += 10;
break;
default:
break;
}
SET_BIT( mh->affected_by , AFF_DOMINATE );
act( "{108}$p rises up into undeath.", ch, obj, NULL, TO_ALL );
RESTRING(mh->name, obj->name);
RESTRING(mh->short_descr, obj->short_descr);
RESTRING(mh->long_descr, format("%s is here, perpetuated by undeath.", obj->short_descr));
RESTRING(mh->description, format("%s%s", obj->description, "It's form is now tattered and twisted through undeath.\n"));
while (obj->first_content)
{
obj->first_content->sac_timer = OBJ_SAC_TIME;
obj_to_room(obj->first_content, obj->in_room->vnum);
}
junk_obj(obj);
add_follower( mh , ch );
pop_call();
return TRUE;
}
DO_SPELL(spell_animate_object)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
MOB_INDEX_DATA *pMob;
CHAR_DATA *mh;
int mod, size;
char clr[10];
push_call("spell_animate_object(%p,%p,%p,%p)",sn,level,ch,vo);
if (!IS_SET(obj->wear_flags, CAN_WEAR_TAKE))
{
act("$p is rooted too firmly to the ground.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
{
act("$p is already enchanted.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (obj->owned_by)
{
act("You cannot seem to animate $p.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (obj->size < SIZE_TINY)
{
act("$p is too small to animate.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
mod = obj->size - SIZE_TINY;
switch (mod)
{
case 0:
case 1:
size = 1;
break;
case 2:
size = 2;
break;
case 3:
size = 4;
break;
case 4:
size = 8;
break;
case 5:
size = 16;
break;
default:
size = 32;
break;
}
if (level < size)
{
act("$p is too big for you to animate.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if ((pMob = get_mob_index(MOB_VNUM_SUMMONS)) == NULL)
{
act("You cannot seem to animate $p.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
mh = create_mobile( pMob );
char_to_room( mh, ch->in_room->vnum, TRUE );
mh->npcdata->sac_timer = level;
mh->npcdata->sac_string = STRALLOC("$n falls to the ground lifeless once more.");
mh->race = RACE_ANIMATED_OBJ;
mh->level = UMAX(1, mod * 2);
mh->size = obj->size;
mh->perm_str = 10 + race_table[mh->race].race_mod[0];
mh->perm_dex = 10 + race_table[mh->race].race_mod[1];
mh->perm_con = 10 + race_table[mh->race].race_mod[2];
mh->perm_int = 10 + race_table[mh->race].race_mod[3];
mh->perm_wis = 10 + race_table[mh->race].race_mod[4];
mh->perm_cha = 10 + race_table[mh->race].race_mod[5];
mh->height = race_table[mh->race].height;
mh->weight = race_table[mh->race].weight;
mh->speak = race_table[mh->race].speaks;
mh->language = race_table[mh->race].understands;
mh->alignment = mh->ethos = 0;
if (mod)
{
mh->height *= 2 * mod;
mh->weight *= 8 * mod;
}
mh->perm_str += mod * 4;
mh->perm_con += mod * 2;
mh->perm_dex += mod * 2;
mh->max_hit = dice(mh->level, race_type_table[race_table[mh->race].type].hit_die);
mh->max_hit = UMAX(mh->level * race_type_table[race_table[mh->race].type].hit_die / 2, mh->max_hit);
mh->max_hit += mod * 10;
mh->hit = get_max_hit(mh);
// just to be thorough, copy the first color tag from obj to mob - Kregor
if (strstr(obj->short_descr, "{"))
{
if (strstr(obj->short_descr, "{10"))
strcpy(clr, ansi_translate("{108}"));
else if (strstr(obj->short_descr, "{11"))
strcpy(clr, ansi_translate("{118}"));
else if (strstr(obj->short_descr, "{12"))
strcpy(clr, ansi_translate("{128}"));
else if (strstr(obj->short_descr, "{13"))
strcpy(clr, ansi_translate("{138}"));
else if (strstr(obj->short_descr, "{14"))
strcpy(clr, ansi_translate("{148}"));
else if (strstr(obj->short_descr, "{15"))
strcpy(clr, ansi_translate("{158}"));
else if (strstr(obj->short_descr, "{16"))
strcpy(clr, ansi_translate("{168}"));
else if (strstr(obj->short_descr, "{17"))
strcpy(clr, ansi_translate("{178}"));
else if (strstr(obj->short_descr, "{01"))
strcpy(clr, ansi_translate("{018}"));
else if (strstr(obj->short_descr, "{02"))
strcpy(clr, ansi_translate("{028}"));
else if (strstr(obj->short_descr, "{03"))
strcpy(clr, ansi_translate("{038}"));
else if (strstr(obj->short_descr, "{04"))
strcpy(clr, ansi_translate("{048}"));
else if (strstr(obj->short_descr, "{05"))
strcpy(clr, ansi_translate("{058}"));
else if (strstr(obj->short_descr, "{06"))
strcpy(clr, ansi_translate("{068}"));
else if (strstr(obj->short_descr, "{07"))
strcpy(clr, ansi_translate("{078}"));
}
RESTRING(mh->name, format("%s animated", obj->name));
RESTRING(mh->short_descr, format("an animated %s", short_to_name(obj->short_descr, 1)));
RESTRING(mh->long_descr, format("{078}An animated %s%s {078}is here.", clr, short_to_name(obj->short_descr, 1)));
SET_BIT( mh->affected_by , AFF_DOMINATE );
act( "$n begins to move on its own.", mh, NULL, NULL, TO_ROOM );
junk_obj(obj);
add_follower( mh , ch );
pop_call();
return TRUE;
}
DO_SPELL(spell_antimagic_field)
{
ROOM_INDEX_DATA *room;
CHAR_DATA *rch, *rch_next;
AFFECT_DATA *paf, *paf_next;
ROOM_TIMER_DATA rtd;
OBJ_DATA *obj;
int paf_type;
push_call("spell_antimagic_field(%p,%p,%p,%p)",sn,level,ch,vo);
if( ch->in_room == NULL )
{
pop_call();
return FALSE;
}
room = ch->in_room;
if( IS_SET(room->room_flags, ROOM_NO_MAGIC ) )
{
send_to_char( "There is already an antimagic ward here.\n\r", ch );
pop_call();
return FALSE;
}
if( IS_SET(room->room_flags, ROOM_SAFE ) )
{
send_to_char( "Your antimagic ward dissipates immediately.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = level * turn;
rtd.bitvector = ROOM_NO_MAGIC;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{058}A sphere of antimagic energy covers the area.", ch, NULL, NULL, TO_ALL );
for (rch = ch->in_room->first_person ; rch != NULL ; rch = rch_next)
{
rch_next = rch->next_in_room;
for ( paf_type = 0, paf = rch->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (!is_spell(paf->type))
{
continue;
}
if ((paf_type == 0 || paf_type != paf->type) && paf->duration >= 0)
{
if (skill_table[paf->type].msg_off)
{
act( skill_table[paf->type].msg_off, rch, NULL, NULL, TO_CHAR);
}
if (skill_table[paf->type].msg_off_room)
{
act(skill_table[paf->type].msg_off_room, rch, NULL, NULL, TO_ROOM);
}
}
paf_type = paf->type;
affect_from_char(rch, paf);
}
for (obj = rch->first_carrying; obj != NULL ; obj = obj->next_content)
{
for ( paf = obj->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (!is_spell(paf->type))
{
continue;
}
if ((paf_type == 0 || paf_type != paf->type) && paf->duration >= 0)
{
if (skill_table[paf->type].msg_obj_off)
{
act( skill_table[paf->type].msg_obj_off, rch, obj, NULL, TO_CHAR);
if (rch->in_room)
act( skill_table[paf->type].msg_obj_off, rch, obj, NULL, TO_ROOM);
}
}
paf_type = paf->type;
affect_from_obj(obj, paf);
}
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_arcane_eye)
{
MOB_INDEX_DATA *pMob;
CHAR_DATA *mh;
push_call("spell_arcane_eye(%p,%p,%p,%p)",sn,level,ch,vo);
if (ch->desc == NULL || ch->desc->original != NULL)
{
send_to_char( "You already are switched into something.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "$n seems to enter into a trance", ch, NULL, NULL, TO_ROOM);
pMob = get_mob_index( MOB_VNUM_WIZARD_EYE ); /* Hard coded in mud.are */
mh = create_mobile( pMob );
char_to_room(mh, ch->in_room->vnum, TRUE);
ch->desc->character = mh;
ch->desc->original = ch;
mh->desc = ch->desc;
ch->desc = NULL;
ch->pcdata->switched = TRUE;
mh->npcdata->sac_timer = turn * level;
vt100prompt( mh );
act( "You focus your senses elsewhere.", mh, NULL, NULL, TO_CHAR);
pop_call();
return TRUE;
}
DO_SPELL(spell_banish)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *rch;
ROOM_INDEX_DATA *pRoomIndex;
int cnt = 0;
push_call("spell_banish(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (victim->in_room == NULL
|| victim == ch
|| IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
|| IS_SET(ch->in_room->area->flags, AFLAG_NORECALL)
|| IS_SET(ch->in_room->room_flags, AFLAG_NOSUMMON)
|| IS_SET(ch->in_room->room_flags, AFLAG_NOTELEPORT)
|| victim->level > level * 2
|| save_resist(ch, victim, sn, level))
{
act( "You failed to banish $N.", ch, NULL, victim, TO_CHAR );
pop_call();
return TRUE;
}
if (IS_NPC(victim) && race_type(victim) == RTYPE_OUTSIDER)
{
act( "{138}$n is banished from this plane!", victim, NULL, NULL, TO_ROOM );
act( "{138}You have been banished from this plane!", ch, NULL, victim, TO_VICT );
if (victim->in_room != ch->in_room)
act( "{138}$N is banished from this plane!", ch, NULL, victim, TO_ROOM );
extract_char(victim);
pop_call();
return TRUE;
}
for ( ; ; )
{
/*
Better safe than freezing, added cnt - Scandum 01-04-2002
*/
if (cnt++ > 10000)
{
send_to_char("Nothing happens", ch);
pop_call();
return TRUE;
}
pRoomIndex = get_room_index(number_range(victim->in_room->area->low_r_vnum, victim->in_room->area->hi_r_vnum));
if ( pRoomIndex != NULL )
{
if (!is_room_good_for_teleport(victim, pRoomIndex->vnum)
|| pRoomIndex == victim->in_room)
{
continue;
}
for (rch = pRoomIndex->first_person ; rch ; rch = rch->next_in_room)
{
if (IS_NPC(rch) && rch->pIndexData->pShop != NULL)
{
break;
}
}
if (rch)
{
continue;
}
break;
}
}
act( "{138}$n is banished from your presence.", victim, NULL, NULL, TO_ROOM );
act( "{138}You have been banished from $n's presence.", ch, NULL, victim, TO_VICT );
if (victim->in_room != ch->in_room)
act( "{138}$N is banished from your presence.", ch, NULL, victim, TO_ROOM );
if (in_combat(victim))
{
withdraw_combat(victim);
}
char_from_room( victim );
char_to_room( victim, pRoomIndex->vnum, TRUE );
do_look( victim, "auto" );
if (!IS_NPC(victim))
{
mprog_greet_trigger(victim);
oprog_greet_trigger(victim);
rprog_greet_trigger(ch);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_black_tentacles)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
ROOM_TIMER_DATA rtd;
push_call("spell_black_tentacles(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(victim->in_room->room_flags, ROOM_ENTANGLE))
{
send_to_char("This area is already affected.\n\r", ch );
pop_call();
return FALSE;
}
if (IS_SET(victim->in_room->room_flags, ROOM_SAFE))
{
send_to_char_color( "Wards prevent you from casting that here.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = victim->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = level;
rtd.bitvector = ROOM_ENTANGLE;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{108}Large, black tentacles erupt from the ground!", victim, NULL, NULL, TO_CHAR);
act( "{108}Large, black tentacles erupt from the ground!", victim, NULL, NULL, TO_ROOM);
if (ch->in_room != victim->in_room)
{
act( "{108}You conjure up black tentacles around $N!", ch, NULL, victim, TO_CHAR);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_blacklight)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
ROOM_TIMER_DATA rtd;
push_call("spell_blacklight(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(victim->in_room->room_flags, ROOM_BLACKLIGHT))
{
send_to_char("This room is already shrouded in darkness.\n\r", ch );
pop_call();
return FALSE;
}
if (IS_SET(victim->in_room->room_flags, ROOM_SAFE) || IS_SET(ch->in_room->room_flags, ROOM_SAFE))
{
send_to_char( "Wards prevent you from casting that spell.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (is_room_affected(victim->in_room, gsn_daylight))
{
affect_room_strip(victim->in_room, gsn_daylight);
pop_call();
return TRUE;
}
rtd.vnum = victim->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_ROOM_LIGHT;
rtd.modifier = -2;
rtd.duration = level;
rtd.bitvector = ROOM_BLACKLIGHT;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{108}The light around you dissolves into darkness.", victim, NULL, NULL, TO_ALL);
if (ch->in_room != victim->in_room)
act( "{108}The light around $N dissolves into darkness.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
DO_SPELL(spell_break_enchantment)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *fch;
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
int paf_type, diceroll, count;
push_call("spell_break_enchantment(%p,%p,%p,%p)",sn,level,ch,vo);
if (arcane_mastery(ch, SCHOOL_ABJURATION))
diceroll = UMAX(dice(1,20), dice(1,20)) + UMIN(level, 15);
else
diceroll = dice(1, 20) + UMIN(level, 15);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (count = 0, fch = victim->in_room->first_person ; fch ; fch = fch->next_in_room)
{
if (count >= level)
continue;
if (!is_same_group(victim, fch))
continue;
for ( paf_type = 0, paf = fch->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (!is_spell(paf->type))
continue;
if (!IS_SET(paf->bitvector, AFF_BLIND)
&& !IS_SET(paf->bitvector, AFF2_PARALYSIS)
&& !IS_SET(paf->bitvector, AFF_SLEEP)
&& !IS_SET(paf->bitvector, AFF_CURSE)
&& !IS_SET(paf->bitvector, AFF_DEAF)
&& !IS_SET(paf->bitvector, AFF_DOMINATE)
&& !IS_SET(paf->bitvector, AFF2_FASCINATED)
&& !IS_SET(paf->bitvector, AFF2_HALLUCINATE)
&& !IS_SET(paf->bitvector, AFF2_STUNNED)
&& !IS_SET(paf->bitvector, AFF2_POSSESS)
&& !IS_SET(paf->bitvector, AFF2_SILENCE)
&& !IS_SET(paf->bitvector, AFF2_CONFUSION)
&& !IS_SET(paf->bitvector, AFF2_PETRIFICATION))
{
if (skill_table[paf->type].spell_class != STYPE_CURSE)
{
continue;
}
}
if (diceroll < 11 + paf->level)
continue;
if (skill_table[paf->type].msg_off)
{
act( skill_table[paf->type].msg_off, fch, NULL, NULL, TO_CHAR);
}
if (skill_table[paf->type].msg_off_room)
{
act( skill_table[paf->type].msg_off_room, fch, NULL, NULL, TO_ROOM);
}
paf_type = paf->type;
affect_from_char(fch, paf);
}
if (paf_type == 0)
{
send_to_char( "Nothing appears to happen.\n\r", ch );
}
else if (fch != ch)
{
act( "$N's enchantments vanish one by one.", ch, NULL, fch, TO_CHAR );
}
for (obj = fch->first_carrying; obj!=NULL ; obj=obj->next_content)
{
if(IS_SET(obj->extra_flags, ITEM_NOREMOVE))
{
act( "%p is removed from $n.", fch, obj, NULL, TO_ROOM);
act( "%p is removed from you.", fch, obj, NULL, TO_CHAR);
obj_from_char(obj);
obj_to_room( obj, fch->in_room->vnum );
}
}
count += 1;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_burning_hands)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_burning_hands(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{118}Searing flames shoot from $n's hands.", ch, NULL, NULL, TO_ROOM );
act( "{118}Searing flames shoot from your hands.", ch, NULL, NULL, TO_CHAR );
dam = spell_dice(ch, sn, UMIN(level, 5),4);
spell_damage(ch, victim, dam, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_scorching_ray)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int count;
push_call("spell_scorching_ray(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (count = 0; count <= UMIN(level, 11); count++)
{
if ( count == 1 || (count - 3) % 4 == 0 )
{
act( "{118}A ray of flames shoots from $n's finger.", ch, NULL, NULL, TO_ROOM );
act( "{118}A ray of flames shoots from your finger.", ch, NULL, NULL, TO_CHAR );
spell_damage(ch, victim, spell_dice(ch, sn, 4, 6), sn, level);
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_call_lightning)
{
ROOM_INDEX_DATA *room;
ROOM_TIMER_DATA rtd;
push_call("spell_call_lightning(%p,%p,%p,%p)",sn,level,ch,vo);
if ((room = ch->in_room) == NULL)
{
pop_call();
return FALSE;
}
if (NO_WEATHER_SECT(room->sector_type))
{
send_to_char_color( "{048}You cannot see the weather from here.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = sn = gsn_call_lightning ? 10 : 15;
rtd.bitvector = ROOM_NONE;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{108}Thunder clouds quickly gather in the area above.", ch, NULL, NULL, TO_ALL);
pop_call();
return TRUE;
}
/*
* One function for all Calm X spells - Kregor
*/
DO_SPELL(spell_calm)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
push_call("spell_calm(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if (is_same_group(ch, vch))
continue;
if (sn == gsn_calm_animals && !IS_ANIMAL(ch))
continue;
if (!in_combat(vch) && !IS_ACT(vch, ACT_AGGRESSIVE))
continue;
if (save_resist(ch, vch, sn, level) != FALSE)
continue;
if (in_combat(vch))
char_from_combat(vch);
af.type = sn;
af.duration = turn * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_CALMED;
af.level = level;
affect_join( ch, vch, &af );
act("Your emotions are calmed.", vch, NULL, NULL, TO_CHAR);
act("$n settles as a soothing peace comes over $m", vch, NULL, NULL, TO_ROOM);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_cause_fear)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
sh_int count, save, duration, mod;
push_call("spell_cause_fear(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (count = 0, vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (count && count >= level / 3)
break;
if (sn == gsn_cause_fear)
{
if (vch != victim)
{
continue;
}
}
else if (!can_mass_cast(ch, vch, sn))
{
continue;
}
if ((sn == gsn_cause_fear || sn == gsn_scare) && vch->level > 6)
{
act( "You ignore $n's fear spell.", vch, NULL, ch, TO_CHAR );
act( "$n shrugs off your spell.", vch, NULL, NULL, TO_ROOM );
continue;
}
if ((save = save_resist(ch, vch, sn, level)) == TRUE)
{
continue;
}
if (IS_NPC(vch))
{
if (!IS_SET(vch->act, ACT_WIMPY))
SET_BIT(vch->act, ACT_WIMPY);
}
if (!save)
{
duration = sn == gsn_fear ? level : dice(1,4);
mod = sn == gsn_fear ? 3 : 2;
act( "You become filled with fear!", vch, NULL, NULL, TO_CHAR );
act( "$n becomes filled with fear!", vch, NULL, NULL, TO_ROOM );
}
else
{
duration = mod = 1;
act( "You become shaken!", vch, NULL, NULL, TO_CHAR );
act( "$n becomes shaken!", vch, NULL, NULL, TO_ROOM );
}
af.type = sn;
af.duration = duration;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_FEAR;
af.location = APPLY_NONE;
af.modifier = mod;
af.level = level;
affect_join( ch, vch, &af);
vch->fear_level = mod;
if (in_combat(vch))
{
do_withdraw(vch, NULL);
}
if (sn == gsn_cause_fear)
break;
if (sn == gsn_scare)
count++;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_chain_lightning)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
ROOM_INDEX_DATA *temp_room = victim->in_room;
int dam, targets;
int save;
push_call("spell_chain_lightning(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{178}You launch forth a bolt of lightning at $N!", ch, NULL, victim, TO_CHAR );
act( "{178}$n launches forth a bolt of lightning at $N!", ch, NULL, victim, TO_NOTVICT );
act( "{178}$n launches forth a bolt of lightning at you!", ch, NULL, victim, TO_VICT );
targets = UMIN(level, 15);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn) || !is_same_group(victim, vch))
{
continue;
}
dam = spell_dice(ch, sn, targets, 6);
act( "{178}The bolt of chain lightning arcs to you.", vch, NULL, NULL, TO_CHAR);
act( "{178}The bolt of chain lightning arcs to $n.", vch, NULL, NULL, TO_ROOM);
if ((save = save_resist(ch, vch, sn, level)) != TRUE)
{
if (save == PARTIAL)
dam /= 2;
damage( ch, vch, dam, sn, NULL );
}
if (--targets <= 0)
{
break;
}
}
send_to_room("{178}The searing bolt of chain lightning arcs to the ground and dissipates.\n\r", temp_room);
pop_call();
return TRUE;
}
DO_SPELL(spell_charm)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_charm(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
{
send_to_char("Wards of peace prevent your spell here.\n\r", ch);
pop_call();
return FALSE;
}
if (victim == ch)
{
send_to_char( "You like yourself even better!\n\r", ch );
pop_call();
return FALSE;
}
if (is_affected(victim, sn))
{
send_to_char( "They are already affected.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (is_safe(ch, victim)
|| (sn == gsn_charm_plant && race_type(victim) != RTYPE_PLANT)
|| (sn == gsn_charm_animal && !IS_ANIMAL(victim))
|| (sn == gsn_charm_person && !IS_HUMANOID(victim)))
{
send_to_char( "They seem to be unaffected by your magic.\n\r", ch );
pop_call();
return TRUE;
}
if (save_resist(ch, victim, sn, level))
{
pop_call();
return TRUE;
}
withdraw_combat(victim);
// if (!IS_NPC(victim))
// {
// act( "You look at $n with a more favorable demeanor.", ch, NULL, victim, TO_VICT );
// act( "$N looks at you with a favorable demeanor.", ch, NULL, victim, TO_CHAR );
// act( "$N looks at $n with a favorable demeanor.", ch, NULL, victim, TO_NOTVICT );
// do_help(victim, "charm person");
// pop_call();
// return TRUE;
// }
//
af.type = sn;
af.duration = hr * level;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_CHARMED;
af.level = level;
affect_to_char( ch, victim, &af );
if (IS_NPC(victim))
REMOVE_BIT(victim->act, ACT_AGGRESSIVE);
act( "You look at $n with a more favorable demeanor.", ch, NULL, victim, TO_VICT );
act( "$N looks at you with a favorable demeanor.", ch, NULL, victim, TO_CHAR );
act( "$N looks at $n with a favorable demeanor.", ch, NULL, victim, TO_NOTVICT );
pop_call();
return TRUE;
}
DO_SPELL(spell_chill_touch)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
int dam;
push_call("spell_chill_touch(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = spell_dice(ch, sn, 1, 6);
if (can_backstab(ch, victim, sn) && number_percent() > get_apply(victim, APPLY_FORTIFICATION))
{
int bs_dice = ROUNDUP(multi_skill_level(ch, gsn_backstab) / 2);
int bs_dam = 0;
if (get_monk_style(ch) == STYLE_SLEEPING_TIGER && class_level(ch, CLASS_MONK) >= 12)
bs_dice++;
if (bs_dice > 0)
{
if (learned(ch, gsn_greater_sneak_attack))
{
bs_dam = dice(bs_dice, 8);
}
else
{
bs_dam = dice(bs_dice, 6);
}
}
dam += bs_dam;
}
damage( ch, victim, dam, sn, NULL );
if (save_resist(ch, victim, sn, level))
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = -1;
af.location = APPLY_STR;
af.modifier = -1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_join( ch, victim, &af );
act( "{068}You feel weaker as $n chills you.", ch, NULL, victim, TO_VICT );
act( "{068}$N looks weaker from your chilling touch.", ch, NULL, victim, TO_CHAR );
act( "{068}$N looks weaker from $n's chilling touch.", ch, NULL, victim, TO_NOTVICT );
pop_call();
return TRUE;
}
DO_SPELL(spell_circle_of_death)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *gch, *gch_next;
int count, lvl, roll;
push_call("spell_circle_of_death(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
roll = dice(UMIN(level, 20), 4);
for (count = lvl = 0 ; lvl <= 9 ; lvl++)
{
for (gch = victim->in_room->first_person ; gch ; gch = gch_next)
{
gch_next = gch->next_in_room;
if (gch->level != lvl)
continue;
if (sn == gsn_circle_of_death && !CAN_CRITICAL(gch))
continue;
if (sn == gsn_undeath_to_death && !IS_UNDEAD(gch))
continue;
if (can_mass_cast(ch, gch, sn))
continue;
if (count + gch->level > roll)
{
act( "$N resists your spell.\n\r", ch, NULL, gch, TO_CHAR );
continue;
}
if (save_resist(ch, gch, sn, level))
continue;
count += gch->level;
damage(ch, gch, gch->hit + 11, sn, NULL);
if (count >= roll)
break;
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_cloudkill)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
ROOM_TIMER_DATA rtd;
ROOM_INDEX_DATA *room;
push_call("spell_cloudkill(%p,%p,%p,%p)",sn,level,ch,vo);
if( victim->in_room == NULL )
{
pop_call();
return FALSE;
}
room = victim->in_room;
if(IS_SET(room->room_flags, ROOM_FOG))
{
send_to_char( "The room is already foggy.\n\r", ch );
pop_call();
return FALSE;
}
if(IS_SET(room->room_flags, ROOM_SAFE))
{
send_to_char( "Wards of peace prevent you from casting that.\n\r", ch );
pop_call();
return TRUE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = turn * level;
rtd.bitvector = ROOM_FOG;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{128}A cloud of green noxious fog billows around you!", victim, NULL, NULL, TO_ALL );
if (room != ch->in_room)
act( "{128}You conjure up a cloud of toxic fog", ch, NULL, NULL, TO_CHAR );
pop_call();
return TRUE;
}
DO_SPELL(spell_color_spray)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch;
CHAR_DATA *vch_next;
int dam1, dam2;
push_call("spell_color_spray)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if (!is_same_group(victim, vch))
continue;
if (save_resist(ch, victim, sn, level))
continue;
dam1 = spell_dice(ch, sn, 2, 4);
dam2 = spell_dice(ch, sn, 1, 4);
act( "{138}You are hit by a {118}da{128}zz{138}li{148}ng {158}ra{168}in{118}bo{128}w {138}of light!", vch, NULL, NULL, TO_CHAR );
act( "A {118}da{128}zz{138}li{148}ng {158}ra{168}in{118}bo{128}w {138} of light hits $n.", vch, NULL, NULL, TO_ROOM );
if (vch->level <= 2)
{
AFFECT_DATA af;
af.type = gsn_color_spray;
af.location = APPLY_NONE;
af.modifier = 0;
af.level = level;
af.duration = dam1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_UNCONSCIOUS;
affect_join( ch, vch, &af );
af.duration = dam1+dam2;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_BLIND;
affect_join( ch, vch, &af );
af.duration = dam1+dam2+1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_STUNNED;
affect_join( ch, vch, &af );
}
else if (vch->level <= 4)
{
AFFECT_DATA af;
af.type = gsn_color_spray;
af.location = APPLY_NONE;
af.modifier = 0;
af.level = level;
af.duration = dam1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_BLIND;
affect_join( ch, vch, &af );
af.duration = dam1+1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_STUNNED;
affect_join( ch, vch, &af );
}
else
{
AFFECT_DATA af;
af.type = gsn_color_spray;
af.location = APPLY_NONE;
af.modifier = 0;
af.level = level;
af.duration = 1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_STUNNED;
affect_join( ch, vch, &af );
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_command)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
OBJ_DATA *obj, *obj_next;
char *command = NULL;
int cnt;
if (victim == ch)
{
send_to_char ("You obey your every whim!\n\r", ch);
pop_call();
return FALSE;
}
if (!is_string(target_name))
{
act("Demand $N to what?", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
switch(tolower(*target_name))
{
case 'd':
case 'f':
case 'k':
break;
default:
send_to_char("You can only order to 'drop', 'flee', or 'kneel'.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
sprintf(command, "%s'%s'", get_color_string(ch, COLOR_SPEECH, VT102_DIM), capitalize(target_name));
act ("$n commands you, $t.", ch, command, victim, TO_VICT);
act ("You command $N, $t.", ch, command, victim, TO_CHAR);
act ("$n commands $N, $t.", ch, command, victim, TO_NOTVICT);
for (cnt = 0, vch = victim->in_room->first_person ; vch ; vch = vch_next)
{
vch_next = vch->next;
if (cnt && cnt >= level)
break;
if (sn == gsn_command && vch != victim)
continue;
if (!is_same_group(vch, victim))
continue;
if (save_resist(ch, vch, sn, level))
continue;
switch(tolower(*target_name))
{
case 'd':
for (obj = vch->first_carrying ; obj ; obj = obj_next)
{
obj_next = obj->next_content;
if (WEAR_LOC(obj, WEAR_HOLD) || WEAR_LOC(obj, WEAR_WIELD) || WEAR_LOC(obj, WEAR_DUAL_WIELD))
{
if (!IS_SET(obj->extra_flags, ITEM_NOREMOVE))
{
unequip_char(vch, obj, TRUE);
drop_obj(vch, obj, NULL, TRUE);
}
}
}
break;
case 'f':
if (in_combat(vch))
{
do_withdraw(vch, "");
}
break;
case 'k':
act("You kneel before $n!", ch, NULL, vch, TO_VICT);
act("$N kneels on the spot!", ch, NULL, vch, TO_VICT);
update_pos(vch, POS_KNEELING);
break;
default:
break;
}
cnt++;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_cone_of_cold)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int diceroll;
push_call("spell_cone_of_cold(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
diceroll = spell_dice(ch, sn, UMIN(level, 15), 6);
spell_damage(ch, victim, diceroll, sn, level);
pop_call();
return TRUE;
}
char * const weather_flags [] =
{
"wet",
"dry",
"hot",
"cold",
"windy",
"calm",
"*"
};
DO_SPELL(spell_control_weather)
{
int value, change;
push_call("spell_control_weather(%p,%p,%p,%p)",sn,level,ch,vo);
if ((value = get_flag(target_name, weather_flags)) == -1)
{
send_to_char ("Do you want the weather cold, hot, calm, windy, wet, or dry?\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
change = level;
if (!has_domain(ch, DOMAIN_WEATHER) && !!has_domain(ch, DOMAIN_AIR) && !!has_domain(ch, DOMAIN_WATER))
change /= 2;
change = UMAX(1, change);
switch (value)
{
case 0:
ch->in_room->area->weather_info->change += change;
break;
case 1:
ch->in_room->area->weather_info->change -= change;
break;
case 2:
ch->in_room->area->weather_info->temperature += change;
break;
case 3:
ch->in_room->area->weather_info->temperature -= change;
break;
case 4:
ch->in_room->area->weather_info->wind_speed += change;
break;
case 5:
ch->in_room->area->weather_info->wind_speed -= change;
break;
}
do_mpareaecho( ch, format("The weather patterns shift suddenly.", target_name) );
weather_area_update(ch->in_room->area);
pop_call();
return TRUE;
}
DO_SPELL(spell_create_food)
{
OBJ_DATA *mushroom;
CHAR_DATA *gch;
int cnt;
push_call("spell_create_food(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (cnt = 0, gch = ch->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (!is_same_group(gch, ch))
{
continue;
}
if (cnt >= 3 * UMIN(level, 20))
{
continue;
}
mushroom = create_object( get_obj_index( OBJ_VNUM_MUSHROOM ), 0 );
mushroom->value[0] = 24;
obj_to_room( mushroom, ch->in_room->vnum );
}
act( "Food suddenly appears in front of $n.", ch, mushroom, NULL, TO_ROOM );
act( "Food suddenly appears in front of you.", ch, mushroom, NULL, TO_CHAR );
pop_call();
return TRUE;
}
DO_SPELL(spell_create_water)
{
OBJ_DATA *obj = ( OBJ_DATA * ) vo;
int water;
if ( obj->item_type != ITEM_DRINK_CON && obj->item_type != ITEM_FOUNTAIN )
{
send_to_char( "It is unable to hold water.\n\r", ch );
pop_call();
return FALSE;
}
if ( obj->value[2] != LIQ_WATER && obj->value[1] != 0 )
{
send_to_char( "It contains some other liquid.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
water = UMIN( level * 2, obj->value[0] - obj->value[1] );
if ( water > 0 )
{
obj->value[2] = LIQ_WATER;
obj->value[1] += water;
act( "$p {168}is filled with clear water.{300}", ch, obj, NULL, TO_CHAR );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_create_spring)
{
OBJ_DATA *spring;
push_call("spell_create_spring(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
spring = create_object( get_obj_index( OBJ_VNUM_SPRING ), 0 );
spring->timer = level;
act( "{148}Tracing a ring before you, the graceful flow of a mystical spring emerges.", ch, spring, NULL, TO_CHAR );
act( "{148}As $n traces a ring through the air, a mystical spring emerges.", ch, spring, NULL, TO_ROOM );
obj_to_room( spring, ch->in_room->vnum );
pop_call();
return TRUE;
}
/*
* The goal was to make this spell as fearful and nasty
* as the original 3.0 spell, without making it a no-save
* instadeath spell - Kregor 2/15/11
*/
DO_SPELL(spell_creeping_doom)
{
ROOM_TIMER_DATA rtd;
push_call("spell_creeping_doom(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(ch->in_room->room_flags, ROOM_SWARM))
{
act("This area is already infested.", ch, NULL, NULL, TO_CHAR );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
{
act("The swarms refuse your call.", ch, NULL, NULL, TO_CHAR );
pop_call();
return TRUE;
}
rtd.vnum = ch->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = (spell_dice(ch, sn, 1, 6) + 4) * 100;
rtd.duration = turn * level;
rtd.bitvector = ROOM_SWARM;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{038}A swarm of vermin pour out from behind $n!", ch, NULL, NULL, TO_ROOM);
act( "{038}A swarm of vermin pour out from behind you!", ch, NULL, NULL, TO_CHAR);
pop_call();
return TRUE;
}
/*
* unified cure and inflict spells into single
* functions for differing strengths - Kregor
*/
DO_SPELL(spell_cure)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int heal;
push_call("spell_cure(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (sn == gsn_cure_light)
heal = spell_dice(ch, sn, 1, 8) + UMIN(level, 5);
else if (sn == gsn_cure_moderate)
heal = spell_dice(ch, sn, 2, 8) + UMIN(level, 10);
else if (sn == gsn_cure_serious)
heal = spell_dice(ch, sn, 3, 8) + UMIN(level, 15);
else if (sn == gsn_cure_critical)
heal = spell_dice(ch, sn, 4, 8) + UMIN(level, 20);
if (is_affected(victim, gsn_festering_wounds))
heal /= 2;
if (IS_UNDEAD(victim))
{
spell_damage( ch, victim, heal, sn, level );
}
else
{
victim->hit = UMIN( victim->hit + heal, get_max_hit(victim));
victim->nonlethal = UMAX(0, victim->nonlethal - heal);
update_pos(victim,-1);
if (heal)
{
act( "{138}Your $t wounds mend and your pain ebbs.", victim, skill_table[sn].msg_off, NULL, TO_CHAR);
act( "{138}$n's $t wounds mend and $s pain ebbs.", victim, skill_table[sn].msg_off, NULL, TO_ROOM);
}
affect_strip(victim, gsn_bleed_damage);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_inflict)
{
int dam;
CHAR_DATA *victim = (CHAR_DATA *) vo;
push_call("spell_inflict(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (sn == gsn_inflict_light)
dam = spell_dice(ch, sn, 1,8) + UMIN(level,5);
else if (sn == gsn_inflict_minor)
dam = spell_dice(ch, sn, 1, 3);
else if (sn == gsn_inflict_moderate)
dam = spell_dice(ch, sn, 2,8) + UMIN(level,10);
else if (sn == gsn_inflict_serious)
dam = spell_dice(ch, sn, 3,8) + UMIN(level,15);
else if (sn == gsn_inflict_critical)
dam = spell_dice(ch, sn, 4,8) + UMIN(level,20);
if (IS_UNDEAD(victim))
{
victim->hit = UMIN( victim->hit + dam, get_max_hit(victim));
update_pos(victim,-1);
act( "{138}Your $t wounds mend and your pain ebbs.", victim, skill_table[sn].msg_off, NULL, TO_CHAR);
act( "{138}$n's $t wounds mend.", victim, skill_table[sn].msg_off, NULL, TO_ROOM);
}
else
{
spell_damage( ch, victim, dam, sn, level );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_stabilize)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
push_call("spell_stabilize(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (IS_UNDEAD(victim))
{
act( "Your spell has no effect on $N.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
else
{
if (victim->position >= POS_STUNNED)
{
act( "{138}$n is not mortally wounded.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
victim->hit = 0;
update_pos(victim,-1);
affect_strip(victim,gsn_bleed_damage);
act( "{138}You no longer feel your life slipping away.", victim, NULL, NULL, TO_CHAR);
act( "{138}$n is no longer slipping into oblivion.", victim, NULL, NULL, TO_ROOM);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_mass_cure)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *gch;
int heal, cure, cnt;
push_call("spell_mass_cure_light(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (sn == gsn_mass_cure_light)
heal = spell_dice(ch, sn, 1, 8) + UMIN(level, 25);
else if (sn == gsn_mass_cure_moderate)
heal = spell_dice(ch, sn, 2, 8) + UMIN(level, 30);
if (sn == gsn_mass_cure_serious)
heal = spell_dice(ch, sn, 3, 8) + UMIN(level, 35);
if (sn == gsn_mass_cure_critical)
heal = spell_dice(ch, sn, 4, 8) + UMIN(level, 40);
for (cnt = 0, gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
cure = heal;
if (cnt >= level)
{
continue;
}
if (!is_same_group(victim, gch))
continue;
if (IS_UNDEAD(gch))
{
if (!can_mass_cast(ch, gch, sn))
continue;
spell_damage( ch, gch, cure, sn, level );
cnt++;
continue;
}
if (is_affected(gch, gsn_festering_wounds))
cure /= 2;
gch->hit = UMIN( gch->hit + cure, get_max_hit(gch));
gch->nonlethal = UMAX(0, gch->nonlethal - cure);
affect_strip(gch,gsn_bleed_damage);
update_pos(gch,-1);
act( "{138}Your $t wounds mend and your pain ebbs.", gch, skill_table[sn].msg_off, NULL, TO_CHAR);
act( "{138}$n's $t wounds mend and $s pain ebbs.", gch, skill_table[sn].msg_off, NULL, TO_ROOM);
cnt++;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_mass_inflict)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *gch;
int heal, cnt;
push_call("spell_mass_inflict_light(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (sn == gsn_mass_inflict_light)
heal = spell_dice(ch, sn, 1, 8) + UMIN(level, 25);
else if (sn == gsn_mass_inflict_moderate)
heal = spell_dice(ch, sn, 2, 8) + UMIN(level, 30);
if (sn == gsn_mass_inflict_serious)
heal = spell_dice(ch, sn, 3, 8) + UMIN(level, 35);
if (sn == gsn_mass_inflict_critical)
heal = spell_dice(ch, sn, 4, 8) + UMIN(level, 40);
for (cnt = 0, gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (cnt >= level)
{
continue;
}
if (!IS_UNDEAD(gch))
{
if (!can_mass_cast(ch, gch, sn))
continue;
spell_damage( ch, gch, heal, sn, level );
cnt++;
continue;
}
gch->hit = UMIN( gch->hit + heal, get_max_hit(gch));
gch->nonlethal = UMAX(0, gch->nonlethal - heal);
affect_strip(gch,gsn_bleed_damage);
update_pos(gch,-1);
act( "{138}Your $t wounds mend and your pain ebbs.", gch, skill_table[sn].msg_off, NULL, TO_CHAR);
act( "{138}$n's $t wounds mend.", gch, skill_table[sn].msg_off, NULL, TO_ROOM);
cnt++;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_dancing_lights)
{
OBJ_DATA *light;
int cnt;
push_call("spell_dancing_lights(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (cnt = 0 ; cnt < level / 3 ; cnt++)
{
if (cnt >= 4)
break;
light = create_object( get_obj_index( OBJ_VNUM_LIGHT_BALL ), 0 );
light->timer = turn * level;
act( "Shards of iridescent light collide to form a dazzling ball.", ch, NULL, NULL, TO_CHAR );
act( "Shards of iridescent light collide to form a dazzling ball.", ch, NULL, NULL, TO_ROOM );
obj_to_char( light, ch );
cnt++;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_darkness)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
ROOM_TIMER_DATA rtd;
push_call("spell_darkness(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE) || IS_SET(victim->in_room->room_flags, ROOM_SAFE))
{
act( "Wards prevent you from casting that here.", ch, NULL, NULL, TO_CHAR );
pop_call();
return FALSE;
}
if (IS_SET(victim->in_room->room_flags, ROOM_DARK))
{
act("The room is already dark.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = victim->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_ROOM_LIGHT;
rtd.modifier = -1;
rtd.duration = level * turn;
rtd.bitvector = ROOM_DARK;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{108}A cloud of shadows fills the area.", victim, NULL, NULL, TO_ALL);
if (ch->in_room != victim->in_room)
act( "{108}A cloud of shadows fills the area around $N.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
DO_SPELL(spell_daylight)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
ROOM_TIMER_DATA rtd;
push_call("spell_daylight(%p,%p,%p,%p)",sn,level,ch,vo);
if (target == TAR_OBJ_INV)
{
if (IS_OBJ_STAT(obj, ITEM_GLOW))
{
send_to_char( "That object already glows.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = 5 * turn * level;
af.bittype = AFFECT_TO_OBJ;
af.bitvector = ITEM_GLOW;
af.location = APPLY_ROOM_LIGHT;
af.modifier = 2;
af.level = level;
affect_to_obj( ch,obj, &af);
act( "$p {138}begins to glow with a bright light.", ch, obj, NULL, TO_CHAR);
act( "$p {138}begins to glow with a bright light.", ch, obj, NULL, TO_ROOM);
}
else if (target == TAR_CHAR_DEFENSIVE)
{
if (is_room_affected(victim->in_room, gsn_blacklight)
|| is_room_affected(victim->in_room, gsn_darkness))
{
if (!ForReal)
{
pop_call();
return TRUE;
}
affect_room_strip(victim->in_room, gsn_blacklight);
affect_room_strip(victim->in_room, gsn_darkness);
}
else
{
if (IS_SET(victim->in_room->room_flags, ROOM_DAYLIGHT))
{
act("The room is already bright.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = ch->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = 5 * turn * level;
rtd.bitvector = ROOM_DAYLIGHT;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{138}The light of a noonday sun fills the area.", ch, NULL, NULL, TO_ALL);
if (ch->in_room != victim->in_room)
act( "138}The light of a noonday sun fills the area.", ch, NULL, NULL, TO_CHAR);
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_demand)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
char command[MAX_INPUT_LENGTH];
int cmd;
if (victim == ch)
{
send_to_char ("You obey your every whim!\n\r", ch);
pop_call();
return FALSE;
}
if (!is_string(target_name))
{
act("Demand $N to what?", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (IS_AFFECTED(victim, AFF_DOMINATE))
{
act("$N is already mind controlled.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
one_argument(target_name, command);
SET_BIT(victim->affected_by, AFF_DOMINATE);
if ((cmd = find_command(command, get_trust(victim))) == -1)
{
act ("$N can't do that!", ch, NULL, victim, TO_CHAR);
REMOVE_BIT(victim->affected_by, AFF_DOMINATE);
pop_call();
return FALSE;
}
if (save_resist(ch, victim, sn, level))
{
REMOVE_BIT(victim->affected_by, AFF_DOMINATE);
pop_call();
return TRUE;
}
sprintf(command, "%s'%s'", get_color_string(ch, COLOR_SPEECH, VT102_DIM), capitalize(cmd_table[cmd].name));
act ("$n commands you, $t.", ch, command, victim, TO_VICT);
act ("You command $N, $t.", ch, command, victim, TO_CHAR);
act ("$n commands $N, $t.", ch, command, victim, TO_NOTVICT);
interpret (victim, target_name);
REMOVE_BIT(victim->affected_by, AFF_DOMINATE);
pop_call();
return TRUE;
}
DO_SPELL(spell_detect_alignment)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *rch;
AFFECT_DATA af;
push_call("spell_detect_alignment(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = level;
af.modifier = 0;
af.location = APPLY_NONE;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_join( ch, victim, &af );
if (sn == gsn_detect_chaos)
send_to_char_color( "{058}You attune yourself to entropic auras.\n\r", victim );
if (sn == gsn_detect_evil)
send_to_char_color( "{018}You attune yourself to unholy auras.\n\r", victim );
if (sn == gsn_detect_good)
send_to_char_color( "{138}You attune yourself to holy auras.\n\r", victim );
if (sn == gsn_detect_law)
send_to_char_color( "{178}You attune yourself to axiomatic auras.\n\r", victim );
for (rch = victim->in_room->first_person ; rch ; rch = rch->next)
{
if (rch == victim)
continue;
if (sn == gsn_detect_chaos && IS_CHAOTIC(rch))
{
send_to_char_color( "{058}You sense a chaotic presence nearby!\n\r", victim );
break;
}
if (sn == gsn_detect_evil && IS_EVIL(rch))
{
send_to_char_color( "{018}You sense an evil presence nearby!\n\r", victim );
break;
}
if (sn == gsn_detect_good && IS_GOOD(rch))
{
send_to_char_color( "{138}You sense a goodly presence nearby!\n\r", victim );
break;
}
if (sn == gsn_detect_law && IS_LAWFUL(rch))
{
send_to_char_color( "{178}You sense a lawful presence nearby!\n\r", victim );
break;
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_detect_poison)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
bool poisoned = FALSE;
push_call("spell_detect_poison(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (target == TAR_CHAR_DEFENSIVE)
{
if ( is_affected( victim, gsn_poison ) )
{
poisoned = TRUE;
}
if (victim->poison != NULL)
poisoned = TRUE;
if ( poisoned )
{
act( "{128}You can detect poison in $N's veins.", ch, NULL, victim, TO_CHAR );
}
else
{
act( "$N does not seem to be poisoned.", ch, NULL, victim, TO_CHAR );
}
}
else
{
if (obj->poison != NULL)
{
act( "{128}You detect poison on $p.", ch, obj, NULL, TO_CHAR );
}
else if (obj->item_type == ITEM_DRINK_CON || obj->item_type == ITEM_FOOD )
{
if ( obj->value[3] != 0 )
{
act( "{128}You detect poison on $p.", ch, obj, NULL, TO_CHAR );
}
else
{
act( "{138}$p doesn't look poisoned.", ch, obj, NULL, TO_CHAR );
}
}
else
{
act( "{138}It doesn't look poisoned.", ch, NULL, NULL, TO_CHAR );
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_detect_shapechanger)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
bool Found = FALSE;
push_call("spell_detect_shapechanger(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = turn * level;
af.modifier = 0;
af.location = APPLY_NONE;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_join( ch, victim, &af );
send_to_char_color( "{148}You attune your senses to find altered forms.\n\r", victim );
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (IS_AFFECTED(vch, AFF_NONDETECTION))
continue;
if (is_polymorph(vch)
|| rspec_req(vch, RSPEC_SHAPECHANGER))
{
send_to_char_color( "{108}You sense altered forms!\n\r", victim );
Found = TRUE;
break;
}
}
if (!Found)
send_to_char_color( "{078}You do not sense any presence here.\n\r", victim );
pop_call();
return TRUE;
}
DO_SPELL(spell_detect_undead)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
bool Found = FALSE;
push_call("spell_detect_undead(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = turn * level;
af.modifier = 0;
af.location = APPLY_NONE;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_join( ch, victim, &af );
send_to_char_color( "{148}You attune your sight to the realm of undead.\n\r", victim );
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (IS_UNDEAD(vch) && !IS_AFFECTED(vch, AFF_NONDETECTION))
{
send_to_char_color( "{108}You sense the presence of undead nearby!\n\r", victim );
Found = TRUE;
break;
}
}
if (!Found)
send_to_char_color( "{078}You do not sense an undead presence.\n\r", victim );
pop_call();
return TRUE;
}
DO_SPELL(spell_discern_location)
{
CHAR_DATA *victim;
char txt[MAX_STRING_LENGTH];
push_call("spell_discern_location(%p,%p,%p,%p)",sn,level,ch,vo);
if (*target_name == '\0')
{
send_to_char( "Who are you trying to locate?\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
*txt = '\0';
for (victim = mud->f_char ; victim ; victim = victim->next)
{
if (!can_see_world(ch, victim))
{
continue;
}
if (IS_GOD(victim))
{
continue;
}
if (!IS_NPC(victim) && !knows_char(ch, victim))
{
continue;
}
if (!is_multi_name_list_short(target_name, PERS(victim, ch)))
{
if (!is_multi_name_list_short(target_name, adjective(victim)))
{
continue;
}
}
if (!victim->in_room)
{
continue;
}
if (check_nondetection(ch, victim, gsn_discern_location))
{
continue;
}
cat_sprintf(txt, "%s is at %s in %s.\n\r", PERS(victim, ch), victim->in_room->name, victim->in_room->area->name);
break;
}
if (*txt == '\0')
{
send_to_char( "You find no one like that in hell, earth, or heaven.\n\r", ch );
}
else
{
send_to_char( txt, ch );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_disjunction)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
OBJ_DATA *obj;
AFFECT_DATA *paf, *paf_next;
int paf_type;
push_call("spell_disjunction(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{168}$n radiates a burst of antimagic energy.", ch, NULL, NULL, TO_ROOM);
act( "{168}You radiate a burst of antimagic energy.", ch, NULL, NULL, TO_CHAR);
for (vch = victim->in_room->first_person ; vch != NULL ; vch = vch_next)
{
vch_next = vch->next_in_room;
if (vch == ch)
continue;
for ( paf_type = 0, paf = vch->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (!is_spell(paf->type))
continue;
// for permanency affects, make a caster level check - Kregor
if (paf->duration >= 0)
{
if (skill_table[paf->type].msg_off)
{
act( skill_table[paf->type].msg_off, vch, NULL, NULL, TO_CHAR);
}
if (skill_table[paf->type].msg_off_room)
{
act( skill_table[paf->type].msg_off_room, vch, NULL, NULL, TO_ROOM);
}
}
else if (dice(1,20) + level < 11 + paf->level)
{
continue;
}
paf_type = paf->type;
affect_from_char(vch, paf);
}
for (obj = vch->first_carrying ; obj ; obj = obj->next_content)
{
for ( paf = obj->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (!is_spell(paf->type))
{
continue;
}
if (paf->duration >= 0)
{
if (skill_table[paf->type].msg_obj_off)
{
act( skill_table[paf->type].msg_obj_off, vch, obj, NULL, TO_CHAR);
if (vch->in_room)
act( skill_table[paf->type].msg_obj_off, vch, obj, NULL, TO_ROOM);
}
}
paf_type = paf->type;
affect_from_obj(obj, paf);
}
}
}
if (paf_type == 0)
{
send_to_char( "Nothing appears to happen.\n\r", ch );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_dispel_alignment)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_dispel_alignment(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if ((sn == gsn_dispel_evil && !IS_EVIL(victim))
|| (sn == gsn_dispel_good && !IS_GOOD(victim))
|| (sn == gsn_dispel_chaos && !IS_CHAOTIC(victim))
|| (sn == gsn_dispel_law && !IS_LAWFUL(victim)))
{
act( "$N does not seem to be affected.", ch, NULL, victim, TO_CHAR );
pop_call();
return TRUE;
}
//one spell where that numeric align scale matters! - Kregor
if (sn == gsn_dispel_good || sn == gsn_dispel_evil)
dam = abs(victim->alignment) / 10;
else
dam = abs(victim->ethos) / 10;
spell_damage( ch, victim, dam, sn, level );
pop_call();
return TRUE;
}
DO_SPELL(spell_dispel_magic)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
int paf_type, diceroll, count;
push_call("spell_dispel_magic(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (arcane_mastery(ch, SCHOOL_ABJURATION))
diceroll = UMAX(dice(1,20), dice(1,20)) + level;
else
diceroll = dice(1, 20) + level;
count = 0;
diceroll += learned(ch, gsn_focus_abj);
if (target == TAR_CHAR_DEFENSIVE)
{
if (IS_ACT(victim, ACT_SUMMONED))
{
if (victim->master && arcane_mastery(victim->master, SCHOOL_CONJURATION))
diceroll -= 4;
if (!will_save(victim, ch, diceroll, sn))
{
act("$n is returned from where $e was summoned!", victim, NULL, NULL, TO_ROOM);
act("You are returned from where you were summoned!", victim, NULL, NULL, TO_CHAR);
pop_call();
return TRUE;
}
}
for ( paf_type = 0, paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (!is_spell(paf->type))
continue;
if (sn == gsn_dispel_magic && IS_SET(paf->bitvector, AFF_CURSE))
continue;
if (!is_name(paf->caster, ch->name))
{
if (diceroll < 11 + paf->level)
{
continue;
}
}
if (paf->duration >= 0)
{
if (skill_table[paf->type].msg_off)
{
act( skill_table[paf->type].msg_off, victim, NULL, NULL, TO_CHAR);
}
if (skill_table[paf->type].msg_off_room)
{
act( skill_table[paf->type].msg_off_room, victim, NULL, NULL, TO_ROOM);
}
}
paf_type = paf->type;
affect_from_char(victim, paf);
if (sn == gsn_dispel_magic)
break;
count++;
if (count >= level/4)
break;
}
if (paf_type == 0)
{
send_to_char( "Nothing appears to happen.\n\r", ch );
}
}
else
{
for ( paf_type = 0, paf = obj->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (!is_spell(paf->type))
{
continue;
}
if (!is_name(paf->caster, ch->name))
{
if (diceroll < 11 + paf->level)
{
continue;
}
}
if (paf_type == 0 && paf->duration >= 0)
{
if (skill_table[paf->type].msg_obj_off)
{
act( skill_table[paf->type].msg_obj_off, ch, obj, NULL, TO_CHAR);
if (ch->in_room)
act( skill_table[paf->type].msg_obj_off, ch, obj, NULL, TO_ROOM);
}
}
paf_type = paf->type;
affect_from_obj(obj, paf);
if (sn == gsn_dispel_magic)
break;
count++;
if (count >= level/4)
break;
}
if (paf_type == 0)
{
send_to_char( "Nothing appears to happen.\n\r", ch );
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_disrupt_undead)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_disrupt_undead(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = spell_dice(ch, sn, 1, 6);
if (!IS_UNDEAD(victim))
{
act( "$N is not affected by your spell.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
if (save_resist(ch, victim, sn, level))
{
pop_call();
return TRUE;
}
damage( ch, victim, dam, sn, NULL );
pop_call();
return TRUE;
}
/* USED to be charm person, but is more fitting for dominate - Kregor. */
DO_SPELL(spell_dominate)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_dominate_person(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
{
send_to_char("Wards of peace prevent your spell here.\n\r", ch);
pop_call();
return FALSE;
}
if (victim == ch)
{
pop_call();
return FALSE;
}
if (is_safe(ch, victim))
{
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if ((sn == gsn_dominate_person && !IS_HUMANOID(victim))
|| (sn == gsn_dominate_animal && !IS_ANIMAL(victim))
|| domain_apotheosis(victim, DOMAIN_LIBERATION))
{
act( "$N seems to be unaffected by your magic.", ch, NULL, victim, TO_CHAR );
pop_call();
return TRUE;
}
if (IS_AFFECTED(victim, AFF_DOMINATE))
{
send_to_char( "They are already dominated.\n\r", ch );
pop_call();
return FALSE;
}
if (save_resist(ch, victim, sn, level))
{
pop_call();
return TRUE;
}
withdraw_combat(victim);
if ( victim->master )
{
stop_follower( victim );
}
add_follower( victim, ch );
af.type = sn;
af.duration = hr * level;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_DOMINATE;
af.level = level;
affect_to_char( ch, victim, &af );
act( "Isn't $n just so nice?", ch, NULL, victim, TO_VICT );
act( "$N turns to ragard you as $S master.", ch, NULL, victim, TO_CHAR );
act( "$N turns to ragard $n as $S master.", ch, NULL, victim, TO_NOTVICT );
if (who_fighting(ch) && IS_NPC(who_fighting(ch)))
{
fight(victim, who_fighting(ch));
}
pop_call();
return TRUE;
}
DO_SPELL(spell_earthquake)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
EXIT_DATA *pExit;
ROOM_TIMER_DATA rtd;
int door, temp_vnum, vict_vnum, dam;
push_call("spell_earthquake(%p,%p,%p,%p)",sn,level,ch,vo);
/*
* no earthquakes in the air
*/
if (ch->in_room->sector_type == SECT_AIR)
{
send_to_char("You cannot cast this in the air.\n\r",ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "The earth trembles beneath $N's feet!", ch, NULL, victim, TO_CHAR );
act( "The earth trembles beneath your feet!", victim, NULL, NULL, TO_CHAR );
act( "$n makes the earth tremble and shiver.", ch, NULL, NULL, TO_ROOM );
if (ch->in_room != victim->in_room)
act( "The earth trembles beneath your feet!", victim, NULL, NULL, TO_ROOM );
temp_vnum = ch->in_room->vnum;
vict_vnum = victim->in_room->vnum;
for (door = 0 ; door <= 5 ; door++)
{
if ((pExit = get_exit(vict_vnum, door)) != NULL && pExit->to_room != vict_vnum)
{
ch->in_room = room_index[pExit->to_room];
act( "The earth trembles and shivers.", ch, NULL, NULL, TO_ROOM );
}
}
ch->in_room = room_index[temp_vnum];
switch (victim->in_room->sector_type)
{
case SECT_UNDER_GROUND:
case SECT_DEEP_EARTH:
if (!IS_SET(victim->in_room->room_flags, ROOM_BLOCK))
{
rtd.vnum = victim->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = -1;
rtd.duration = -1;
rtd.bitvector = ROOM_BLOCK;
rtd.level = level;
set_room_timer(ch, &rtd);
}
act( "{108}The rocks cave in down around you!", victim, NULL, NULL, TO_ROOM);
act( "{108}The rocks cave in around the area!", victim, NULL, NULL, TO_CHAR);
break;
case SECT_MOUNTAIN:
case SECT_HILLS:
act( "{108}The rocks around you crumble in a landslide!", victim, NULL, NULL, TO_ROOM);
act( "{108}The rocks around you crumble in a landslide!", victim, NULL, NULL, TO_CHAR);
break;
case SECT_FIELD:
case SECT_FOREST:
case SECT_ROAD:
act( "{178}Large fissures open up in the ground!", victim, NULL, NULL, TO_ROOM);
act( "{178}Large fissures open up in the ground!", victim, NULL, NULL, TO_CHAR);
break;
case SECT_INSIDE:
if (!IS_SET(victim->in_room->room_flags, ROOM_BLOCK))
{
rtd.vnum = victim->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = -1;
rtd.duration = -1;
rtd.bitvector = ROOM_BLOCK;
rtd.level = level;
set_room_timer(ch, &rtd);
}
act( "{178}The ceiling above you collapses!", victim, NULL, NULL, TO_ROOM);
act( "{178}The ceiling above you collapses!", victim, NULL, NULL, TO_CHAR);
break;
case SECT_CITY:
act( "{178}Rubble crumbles from the buildings above you!", victim, NULL, NULL, TO_ROOM);
act( "{178}Rubble crumbles from the buildings above you!", victim, NULL, NULL, TO_CHAR);
break;
case SECT_LAKE:
case SECT_RIVER:
case SECT_OCEAN:
act( "{168}The water churns around you in waves!", victim, NULL, NULL, TO_ROOM);
act( "{168}The water churns around you in waves!", victim, NULL, NULL, TO_CHAR);
break;
}
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (vch == ch)
continue;
if (!can_mass_cast(ch, vch, sn))
continue;
if (vch->in_room->sector_type == SECT_UNDER_GROUND
|| vch->in_room->sector_type == SECT_DEEP_EARTH
|| vch->in_room->sector_type == SECT_MOUNTAIN
|| vch->in_room->sector_type == SECT_HILLS
|| vch->in_room->sector_type == SECT_CITY
|| vch->in_room->sector_type == SECT_INSIDE)
{
dam = spell_dice(ch, sn, 8, 6);
if (!refl_save(vch, NULL, 15, -1))
{
damage(ch, vch, dam, sn, NULL);
update_pos(vch, POS_RESTING);
}
else
{
damage(ch, vch, dam/2, sn, NULL);
}
}
if (vch->in_room->sector_type == SECT_FIELD
|| vch->in_room->sector_type == SECT_FOREST
|| vch->in_room->sector_type == SECT_ROAD)
{
if (IS_FLYING(vch))
{
continue;
}
if (!refl_save(vch, NULL, 15, -1))
{
update_pos(vch, POS_RESTING);
}
if (number_percent() < 25)
{
act( "$N {118}falls into a fissure as it closes, crushing $M!", ch, NULL, vch, TO_NOTVICT);
act( "$N {118}falls into a fissure as it closes, crushing $M!", ch, NULL, vch, TO_CHAR);
act( "{118}You fall into a fissure as it closes, crushing you!", ch, NULL, vch, TO_VICT);
if (!refl_save(vch, NULL, 20, -1))
damage(ch, vch, 10 * level, sn, NULL);
else
damage(ch, vch, dice(3,6)+level, sn, NULL);
}
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_electric_jolt)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_electric_jolt(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{178}A tiny jolt of energy shoots from $n's hand.", ch, NULL, NULL, TO_ROOM );
act( "{178}A tiny jolt of energy shoots from your hand.", ch, NULL, NULL, TO_CHAR );
dam = spell_dice(ch, sn, 1,4) + UMIN(level/2, 5);
spell_damage(ch, victim, dam, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_ray_of_frost)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_ray_of_frost(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{168}A tiny ray of cold shoots from $n's hand.", ch, NULL, NULL, TO_ROOM );
act( "{168}A tiny ray of cold shoots from your hand.", ch, NULL, NULL, TO_CHAR );
dam = spell_dice(ch, sn, 1,4) + UMIN(level/2, 5);
spell_damage(ch, victim, dam, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_flame_tongue)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_flame_tongue(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{118}A tiny blast of fire shoots from $n's finger.", ch, NULL, NULL, TO_ROOM );
act( "{118}A tiny blast of fire shoots from your finger.", ch, NULL, NULL, TO_CHAR );
dam = spell_dice(ch, sn, 1,4) + UMIN(level/2, 5);
spell_damage(ch, victim, dam, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_endure_elements)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
int resist;
push_call("spell_endure_elements(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
resist = 5;
af.type = sn;
af.duration = UMIN(2 * level * hr, 24);
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_DR_COLD;
af.modifier = resist;
affect_join( ch, victim, &af );
af.location = APPLY_DR_FIRE;
af.modifier = resist;
affect_join( ch, victim, &af );
act( "{138}A minor ward against the elements surrounds $n's body.", victim, NULL, NULL, TO_ROOM );
act( "{138}A minor ward against the elements surrounds your body.", victim, NULL, NULL, TO_CHAR );
pop_call();
return TRUE;
}
DO_SPELL(spell_enervation)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_enervation(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (save_resist(ch, victim, sn, level))
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = UMIN(hr * level, 15);
af.modifier = 0 - dice(1, 4);
af.location = APPLY_LEVEL;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.level = level;
affect_join( ch, victim, &af );
act( "{108}$N wails as the life force is drawn from him!", victim, NULL, NULL, TO_ROOM);
act( "{108}You wail as your life force is drawn from you!", victim, NULL, NULL, TO_CHAR);
update_pos(victim,-1);
pop_call();
return TRUE;
}
DO_SPELL(spell_energy_drain)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_energy_drain(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (save_resist(ch, victim, sn, level))
{
pop_call();
return TRUE;
}
af.type = gsn_drain;
af.duration = -1;
af.modifier = 0 - dice(2, 4);
af.location = APPLY_LEVEL;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.level = level;
affect_join( ch, victim, &af );
act( "{108}$N wails as the life force is drawn from him!", victim, NULL, NULL, TO_ROOM);
act( "{108}You wail as your life force is drawn from you!", victim, NULL, NULL, TO_CHAR);
update_pos(victim,-1);
pop_call();
return TRUE;
}
DO_SPELL(spell_entangle)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
ROOM_TIMER_DATA rtd;
push_call("spell_entangle(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(victim->in_room->room_flags, ROOM_ENTANGLE))
{
send_to_char("This area is already affected.\n\r", ch );
pop_call();
return FALSE;
}
if (IS_SET(victim->in_room->room_flags, ROOM_SAFE))
{
send_to_char( "The plants here refuse to be beguiled.\n\r", ch );
pop_call();
return FALSE;
}
switch (victim->in_room->sector_type)
{
case SECT_FIELD:
case SECT_FOREST:
case SECT_HILLS:
case SECT_MOUNTAIN:
case SECT_SWAMP:
case SECT_BEACH:
break;
default:
send_to_char("That cannot be cast here.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = victim->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = turn * level;
rtd.bitvector = ROOM_ENTANGLE;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{128}Plant life begins to grow and flail around you!", victim, NULL, NULL, TO_CHAR);
act( "{128}Plant life begins to grow and flail around you!", victim, NULL, NULL, TO_ROOM);
if (ch->in_room != victim->in_room)
{
act( "{128}Plant life begins to grow and flail around $N!", ch, NULL, victim, TO_CHAR);
}
pop_call();
return TRUE;
}
/*
* Eyebite spell worth the effort to do it standalone
* in order to do it right - Kregor
*/
DO_SPELL(spell_eyebite)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
int victsave, duration;
push_call("spell_eyebite(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{118}$n gazes at $N with an evil eye!", ch, NULL, victim, TO_NOTVICT );
act( "{118}$n gazes at you with an evil eye!", ch, NULL, NULL, TO_VICT );
if (!CAN_CRITICAL(victim) || (victsave = save_resist(ch, victim, sn, level)) == TRUE)
{
act( "{118}$N is unaffected by your evil eye.", ch, NULL, NULL, TO_CHAR );
pop_call();
return TRUE;
}
if (victsave == PARTIAL)
{
duration = dice(2,4);
}
else
{
duration = level * turn;
}
act( "{118}You gaze at $N with an evil eye!", ch, NULL, NULL, TO_CHAR );
if (victim->level <= 4 && !is_immune(victim, SDESC_PARALYSIS))
{
af.type = sn;
af.duration = duration;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_PARALYSIS;
af.level = level;
affect_join( ch, victim, &af );
}
if ((victim->level >= 5 || victim->level <= 9) && !is_immune(victim, SDESC_FEAR))
{
af.type = sn;
af.duration = duration;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_FEAR;
af.location = APPLY_NONE;
af.modifier = victsave ? 1 : 3;
af.level = level;
affect_join( ch, victim, &af);
victim->fear_level = af.modifier;
if (!victsave)
act( "You become filled with fear!", victim, NULL, NULL, TO_CHAR );
else
act( "You become shaken!", victim, NULL, NULL, TO_CHAR );
if (in_combat(victim))
{
do_withdraw(victim, NULL);
}
}
af.type = sn;
af.duration = duration;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_SICKENED;
af.level = level;
affect_join( ch, victim, &af );
pop_call();
return TRUE;
}
DO_SPELL(spell_faerie_fire)
{
CHAR_DATA *vch;
AFFECT_DATA af;
push_call("spell_faerie_fire(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for ( vch = ch->in_room->first_person; vch != NULL; vch = vch->next_in_room )
{
if ( !IS_NPC(vch) && IS_SET(vch->act, PLR_WIZINVIS) )
continue;
if ( !IS_NPC(vch) && IS_SET(vch->act, PLR_WIZCLOAK) )
continue;
if( IS_NPC(vch) && IS_SET(vch->act, ACT_MOBINVIS) )
continue;
if (vch == ch)
continue;
if (save_resist(ch, vch, sn, level))
continue;
af.type = sn;
af.duration = turn * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_join( ch, vch, &af );
act( "{158}$n is surrounded by a pink outline.", vch, NULL, NULL, TO_ROOM );
act( "{158}You are surrounded by a pink outline.", vch, NULL, NULL, TO_CHAR );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_faithful_hound)
{
ROOM_INDEX_DATA *room;
ROOM_TIMER_DATA rtd;
push_call("spell_faithful_hound(%p,%p,%p,%p)",sn,level,ch,vo);
if (ch->in_room == NULL)
{
pop_call();
return FALSE;
}
room = ch->in_room;
if (is_room_affected(room, gsn_faithful_hound))
{
send_to_char( "There is already a spectral hound here.\n\r", ch );
pop_call();
return FALSE;
}
if (room->area->low_r_vnum == ROOM_VNUM_ARENA)
{
send_to_char("You may not conjure your hound here.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = hr * level;
rtd.bitvector = 0;
rtd.level = level;
set_room_timer(ch, &rtd);
send_to_char("{108}You conjure up an spectral watchdog to guard you.\n\r", ch);
pop_call();
return TRUE;
}
/*
* Function for the Faith Hammer alignment spells:
* Chaos Hammer, Holy Smite, Order's Wrath and Unholy Blight
* all pass thru this - Kregor
*/
DO_SPELL(spell_faith_hammer)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int vchsave, dam, dam1, dam2;
bool ethos = FALSE;
char name[20];
push_call("faith_hammer(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (sn == gsn_unholy_blight)
{
act( "{108}$n unleashes a cold miasma of darkness!", ch, NULL, NULL, TO_ROOM );
act( "{108}You unleash a cold miasma of darkness!", ch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_orders_wrath)
{
act( "{138}$n unleashes a three-dimensional grid of energy!", ch, NULL, NULL, TO_ROOM );
act( "{138}You unleash a three-dimensional grid of energy!", ch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_holy_smite)
{
act( "{178}$n unleashes a purifying sphere of light!", ch, NULL, NULL, TO_ROOM );
act( "{178}You unleash a purifying sphere of light!", ch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_chaos_hammer)
{
act( "{158}$n unleashes an explosion of leaping energy bolts!", ch, NULL, NULL, TO_ROOM );
act( "{158}You unleash an explosion of leaping energy bolts!", ch, NULL, NULL, TO_CHAR );
}
strcpy(name, skill_table[sn].name);
dam1 = spell_dice(ch, sn, UMIN(level/2, 5), 8);
dam2 = spell_dice(ch, sn, UMIN(level, 10), 8);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if ((sn == gsn_unholy_blight && IS_EVIL(vch))
|| (sn == gsn_holy_smite && IS_GOOD(vch))
|| (sn == gsn_chaos_hammer && IS_CHAOTIC(vch))
|| (sn == gsn_orders_wrath && IS_LAWFUL(vch)))
continue;
if (sn == gsn_orders_wrath && sn == gsn_chaos_hammer)
ethos = TRUE;
if (race_type(vch) == RTYPE_OUTSIDER)
dam = dam2;
else
dam = dam1;
if (ethos && IS_UNCONCERNED(vch))
dam /= 2;
else if (IS_NEUTRAL(vch))
dam /= 2;
if ((vchsave = save_resist(ch, vch, sn, level)) == TRUE)
{
continue;
}
else if (vchsave == PARTIAL)
{
damage(ch, vch, dam/2, sn, NULL);
continue;
}
else
{
damage(ch, vch, dam, sn, NULL);
}
if (!valid_fight(ch, vch))
continue;
if ((ethos && IS_UNCONCERNED(vch)) || IS_NEUTRAL(vch))
continue;
af.type = sn;
af.duration = dice(1,6);
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
if (sn == gsn_unholy_blight)
af.bitvector = AFF2_SICKENED;
else if (sn == gsn_chaos_hammer)
af.bitvector = AFF2_STAGGERED;
else if (sn == gsn_orders_wrath)
af.bitvector = AFF2_DAZED;
else
af.bitvector = AFF_BLIND;
af.level = level;
affect_join( ch, vch, &af );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_farheal)
{
CHAR_DATA *victim;
int heal;
push_call("spell_farheal(%p,%p,%p,%p)",sn,level,ch,vo);
if ((victim = get_player_world(ch, target_name)) == NULL)
{
send_to_char("Farheal who ?\n\r", ch);
pop_call();
return FALSE;
}
if (victim->in_room == NULL
|| IS_SET(victim->in_room->room_flags, ROOM_PRIVATE)
|| IS_SET(victim->in_room->room_flags, ROOM_SOLITARY)
|| victim->in_room->sector_type == SECT_ETHEREAL
|| victim->in_room->sector_type == SECT_ASTRAL
|| ch->in_room->sector_type == SECT_ETHEREAL
|| ch->in_room->sector_type == SECT_ASTRAL
|| IS_NPC(victim))
{
act("You can not reach $N through the void.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (victim == ch)
{
send_to_char("You can't farheal yourself!\n\r", ch);
pop_call();
return FALSE;
}
if (victim->in_room == ch->in_room)
{
ch_printf_color(ch, "%s is in the same room as you!\n\r",
get_name(victim));
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
heal = UMIN(level * 10, 200);
if (is_affected(ch, gsn_festering_wounds))
heal /= 2;
victim->hit = UMIN( victim->hit + heal, get_max_hit(victim) );
update_pos(victim,-1);
act( "{138}$n reaches through the void to fill you with healing energy.", ch, NULL, victim, TO_VICT );
act( "{138}$n's wounds spontaneously heal!", victim, NULL, NULL, TO_ROOM );
act ("{138}You reach through the void to $N, filling $M with healing energy.", ch, NULL, victim, TO_CHAR );
pop_call();
return TRUE;
}
DO_SPELL(spell_fatigue)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch;
int cnt;
push_call("spell_fatigue(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (cnt = 0, vch = victim->in_room->first_person ; vch ; vch = vch->next_in_room)
{
if (sn == gsn_touch_of_fatigue && victim != vch)
continue;
if (!is_same_group(vch, victim))
continue;
if (cnt >= level)
continue;
if (save_resist(ch, victim, sn, level))
continue;
if (sn == gsn_waves_of_exhaustion)
{
vch->move = 0;
act( "{108}$n suddenly looks exhausted.", vch, NULL, NULL, TO_ROOM );
act( "{108}You feel totally exhausted.", vch, NULL, NULL, TO_CHAR );
}
else if (sn == gsn_waves_of_fatigue)
{
vch->move -= (vch->move / 3 * 2 + 1);
act( "{108}$n suddenly looks fatigued.", vch, NULL, NULL, TO_ROOM );
act( "{108}You feel fatigued.", vch, NULL, NULL, TO_CHAR );
}
else
{
vch->move -= (vch->move / 3 + 1);
act( "{108}$n looks a bit less energetic.", vch, NULL, NULL, TO_ROOM );
act( "{108}You feel more tired.", vch, NULL, NULL, TO_CHAR );
}
cnt++;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_finger_of_death)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam = 0;
int save;
push_call("spell_finger_of_death(%p,%p,%p,%p)",sn,level,ch,vo);
if (victim == ch)
{
send_to_char_color("You shouldn't point at yourself with that!", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{118}You point a finger at $N...", ch, NULL, victim, TO_CHAR );
act( "{118}$n points a finger at you...", ch, NULL, victim, TO_VICT );
act( "{118}$n points a finger at $N...", ch, NULL, victim, TO_NOTVICT );
if ((save = save_resist(ch, victim, sn, level)) == -1)
{
dam = spell_dice(ch, sn, 3, 6) + level;
}
else if (!save)
{
dam = level * 10;
}
else
{
pop_call();
return TRUE;
}
damage(ch, victim, dam, sn, NULL);
pop_call();
return TRUE;
}
DO_SPELL(spell_fireball)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int diceroll;
push_call("spell_fireball(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
diceroll = spell_dice(ch, sn, UMIN(level, 10), 6);
spell_damage(ch, victim, diceroll, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_firestorm)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
EXIT_DATA *pExit;
int door, temp_vnum, dam;
push_call("spell_firestorm(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{118}Sheets of fire and flame spew forth by your command!", ch, NULL, NULL, TO_CHAR);
act( "{118}Sheets of fire and flame spew forth by $n's command.", ch, NULL, NULL, TO_ROOM);
temp_vnum = ch->in_room->vnum;
for (door = 0 ; door <= 5 ; door++)
{
if ((pExit = get_exit(temp_vnum, door)) && pExit->to_room != temp_vnum)
{
ch->in_room = room_index[pExit->to_room];
act( "{118}The air about you sears with heat.", ch, NULL, NULL, TO_ROOM);
}
}
ch->in_room = room_index[temp_vnum];
dam = spell_dice(ch, sn, UMIN(level, 20), 6);
spell_damage(ch, victim, dam, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_flame_arrow)
{
OBJ_DATA *obj;
AFFECT_DATA af;
push_call("spell_flame_arrow(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (obj = ch->first_carrying ; obj ; obj = obj->next_content)
{
if (obj->item_type != ITEM_AMMO || IS_OBJ_STAT(obj, ITEM_MAGIC) || obj->first_affect != NULL)
continue;
if (IS_SET(obj->value[1], WFLAG_FLAMING))
continue;
act( "{118}Flames ignite from $p.", ch, obj, NULL, TO_CHAR);
act( "{118}Flames ignite from $p.", ch, obj, NULL, TO_ROOM);
af.type = sn;
af.duration = turn * level;
af.location = APPLY_WEAPON_FLAG;
af.modifier = WFLAG_FLAMING;
af.bittype = AFFECT_TO_OBJ;
af.bitvector = ITEM_MAGIC;
af.level = level;
affect_to_obj( ch,obj, &af);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_flame_blade)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
push_call("spell_flame_blade(%p,%p,%p,%p)",sn,level,ch,vo);
if (obj->item_type != ITEM_WEAPON)
{
act( "You can only imbue weapons with fire.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (IS_SET(obj->value[1], WFLAG_FLAMING))
{
act( "$p is already burning.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{118}Flames ignite from $p.", ch, obj, NULL, TO_CHAR);
act( "{118}Flames ignite from $p.", ch, obj, NULL, TO_ROOM);
af.type = sn;
af.duration = turn*level;
af.location = APPLY_WEAPON_FLAG;
af.modifier = WFLAG_FLAMING;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_to_obj( ch,obj, &af);
pop_call();
return TRUE;
}
DO_SPELL(spell_keen_edge)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
push_call("spell_keen_edge(%p,%p,%p,%p)",sn,level,ch,vo);
if (obj->item_type != ITEM_WEAPON)
{
act( "You can only give weapons a keen edge", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (IS_SET(obj->value[1], WFLAG_KEEN))
{
act( "$p is already keen.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
switch (weapon_table[obj->value[0]].dam_type)
{
case WEAPON_SLASH:
case WEAPON_PIERCE:
case WEAPON_PIERCE_SLASH:
break;
default:
act( "$p is not an edged weapon.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{178}The edge on $p grows sharper!", ch, obj, NULL, TO_CHAR);
af.type = sn;
af.duration = turn*level;
af.location = APPLY_WEAPON_FLAG;
af.modifier = WFLAG_KEEN;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_to_obj( ch,obj, &af);
pop_call();
return TRUE;
}
DO_SPELL(spell_flamestrike)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int diceroll;
push_call("spell_flamestrike(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
diceroll = spell_dice(ch, sn, UMIN(level, 15), 6);
act( "$n {118}calls down a column of divine fury and fire!", ch, NULL, NULL, TO_ROOM);
act( "{118}You call down a column of divine fury and fire!", ch, NULL, NULL, TO_CHAR);
spell_damage(ch, victim, diceroll, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_fly)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_fly(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if ( is_affected(victim, sn) )
{
act( "{168}$n's power of flight renews.", victim, NULL, NULL, TO_ROOM );
act( "{168}Your power of flight renews.", victim, NULL, NULL, TO_CHAR );
}
else
{
act( "{168}Your feet rise off the ground.", victim, NULL, NULL, TO_CHAR );
act( "{168}$n's feet rise off the ground.", victim, NULL, NULL, TO_ROOM );
}
af.type = sn;
af.duration = turn * level;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_FLYING;
af.level = level;
affect_join( ch, victim, &af );
pop_call();
return TRUE;
}
DO_SPELL(spell_floating_disc)
{
AFFECT_DATA af;
push_call("spell_floating_disc(%p,%p,%p,%p)",sn,level,ch,vo);
if (is_affected(ch, sn))
{
act( "You can only have one floating disc at once.", ch, NULL, NULL, TO_CHAR );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
{
act( "{158}A floating disc of force materializes before $n.", ch, NULL, NULL, TO_ROOM );
act( "{158}A floating disc of force materializes before you.", ch, NULL, NULL, TO_CHAR );
}
af.type = sn;
af.duration = hr * level;
af.modifier = 0;
af.location = APPLY_NONE;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_join( ch, ch, &af );
pop_call();
return TRUE;
}
DO_SPELL(spell_fog_cloud)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
ROOM_TIMER_DATA rtd;
ROOM_INDEX_DATA *room;
push_call("spell_fog_cloud(%p,%p,%p,%p)",sn,level,ch,vo);
if( victim->in_room == NULL )
{
pop_call();
return FALSE;
}
room = victim->in_room;
if( IS_SET(room->room_flags, ROOM_FOG ) )
{
send_to_char( "The room is already foggy.\n\r", ch );
pop_call();
return FALSE;
}
if( IS_SET(room->room_flags, ROOM_SAFE ) )
{
send_to_char("Wards of peace prevent you from doing that.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = turn * level;
rtd.bitvector = ROOM_FOG;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{108}A dark cloud of fog suddenly rolls in...", victim, NULL, NULL, TO_ALL );
if (room != ch->in_room)
act( "{108}You conjure up a dark cloud of fog!", ch, NULL, NULL, TO_CHAR );
pop_call();
return TRUE;
}
DO_SPELL(spell_forceful_hand)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
EXIT_DATA *pExit;
ROOM_INDEX_DATA *to_room;
int check, dir;
push_call("spell_forceful_hand(%p,%p,%p,%p)",sn,level,ch,vo);
if (victim == ch)
{
send_to_char_color("You can't heavy hand yourself.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if ((check = combat_maneuver_check(ch, victim, sn)) >= 10)
{
act("A giant hand shoves you away from $n!", ch, NULL, victim, TO_VICT);
act("A giant hand shoves $N away from $n!", ch, NULL, victim, TO_NOTVICT);
act("A giant hand shoves $N away from you!", ch, NULL, victim, TO_CHAR);
for (dir = 0 ; dir <= 5 ; dir++)
{
if ((pExit = get_exit(ch->in_room->vnum, dir)) == NULL
|| (to_room = room_index[pExit->to_room]) == NULL)
{
continue;
}
if (can_move_char(ch, dir))
{
char_from_room(victim);
char_to_room(victim, to_room->vnum, TRUE);
act( "$N is shoved in from $T by a large hand!", ch, rev_dir_name[dir], victim, TO_NOTVICT);
break;
}
}
if (in_same_room(ch, victim))
{
damage(ch, victim, dice(1,8)+8, sn, NULL);
}
update_pos(victim, POS_RESTING);
}
else if (check >= 0)
{
act("A giant hand shoves you away from $n!", ch, NULL, victim, TO_VICT);
act("A giant hand shoves $N away from $n!", ch, NULL, victim, TO_NOTVICT);
act("A giant hand shoves $N away from you!", ch, NULL, victim, TO_CHAR);
victim->distracted = 2;
update_pos(victim, POS_RESTING);
}
else
{
act("A giant hand tries to shove you away, and fails.", ch, NULL, victim, TO_VICT);
act("A giant hand tries to shove $N, and fails.", ch, NULL, victim, TO_NOTVICT);
act("A giant hand tries to shove $N, and fails.", ch, NULL, victim, TO_CHAR);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_gate)
{
MOB_INDEX_DATA *pMob;
CHAR_DATA *mh;
bool fMatch;
int cnt, count, hitdice, rdm, race;
push_call("spell_gate(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
{
send_to_char("Wards bar your summoning spell.\n\r", ch);
pop_call();
return FALSE;
}
// if (ch->gold < 1000000)
// {
// act("You do not have enough gold to sacrifice for this spell.", ch, NULL, NULL, TO_CHAR);
// pop_call();
// return FALSE;
// }
//
if (!ForReal)
{
pop_call();
return TRUE;
}
for (cnt = race = 0 ; race < MAX_RACE ; race++)
{
if (race_table[race].type != RTYPE_OUTSIDER)
continue;
if (!IS_SET(race_table[race].flags, RSPEC_GOOD) && IS_GOOD(ch))
continue;
if (!IS_SET(race_table[race].flags, RSPEC_EVIL) && IS_EVIL(ch))
continue;
if (race_table[race].hit_dice > level)
continue;
cnt++;
fMatch = TRUE;
}
if (!fMatch)
{
act( "You can't seem to summon forth an ally.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
rdm = number_range(1, cnt);
for (cnt = race = 0 ; race < MAX_RACE ; race++)
{
if (race_table[race].type != RTYPE_OUTSIDER)
continue;
if (!IS_SET(race_table[race].flags, RSPEC_GOOD) && IS_GOOD(ch))
continue;
if (!IS_SET(race_table[race].flags, RSPEC_EVIL) && IS_EVIL(ch))
continue;
if (race_table[race].hit_dice > level)
continue;
if (cnt++ == rdm)
break;
}
hitdice = race_table[race].hit_dice;
count = level / hitdice;
pMob = get_mob_index(MOB_VNUM_SUMMONS);
while (count)
{
mh = create_mobile(pMob);
char_to_room( mh, ch->in_room->vnum, TRUE );
mh->race = race;
mh->level = race_table[race].hit_dice;
mh->perm_str = 10 + race_table[race].race_mod[0];
mh->perm_dex = 10 + race_table[race].race_mod[1];
mh->perm_con = 10 + race_table[race].race_mod[2];
mh->perm_int = 10 + race_table[race].race_mod[3];
mh->perm_wis = 10 + race_table[race].race_mod[4];
mh->perm_cha = 10 + race_table[race].race_mod[5];
mh->size = race_table[race].size;
mh->height = race_table[race].height;
mh->weight = race_table[race].weight;
mh->speak = race_table[race].speaks;
mh->language = race_table[race].understands;
mh->alignment = race_table[race].alignment;
mh->ethos = race_table[race].ethos;
mh->max_hit = dice(mh->level, race_type_table[race_table[race].type].hit_die);
mh->max_hit = UMAX(mh->level * race_type_table[race_table[race].type].hit_die / 2, mh->max_hit);
mh->hit = get_max_hit(mh);
RESTRING(mh->name, format("summoned %s", race_table[race].race_name));
RESTRING(mh->short_descr, format("a summoned %s", race_table[race].race_name));
RESTRING(mh->long_descr, format("A summoned %s is here.", race_table[race].race_name));
mh->npcdata->sac_timer = turn * level;
if (!IS_EVIL(mh))
{
mh->npcdata->sac_string = STRALLOC("{178}$n shimmers and vanishes!");
act( "{178}$n appears in a shimmer of light.", mh, NULL, NULL, TO_ALL);
}
else
{
mh->npcdata->sac_string = STRALLOC("{108}$n vanishes in a puff black smoke!");
act( "{118}$n appears in a burst of hellish flames!", mh, NULL, NULL, TO_ALL);
}
char_reset(mh);
if (!will_save(mh, ch, level, gsn_gate))
{
SET_BIT(mh->affected_by , AFF_DOMINATE);
// add_follower(mh, ch);
if (who_fighting(ch))
fight(mh, who_fighting(ch));
}
else
{
act("Unmoved by your pleas, $N returns through the gate.", ch, NULL, mh, TO_ALL);
junk_mob(mh);
}
--count;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_grasping_hand)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_grasping_hand(%p,%p,%p,%p)",sn,level,ch,vo);
if (victim == ch)
{
send_to_char_color("You can't heavy hand yourself.\n\r", ch);
pop_call();
return FALSE;
}
if (victim->grappling || victim->grappled_by
|| is_affected(victim, gsn_crushing_hand) || is_affected(victim, gsn_grasping_hand))
{
act("$N is already grappling.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (IS_AFFECTED(victim, AFF_FREEDOM))
{
act("You slip past a giant hand's grasp!", victim, NULL, NULL, TO_VICT);
act("$n slips past a giant hand's grasp!", victim, NULL, NULL, TO_ROOM);
pop_call();
return TRUE;
}
if (combat_maneuver_check(ch, victim, sn) >= 0)
{
act("A giant hand grasps you firmly!", victim, NULL, NULL, TO_CHAR);
act("A giant hand grasps $N firmly!", victim, NULL, NULL, TO_ROOM);
if (sn == gsn_crushing_hand)
{
damage(ch, victim, dice(2,6)+12, sn, NULL);
}
}
if (!valid_fight(ch, victim))
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = level;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_join( ch, victim, &af );
pop_call();
return TRUE;
}
DO_SPELL(spell_harden)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
push_call("spell_harden(%p,%p,%p,%p)",sn,level,ch,vo);
if (target == TAR_CHAR_DEFENSIVE)
{
if (race_type(victim) != RTYPE_CONSTRUCT)
{
act("$N is not a construct.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (is_affected(victim, gsn_harden))
{
act("$N is already hardened.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{178}Your defenses are further hardened.", victim, NULL, NULL, TO_CHAR);
act( "{178}$n's defenses are further hardened.", victim, NULL, NULL, TO_ROOM);
af.type = sn;
af.duration = turn * level;
af.location = APPLY_DR_NONE;
af.modifier = level/2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.level = level;
affect_to_char( ch, victim, &af );
}
else if (target == TAR_OBJ_INV)
{
if (is_obj_affected(obj, gsn_harden))
{
act( "$p is already hardened.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = -1;
af.location = APPLY_NONE;
af.modifier = level/2;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_to_obj( ch, obj, &af );
act( "$p becomes more resilient.", ch, obj, NULL, TO_CHAR);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_harm)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_harm(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = 10 * UMIN(level, 15);
if (IS_UNDEAD(victim))
{
victim->hit = UMIN( victim->hit + dam, get_max_hit(victim));
update_pos(victim,-1);
act( "{138}A healing energy fills your body.", victim, NULL, NULL, TO_CHAR);
act( "{138}A healing energy fills $N's body.", victim, NULL, NULL, TO_ROOM);
}
else
{
spell_damage( ch, victim, dam, sn, level );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_heal)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
DISEASE_DATA *dis, *dis_next;
int heal;
push_call("spell_heal(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
heal = 10 * UMIN(level, 15);
if (is_affected(victim, gsn_festering_wounds))
heal /= 2;
if (IS_UNDEAD(victim))
{
spell_damage( ch, victim, heal, sn, level );
}
else
{
act( "{138}A healing energy fills your body.", victim, NULL, NULL, TO_CHAR);
act( "{138}A healing energy fills $n's body.", victim, NULL, NULL, TO_ROOM);
for ( paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (IS_SET(paf->bitvector, AFF_BLIND|AFF_DEAF|AFF_POISON))
{
affect_strip(victim,paf->type);
}
else if (IS_SET(paf->bitvector, AFF2_CONFUSION|AFF2_DAZED|AFF2_DAZZLED|AFF2_DROWNING|AFF2_NAUSEATED|AFF2_SICKENED|AFF2_STUNNED))
{
affect_strip(victim,paf->type);
}
switch (paf->location)
{
case APPLY_STR_DAMAGE:
case APPLY_DEX_DAMAGE:
case APPLY_CON_DAMAGE:
case APPLY_INT_DAMAGE:
case APPLY_WIS_DAMAGE:
case APPLY_CHA_DAMAGE:
affect_strip(victim,paf->type);
break;
}
}
affect_strip(victim,gsn_bleed_damage);
affect_strip(victim,gsn_poison);
affect_strip( victim, gsn_feeblemind );
affect_strip( victim, gsn_festering_wounds );
if (victim->poison != NULL)
{
POISON_DATA *npd, *pd;
pd = victim->poison;
victim->poison = NULL;
while (pd != NULL)
{
npd = pd->next;
FREEMEM( pd );
pd = npd;
}
}
for ( dis = victim->first_disease; dis != NULL; dis = dis_next )
{
dis_next = dis->next;
disease_from_char(ch, dis);
}
if (domain_apotheosis(ch, DOMAIN_HEALING))
{
victim->hit = get_max_hit(victim);
victim->nonlethal = 0;
}
else
{
victim->hit = UMIN( victim->hit + heal, get_max_hit(victim));
victim->nonlethal = UMAX(0, victim->nonlethal - heal);
}
victim->move = get_max_move(victim);
update_pos(victim,-1);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_mass_heal)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
DISEASE_DATA *dis, *dis_next;
CHAR_DATA *gch, *gch_next;
int heal, cnt;
push_call("spell_mass_heal(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
heal = 10 * UMIN(level, 25);
for (cnt = 0, gch = victim->in_room->first_person ; gch ; gch = gch_next)
{
gch_next = gch->next_in_room;
if (IS_UNDEAD(gch))
{
if (!can_mass_cast(ch, gch, sn))
{
continue;
}
if (cnt >= level)
{
break;
}
spell_damage( ch, gch, heal, sn, level );
cnt++;
continue;
}
if (!is_same_group(gch, victim))
{
continue;
}
if (cnt >= level)
{
break;
}
act( "{138}A healing energy fills your body.", gch, NULL, NULL, TO_CHAR);
act( "{138}A healing energy fills $n's body.", gch, NULL, NULL, TO_ROOM);
for ( paf = gch->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (IS_SET(paf->bitvector, AFF_BLIND|AFF_DEAF|AFF_POISON))
{
affect_strip(victim,paf->type);
}
else if (IS_SET(paf->bitvector, AFF2_CONFUSION|AFF2_DAZED|AFF2_DAZZLED|AFF2_NAUSEATED|AFF2_SICKENED|AFF2_STUNNED|AFF2_DROWNING))
{
affect_strip(victim,paf->type);
}
switch (paf->location)
{
case APPLY_STR_DAMAGE:
case APPLY_DEX_DAMAGE:
case APPLY_CON_DAMAGE:
case APPLY_INT_DAMAGE:
case APPLY_WIS_DAMAGE:
case APPLY_CHA_DAMAGE:
affect_strip(gch,paf->type);
break;
}
}
affect_strip(gch,gsn_bleed_damage);
affect_strip(gch,gsn_poison);
affect_strip( gch, gsn_feeblemind );
affect_strip( gch, gsn_festering_wounds );
if (gch->poison != NULL)
{
POISON_DATA *npd, *pd;
pd = gch->poison;
while (pd != NULL)
{
npd = pd->next;
FREEMEM( pd );
pd = npd;
}
}
for ( dis = gch->first_disease; dis != NULL; dis = dis_next )
{
dis_next = dis->next;
disease_from_char(gch, dis);
}
gch->hit = UMIN( gch->hit + heal, get_max_hit(gch));
gch->nonlethal = UMAX(0, gch->nonlethal - heal);
gch->move = get_max_move(gch);
cnt++;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_heal_mount)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
DISEASE_DATA *dis, *dis_next;
int heal;
push_call("spell_heal_mount(%p,%p,%p,%p)",sn,level,ch,vo);
if (!IS_ACT(victim, ACT_WARHORSE) || !is_master(victim, ch))
{
act("You can only use this spell on your divine mount.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
heal = 10 * UMIN(level, 15);
act( "{138}You channel energy to heal your mount.", ch, NULL, NULL, TO_CHAR);
act( "{138}$N channels energy to heal $s mount.", ch, NULL, NULL, TO_ROOM);
for ( paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (IS_SET(paf->bitvector, AFF_BLIND|AFF2_CONFUSION|AFF2_DAZED|AFF2_DAZZLED|AFF_DEAF|AFF_POISON))
{
affect_strip(victim,paf->type);
}
else if (IS_SET(paf->bitvector, AFF2_NAUSEATED|AFF2_SICKENED|AFF2_STUNNED))
{
affect_strip(victim,paf->type);
}
switch (paf->location)
{
case APPLY_STR_DAMAGE:
case APPLY_DEX_DAMAGE:
case APPLY_CON_DAMAGE:
case APPLY_INT_DAMAGE:
case APPLY_WIS_DAMAGE:
case APPLY_CHA_DAMAGE:
affect_strip(victim,paf->type);
break;
}
}
affect_strip(victim,gsn_bleed_damage);
affect_strip(victim,gsn_poison);
affect_strip(victim, gsn_feeblemind);
affect_strip(victim, gsn_festering_wounds);
if (victim->poison != NULL)
{
POISON_DATA *npd, *pd;
pd = victim->poison;
victim->poison = NULL;
while (pd != NULL)
{
npd = pd->next;
FREEMEM( pd );
pd = npd;
}
}
for ( dis = victim->first_disease; dis != NULL; dis = dis_next )
{
dis_next = dis->next;
disease_from_char(victim, dis);
}
victim->hit = UMIN( victim->hit + heal, get_max_hit(victim));
victim->move = UMIN( victim->move + heal, get_max_move(victim));
victim->nonlethal = UMAX(0, victim->nonlethal - heal);
update_pos(victim,-1);
pop_call();
return TRUE;
}
DO_SPELL(spell_heat_metal)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
sh_int count;
push_call("spell_heat_metal(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = 7;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
af.level = level;
if (wears_metal(victim, TRUE))
{
if (!save_resist(ch, victim, sn, level))
{
affect_join( ch, victim, &af);
if (sn == gsn_heat_metal)
act("{018}The metal you wear starts to get very warm!", victim, NULL, NULL, TO_CHAR);
else
act("{168}The metal you wear starts to get very chilly!", victim, NULL, NULL, TO_CHAR);
}
}
if ((count = level/2) <= 1)
{
pop_call();
return TRUE;
}
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (count <= 1)
break;
if (vch == victim)
continue;
if (!can_mass_cast(ch, vch, sn))
continue;
if (!wears_metal(victim, TRUE))
continue;
if (save_resist(ch, victim, sn, level))
continue;
affect_join(ch, vch, &af);
if (sn == gsn_heat_metal)
act("{018}The metal you wear starts to get very warm!", vch, NULL, NULL, TO_CHAR);
else
act("{168}The metal you wear starts to get very chilly!", vch, NULL, NULL, TO_CHAR);
--count;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_heroes_feast)
{
CHAR_DATA *fch;
AFFECT_DATA af;
DISEASE_DATA *dis, *dis_next;
bool cured = FALSE;
int caster_check;
push_call("spell_heroes_feast(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "$n creates a large selection of food and drinks.", ch, NULL, NULL, TO_ROOM );
act( "You create a large selection of food and drinks.", ch, NULL, NULL, TO_CHAR );
act( "Everyone joins you as you eat your fill.", ch, NULL, NULL, TO_CHAR );
caster_check = spell_dice(ch, sn, 1, 20) + level;
for (fch = ch->in_room->first_person ; fch ; fch = fch->next_in_room)
{
if (must_eat(fch) && fch->position >= POS_RESTING)
{
gain_condition( fch, COND_FULL, 50 );
gain_condition( fch, COND_THIRST, 50 );
send_to_char( "You join in the feast and eat your fill.\n\r", fch );
if (IS_AFFECTED(fch, AFF2_SICKENED))
{
AFFECT_STRIP(fch, AFF2_SICKENED);
cured = TRUE;
}
if (IS_AFFECTED(fch, AFF2_NAUSEATED))
{
AFFECT_STRIP(fch, AFF2_NAUSEATED);
cured = TRUE;
}
if (is_affected( fch, gsn_poison))
{
if (caster_check >= 10 + get_affect_level(fch, gsn_poison))
{
affect_strip( fch, gsn_poison );
cured = TRUE;
}
}
if (fch->poison != NULL)
{
POISON_DATA *npd, *pd;
pd = fch->poison;
if (caster_check >= (pd->dc ? pd->dc : poison_table[pd->type].dc))
{
while (pd != NULL)
{
npd = pd->next;
FREEMEM( pd );
pd = npd;
}
cured = TRUE;
}
else
{
cured = FALSE;
}
}
if (fch->first_disease != NULL)
{
for ( dis = fch->first_disease; dis != NULL; dis = dis_next )
{
dis_next = dis->next;
if (dis->dc && caster_check < dis->dc)
continue;
if (!dis->dc && caster_check < disease_table[dis->type].dc)
continue;
disease_from_char(fch, dis);
}
if (!fch->first_disease)
cured = TRUE;
}
if ( cured )
{
act( "A warm feeling runs through your body.", fch, NULL, NULL, TO_CHAR );
}
if (is_affected( fch, sn ))
{
continue;
}
af.type = sn;
af.duration = 12 * hr;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_HIT;
af.modifier = spell_dice(ch, sn, 1, 8) + UMIN(level/2, 10);
affect_to_char( ch, fch, &af );
af.location = APPLY_MOR_TOHIT;
af.modifier = 1;
affect_to_char( ch, fch, &af );
af.location = APPLY_MOR_WILL;
af.modifier = 1;
affect_to_char( ch, fch, &af );
af.location = APPLY_SAVE_POISON;
af.modifier = 4;
affect_to_char( ch, fch, &af );
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_hold)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
push_call("spell_hold(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (is_same_group(ch, vch))
continue;
if ((sn == gsn_hold_animal || sn == gsn_hold_person
|| sn == gsn_hold_monster) && vch != victim)
continue;
if (!can_mass_cast(ch, vch, sn))
continue;
if (((sn == gsn_hold_plant || sn == gsn_mass_hold_plant) && race_type(vch) != RTYPE_PLANT)
|| ((sn == gsn_hold_animal || sn == gsn_mass_hold_animal) && !IS_ANIMAL(vch))
|| ((sn == gsn_hold_person || sn == gsn_mass_hold_person) && !IS_HUMANOID(vch)))
{
act( "$N seems to be unaffected by your magic.", ch, NULL, vch, TO_CHAR );
continue;
}
if (save_resist(ch, vch, sn, level))
continue;
af.type = sn;
af.duration = level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_PARALYSIS;
af.level = level;
affect_to_char( ch, vch, &af );
act( "You freeze in your tracks!", vch, NULL, NULL, TO_CHAR );
act( "$n freezes in $s tracks!", vch, NULL, NULL, TO_ROOM );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_horrid_wilting)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
int dam, sizedie;
int save;
push_call("spell_horrid_wilting(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act("{108}Moisture is sucked rapidly out of the area!", victim, NULL, NULL, TO_ALL);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if (IS_INCORPOREAL(vch))
continue;
switch (race_type(vch))
{
case RTYPE_UNDEAD:
case RTYPE_CONSTRUCT:
continue;
case RTYPE_PLANT:
case RTYPE_OOZE:
sizedie = 8;
break;
default:
sizedie = 6;
break;
}
if (rspec_req(vch, RSPEC_WATER))
sizedie = 8;
if ((save = save_resist(ch, vch, sn, level)) == TRUE)
continue;
dam = spell_dice(ch, sn, UMIN(level,20), sizedie);
if (save == PARTIAL)
dam /= 2;
damage( ch, vch, dam, sn, NULL );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_ice_storm)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
ROOM_TIMER_DATA rtd;
int diceroll;
push_call("spell_ice_storm(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
diceroll = spell_dice(ch, sn, 5, 6);
act( "$n {178}calls down a storm of ice!", ch, NULL, NULL, TO_ROOM);
act( "{178}You call down a storm of ice!", ch, NULL, NULL, TO_CHAR);
spell_damage(ch, victim, diceroll, sn, level);
if (IS_SET(ch->in_room->room_flags, ROOM_ICE))
{
pop_call();
return TRUE;
}
switch (ch->in_room->sector_type)
{
case SECT_ETHEREAL:
case SECT_ASTRAL:
case SECT_UNDER_WATER:
pop_call();
return TRUE;
}
rtd.vnum = ch->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = level;
rtd.bitvector = ROOM_ICE;
rtd.level = level;
set_room_timer(ch, &rtd);
pop_call();
return TRUE;
}
DO_SPELL(spell_implosion)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
int cnt, save;
push_call("spell_implosion(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (cnt = 0, vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn) || !is_same_group(victim, vch))
{
continue;
}
if (!IS_LIVING(vch))
continue;
if ((save = save_resist(ch, vch, sn, level)) == TRUE)
continue;
cnt++;
if (cnt >= 4)
break;
if (save == PARTIAL)
{
damage(ch, vch, spell_dice(ch, sn, 3, 6) + level, sn, NULL);
}
else
{
damage(ch, vch, level * 10, sn, NULL);
}
}
if (!cnt)
{
act("Your spell had no effect on anyone.", ch, NULL, NULL, TO_CHAR);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_insect_plague)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int save, count;
push_call("spell_insect_plague(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{038}A cloud of flying insects swarms in!", ch, NULL, NULL, TO_ALL );
for (count = UMIN(level/3, 6), vch = victim->in_room->first_person ; vch ; vch = vch_next)
{
vch_next = vch->next_in_room;
if (count <= 0)
break;
if (!can_mass_cast(ch, vch, sn))
continue;
if (is_affected(vch, sn))
continue;
if ((save = save_resist(ch, vch, sn, level)) == TRUE)
continue;
af.type = sn;
af.duration = turn*level;
af.location = APPLY_NONE;
af.modifier = 0;
af.level = level;
if (save == PARTIAL)
{
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
}
else
{
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_SICKENED;
}
affect_to_char( ch, vch, &af );
act( "{038}The insects swarm around you!", vch, NULL, NULL, TO_CHAR );
act( "{038}The insects swarm around $n!", vch, NULL, NULL, TO_ROOM );
--count;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_invis)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
push_call("spell_invis(%p,%p,%p,%p)",sn,level,ch,vo);
if (target == TAR_CHAR_DEFENSIVE)
{
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{108}You fade out of view.", victim, NULL, NULL, TO_CHAR);
act( "{108}$n fades out of view.", victim, NULL, NULL, TO_ROOM);
af.type = sn;
af.duration = sn == gsn_improved_invis ? level : turn * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_INVISIBLE;
af.level = level;
affect_join( ch, victim, &af );
if (sn == gsn_improved_invis)
{
af.location = APPLY_CONCEALMENT;
af.modifier = 50;
affect_join( ch, victim, &af );
}
}
else if (target == TAR_OBJ_INV)
{
if (IS_SET(obj->extra_flags, ITEM_INVIS))
{
act( "$p is already invisible.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = turn * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_OBJ;
af.bitvector = ITEM_INVIS;
af.level = level;
affect_to_obj( ch,obj, &af );
act( "$p fades out of view.", ch, obj, NULL, TO_CHAR);
}
pop_call();
return TRUE;
}
/*
* Knock spell, d20 style
* homebrew function is a hack of do_pick
* Variant rule pits caster level check + 10 vs. lock DC - Kregor
*/
DO_SPELL(spell_knock)
{
char arg[MAX_INPUT_LENGTH];
OBJ_DATA *obj;
int door, diceroll, pick_lvl;
target_name = one_argument(target_name, arg);
if ((door = find_door(ch, arg)) >= 0)
{
ROOM_INDEX_DATA *to_room;
EXIT_DATA *pExit, *pExit_rev;
pExit = ch->in_room->exit[door];
if (!IS_SET(pExit->exit_info, EX_CLOSED))
{
send_to_char("It's not even closed. That was a waste.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_SET(pExit->exit_info, EX_LOCKED)
|| IS_SET(pExit->exit_info, EX_KNOCKED))
{
send_to_char("It's already unlocked.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (IS_SET(pExit->exit_info, EX_PICKPROOF))
{
pop_call();
return TRUE;
}
if (IS_SET(pExit->exit_info, EX_AMAZING_PICK))
pick_lvl = 40;
else if (IS_SET(pExit->exit_info, EX_HARD_PICK))
pick_lvl = 30;
else if (IS_SET(pExit->exit_info, EX_EASY_PICK))
pick_lvl = 20;
else
pick_lvl = 25;
if (IS_SET(pExit->exit_info, EX_MAGICAL_LOCK))
pick_lvl += 10;
diceroll = spell_dice(ch, sn, 1, 20) + 10 + level;
if (diceroll < pick_lvl)
{
pop_call();
return TRUE;
}
act( "{138}The lock on the $d glows momentarily.", ch, pExit->keyword, NULL, TO_ROOM);
act( "{138}The lock on the $d glows momentarily.", ch, pExit->keyword, NULL, TO_CHAR);
SET_BIT(pExit->exit_info, EX_KNOCKED);
/*
* knock the other side
*/
if ((to_room = room_index[pExit->to_room]) != NULL
&& (pExit_rev = to_room->exit[rev_dir[door]]) != NULL
&& room_index[pExit_rev->to_room] == ch->in_room)
{
SET_BIT( pExit_rev->exit_info, EX_KNOCKED );
}
}
else if ((obj = get_obj_here(ch, arg)) != NULL)
{
if (obj->item_type != ITEM_CONTAINER)
{
act( "$p is not a container.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!IS_SET(obj->value[1], CONT_CLOSED))
{
act( "$p is not closed.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!IS_SET(obj->value[1], CONT_LOCKED) || IS_SET(obj->value[1], CONT_KNOCKED))
{
act( "$p is already unlocked.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (IS_SET(obj->value[1], CONT_AMAZING_PICK))
pick_lvl = 40;
else if (IS_SET(obj->value[1], CONT_HARD_PICK))
pick_lvl = 30;
else if (IS_SET(obj->value[1], CONT_EASY_PICK))
pick_lvl = 20;
else
pick_lvl = 25;
if (IS_SET(obj->value[1], CONT_MAGICAL_LOCK))
pick_lvl += 10;
diceroll = spell_dice(ch, sn, 1, 20) + 3 + level;
if (diceroll < pick_lvl)
{
pop_call();
return TRUE;
}
SET_BIT(obj->value[1], CONT_KNOCKED);
REMOVE_BIT(obj->value[1], CONT_CLOSED);
act( "{138}$p pops open.", ch, obj, NULL, TO_ROOM);
act( "{138}$p pops open.", ch, obj, NULL, TO_CHAR);
}
else
{
act( "You see no $T here.", ch, NULL, arg, TO_CHAR );
pop_call();
return FALSE;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_light)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
push_call("spell_light(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_OBJ_STAT(obj, ITEM_GLOW))
{
send_to_char( "That object already glows.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = sn == gsn_cont_light ? -1 : (turn * level);
af.bittype = AFFECT_TO_OBJ;
af.bitvector = ITEM_GLOW;
af.location = APPLY_ROOM_LIGHT;
af.modifier = 1;
af.level = level;
affect_to_obj( ch,obj, &af);
act( "$p {138}begins to glow with a soft light.", ch, obj, NULL, TO_CHAR);
act( "$p {138}begins to glow with a soft light.", ch, obj, NULL, TO_ROOM);
pop_call();
return TRUE;
}
DO_SPELL(spell_lightning_bolt)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_lightning_bolt(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = spell_dice(ch, sn, UMIN(level, 10), 6);
spell_damage(ch, victim, dam, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_locate_creature)
{
CHAR_DATA *victim;
int count, race, casterlvl;
char txt[MAX_STRING_LENGTH];
push_call("spell_locate_creature(%p,%p,%p,%p)",sn,level,ch,vo);
if (*target_name == '\0')
{
send_to_char( "Who are you trying to locate?\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
casterlvl = dice(1,20) + level;
*txt = '\0';
for (count = 0, victim = mud->f_char ; victim ; victim = victim->next)
{
if (!can_see_world(ch, victim))
{
continue;
}
if (!is_multi_name_list_short(target_name, PERS(victim, ch)))
{
if (!is_multi_name_list_short(target_name, adjective(victim)))
{
if ((race = lookup_race(target_name)) == -1 || get_race(victim) != race)
{
continue;
}
}
}
if (!victim->in_room)
{
continue;
}
//flowing water blocks spell
if (victim->in_room->sector_type == SECT_LAKE
|| victim->in_room->sector_type == SECT_RIVER
|| victim->in_room->sector_type == SECT_OCEAN
|| victim->in_room->sector_type == SECT_UNDER_WATER)
{
continue;
}
if (IS_SET(victim->in_room->room_flags, ROOM_NOSCRY))
{
continue;
}
if (CAN_ETHEREAL_WALK(victim) || CAN_ASTRAL_WALK(victim))
{
continue;
}
if (check_nondetection(ch, victim, gsn_locate_creature))
{
continue;
}
if (is_affected(victim, gsn_mislead))
{
continue;
}
cat_sprintf(txt, "%s is at %s in %s.\n\r", PERS(victim, ch), victim->in_room->name, victim->in_room->area->name);
if (++count >= UMIN(level/2, 10))
{
break;
}
}
if (count == 0)
{
send_to_char( "You find no one like that in hell, earth, or heaven.\n\r", ch );
}
else
{
send_to_char( txt, ch );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_locate_object)
{
OBJ_DATA *obj;
OBJ_DATA *in_obj;
char obj_name[MAX_INPUT_LENGTH];
char txt[MAX_STRING_LENGTH];
int count;
push_call("spell_locate_object(%p,%p,%p,%p)",sn,level,ch,vo);
if (*target_name == '\0')
{
send_to_char( "What are you trying to locate?\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
*txt = '\0';
for (count = 0, obj = mud->f_obj ; obj ; obj = obj->next)
{
if (!is_multi_name_list_short(target_name, obj->short_descr) || !can_see_obj(ch, obj) )
{
continue;
}
if (IS_SET(obj->extra_flags, ITEM_NOSCRY))
{
continue;
}
if (obj->in_room && IS_SET(obj->in_room->room_flags, ROOM_NOSCRY))
{
continue;
}
for (in_obj = obj ; in_obj->in_obj ; in_obj = in_obj->in_obj);
if (in_obj->carried_by && !can_see_world(ch, in_obj->carried_by))
{
continue;
}
if (in_obj->carried_by)
{
if (check_nondetection(ch, in_obj->carried_by, gsn_locate_object))
{
continue;
}
}
else if (!obj->in_room)
{
continue;
}
if (in_obj->carried_by->in_room && IS_SET(in_obj->carried_by->in_room->room_flags, ROOM_NOSCRY))
{
continue;
}
if (in_obj->material == MATERIAL_LEAD)
{
continue;
}
strcpy(obj_name, capitalize(obj->short_descr));
if (in_obj->carried_by != NULL)
{
cat_sprintf(txt, "%s {300}is carried by %s.\n\r", obj_name, PERS(in_obj->carried_by, ch));
}
else
{
cat_sprintf(txt, "%s {300}is at %s.\n\r", obj_name, in_obj->in_room->name);
}
if (++count >= UMIN(level/2, 10))
{
break;
}
}
if (count == 0)
{
send_to_char( "You find nothing like that in hell, earth, or heaven.\n\r", ch );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_make_whole)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
int mend;
push_call("spell_make_whole(%p,%p,%p,%p)",sn,level,ch,vo);
if (target == TAR_CHAR_DEFENSIVE)
{
if (race_type(victim) != RTYPE_CONSTRUCT)
{
act("$N is not a construct!", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
mend = spell_dice(ch, sn, UMIN(level, 5), 6);
victim->hit = UMIN( victim->hit + mend, get_max_hit(victim));
update_pos(victim,-1);
act("$n's scars and breaks mend themselves.", victim, NULL, NULL, TO_ROOM);
act("Your scars and breaks mend themselves.", victim, NULL, NULL, TO_CHAR);
}
else if (target == TAR_OBJ_INV)
{
if (obj->weight > 100 * level)
{
act( "$p is too large to be mended by this spell.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
mend = spell_dice(ch, sn, 1, 6) + level;
if (obj->hit_points + mend >= get_obj_max_hit(obj))
{
act( "$p {138}mends as good as new!", ch, obj, NULL, TO_CHAR);
act( "$p {138}mends as good as new!", ch, obj, NULL, TO_ROOM);
}
else
{
act( "$p {138}is mended.", ch, obj, NULL, TO_CHAR);
act( "$p {138}is mended.", ch, obj, NULL, TO_ROOM);
}
obj->hit_points = UMIN(obj->hit_points + mend, get_obj_max_hit(obj));
}
pop_call();
return TRUE;
}
DO_SPELL(spell_magic_missile)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int count;
push_call("spell_magic_missile(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
count = (level - 1) / 2 + 1;
if (count == 1)
{
act( "{158}A bolt of force shoots from $n's finger...", ch, NULL, victim, TO_ROOM );
act( "{158}A bolt of force shoots from your finger...", ch, NULL, victim, TO_CHAR );
}
else
{
act( "{158}Bolts of force shoot from $n's fingers...", ch, NULL, victim, TO_ROOM );
act( "{158}Bolts of force shoot forth from your fingers...", ch, NULL, victim, TO_CHAR );
}
while (count)
{
if (!save_resist(ch, victim, sn, level))
{
damage( ch, victim, spell_dice(ch, sn, 1,4)+1, sn, NULL );
}
--count;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_magic_vestment)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
OBJ_DATA *armor;
AFFECT_DATA af;
push_call("spell_magic_vestment(%p,%p,%p,%p)",sn,level,ch,vo);
if (target == TAR_CHAR_DEFENSIVE)
{
// get_eq_char will not work here, since the armor could be layered - Kregor
for (armor = victim->first_carrying ; armor ; armor = armor->next_content)
{
if (IS_WORN(armor) && IS_OBJ_TYPE(armor, ITEM_ARMOR) && !IS_OBJ_STAT(armor, ITEM_MAGIC) && (WEAR_LOC(armor, WEAR_SHIELD) || WEAR_LOC(armor, WEAR_BODY)))
break;
}
if (!armor)
{
act( "$N is not wearing a suitable vestment.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = turn * level;
af.bittype = AFFECT_TO_OBJ;
af.level = level;
af.bitvector = ITEM_MAGIC;
af.location = APPLY_ENHANCE_AC;
af.modifier = URANGE(1, level/4, 5);
affect_to_obj(ch, armor, &af);
act( "$p {138}glows {078}momentarily.", ch, obj, NULL, TO_CHAR);
act( "$p {138}glows {078}momentarily.", ch, obj, NULL, TO_ROOM);
}
else if (target == TAR_OBJ_INV)
{
if (obj->item_type != ITEM_ARMOR || IS_OBJ_STAT(obj, ITEM_MAGIC))
{
act( "$p cannot be enchanted.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = turn * level;
af.bittype = AFFECT_TO_OBJ;
af.level = level;
af.bitvector = ITEM_MAGIC;
af.location = APPLY_ENHANCE_AC;
af.modifier = URANGE(1, level/4, 5);
affect_to_obj(ch, obj, &af);
act( "$p {138}glows {078}momentarily.", ch, obj, NULL, TO_CHAR);
act( "$p {138}glows {078}momentarily.", ch, obj, NULL, TO_ROOM);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_magic_weapon)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
push_call("spell_magic_weapon(%p,%p,%p,%p)",sn,level,ch,vo);
if (target == TAR_CHAR_DEFENSIVE)
{
if ((obj = get_wield(victim, FALSE)) == NULL)
{
if (!learned(victim, gsn_martial_arts))
{
act( "$N's hands are not that deadly.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.level = level;
af.bitvector = AFF_NONE;
af.location = APPLY_HITROLL;
af.modifier = URANGE(1, level/4, 5);
affect_join( ch, victim, &af);
af.location = APPLY_DAMROLL;
af.modifier = URANGE(1, level/4, 5);
affect_join( ch, victim, &af);
act( "$n's hands {138}glow {078}momentarily.", ch, NULL, NULL, TO_CHAR);
act( "$n's hands {138}glow {078}momentarily.", ch, NULL, NULL, TO_ROOM);
}
else
{
if (!IS_OBJ_TYPE(obj, ITEM_WEAPON))
{
act( "$p is not a weapon.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
{
act( "$p is already enchanted.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = turn * level;
af.bittype = AFFECT_TO_OBJ;
af.level = level;
af.bitvector = ITEM_MAGIC;
af.location = APPLY_HITROLL;
af.modifier = URANGE(1, level/4, 5);
affect_to_obj( ch,obj, &af);
af.location = APPLY_DAMROLL;
af.modifier = URANGE(1, level/4, 5);
affect_to_obj( ch,obj, &af);
act( "$p {138}glows {078}momentarily in your hand.", victim, obj, NULL, TO_CHAR);
act( "$p {138}glows {078}momentarily in $n's hand.", victim, obj, NULL, TO_ROOM);
}
}
else if (target == TAR_OBJ_INV)
{
if (!IS_OBJ_TYPE(obj, ITEM_WEAPON))
{
act( "$p is not a weapon.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
{
act( "$p is already enchanted.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = turn * level;
af.bittype = AFFECT_TO_OBJ;
af.level = level;
af.bitvector = ITEM_MAGIC;
af.location = APPLY_HITROLL;
af.modifier = URANGE(1, level/4, 5);
affect_to_obj( ch,obj, &af);
af.location = APPLY_DAMROLL;
af.modifier = URANGE(1, level/4, 5);
affect_to_obj( ch,obj, &af);
act( "$p {138}glows {078}momentarily in your hand.", ch, obj, NULL, TO_CHAR);
act( "$p {138}glows {078}momentarily in $n's hand.", ch, obj, NULL, TO_ROOM);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_major_image)
{
CHAR_DATA *mh, *victim;
char illusionname[MAX_INPUT_LENGTH];
int i;
push_call("spell_major_image(%p,%p,%p,%p)",sn,level,ch,vo);
for (i = 0 ; target_name[i] != '\0' ; i++)
{
if (ispunct(target_name[i]) || isdigit(target_name[i]))
{
send_to_char("You cannot create such an abstract illusion.\n\r", ch);
pop_call();
return FALSE;
}
}
if (!ForReal)
{
pop_call();
return TRUE;
}
mh = create_mobile( get_mob_index( MOB_VNUM_ILLUSION ) );
char_to_room( mh, ch->in_room->vnum, TRUE );
mh->level = 1;
mh->npcdata->sac_timer = level * turn;
mh->npcdata->sac_string = STRALLOC("$n shimmers then winks out of existence.");
mh->max_hit = mh->hit = 1;
if (target_name[0] == '\0' || !strcasecmp(target_name, "self"))
{
sprintf(illusionname, "%s^", ch->name);
RESTRING(mh->name, illusionname);
if (IS_NPC(ch))
{
RESTRING(mh->short_descr, ch->short_descr);
}
else
{
RESTRING(mh->short_descr, ch->name);
}
RESTRING(mh->long_descr, ch->long_descr);
RESTRING(mh->description, ch->description);
mh->race = ch->race;
mh->sex = ch->sex;
}
else if ((victim = get_char_room(ch, target_name)) != NULL && victim != mh)
{
for (illusionname[0] = '\0', i = 0 ; victim->name[i] != '\0' ; i++)
{
if (victim->name[i] == ' ')
{
strcat(illusionname, "^ ");
}
else
{
cat_sprintf(illusionname, "%c", victim->name[i]);
}
}
strcat(illusionname, "^");
RESTRING(mh->name, illusionname);
if (IS_NPC(victim))
{
RESTRING(mh->short_descr, victim->short_descr);
}
else
{
RESTRING(mh->short_descr, victim->name);
}
if (IS_NPC(victim))
{
RESTRING(mh->long_descr, victim->long_descr);
}
else
{
RESTRING(mh->long_descr, victim->long_descr);
}
RESTRING(mh->description, victim->description);
mh->race = victim->race;
mh->sex = victim->sex;
}
else
{
for (illusionname[0] = '\0', i = 0 ; target_name[i] != '\0' ; i++)
{
if (target_name[i] == ' ')
{
strcat(illusionname, "^ ");
}
else
{
cat_sprintf(illusionname, "%c", target_name[i]);
}
}
strcat(illusionname, "^");
RESTRING(mh->name, illusionname);
RESTRING(mh->short_descr, target_name);
RESTRING(mh->long_descr, format("%s stands here.", target_name));
RESTRING(mh->description, "");
mh->race = ch->race;
mh->sex = ch->sex;
}
SET_BIT( mh->affected_by , AFF_DOMINATE );
act( "$N takes shape before your eyes.",ch,NULL,mh,TO_CHAR);
act( "$N takes shape before your eyes.",ch,NULL,mh,TO_ROOM);
add_follower( mh , ch );
pop_call();
return TRUE;
}
DO_SPELL(spell_mass_invis)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
CHAR_DATA *gch;
int count;
push_call("spell_mass_invis(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (count = 0, gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (count >= level)
break;
if (!is_same_group(gch, victim))
{
continue;
}
if (IS_AFFECTED(gch, AFF_INVISIBLE))
{
continue;
}
act( "$n slowly fades out of existence.", gch, NULL, NULL, TO_ROOM);
act( "You slowly fade out of existence.", gch, NULL, NULL, TO_CHAR);
af.type = sn;
af.duration = turn * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_INVISIBLE;
af.level = level;
affect_to_char( ch, gch, &af );
count++;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_mass_refresh)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *gch;
int move, cnt;
push_call("spell_mass_refresh(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
move = spell_dice(ch, sn, 2, 8) + UMIN(level, 30);
for (cnt = 0, gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (!is_same_group(gch, victim))
{
continue;
}
if (cnt >= level)
{
continue;
}
gch->move = UMIN(gch->move + move, get_max_move(gch));
act( "{138}$n looks a bit more refreshed.", gch, NULL, NULL, TO_ROOM );
act( "{138}You feel a bit more refreshed.", gch, NULL, NULL, TO_CHAR );
cnt++;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_mending)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
int mend;
push_call("spell_mending(%p,%p,%p,%p)",sn,level,ch,vo);
if (obj->weight > 10 * level)
{
act( "$p is too large to be mended by this cantrip.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
{
act( "Magical items cannot be mended with this cantrip.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (IS_OBJ_STAT(obj, ITEM_BROKEN))
{
act( "$p is too badly damaged to mend.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (obj->hit_points == 0)
{
act( "$p is too badly damaged to mend.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
mend = dice(1,4);
if (obj->hit_points + mend >= get_obj_max_hit(obj))
{
act( "$p {138}mends as good as new!", ch, obj, NULL, TO_CHAR);
act( "$p {138}mends as good as new!", ch, obj, NULL, TO_ROOM);
}
else
{
act( "$p {138}mends slightly.", ch, obj, NULL, TO_CHAR);
act( "$p {138}mends slightly.", ch, obj, NULL, TO_ROOM);
}
obj->hit_points = UMIN(obj->hit_points + mend, get_obj_max_hit(obj));
pop_call();
return TRUE;
}
/*
* new approach to one-spell, multi-missile spells - Kregor
*/
DO_SPELL(spell_meteor_swarm)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
ROOM_INDEX_DATA *tar_room; //might need in case victim dies before spell runs out
int diceroll, count, cnt;
push_call("spell_meteor_swarm(%p,%p,%p,%p)",sn,level,ch,vo);
if ((tar_room = victim->in_room) == NULL)
{
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act("{118}A hail of {138}fireballs {118}showers forth!", ch, NULL, NULL, TO_ALL);
//Send out 1 ball for every 5 caster levels against the victim and allies...
for (count = cnt = level/5 ; cnt ; cnt--)
{
if (count <= 0) //balls all gone
break;
for (vch = tar_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (vch == victim || is_same_group(vch, victim))
{
//first check_hit for blunt trauma on target
if(check_hit(ch, vch, dice(1,20), 0, sn, NULL, TRUE, TRUE))
{
act("{118}A fireball slams into you!", vch, NULL, NULL, TO_CHAR);
act("{118}A fireball slams into $n!", vch, NULL, NULL, TO_ROOM);
damage( ch, vch, spell_dice(ch, sn, 2, 6), gsn_bash_hit, NULL );
}
else
{
damage( ch, vch, 0, gsn_bash_hit, NULL );
}
//then make the ball of fire explode!
diceroll = spell_dice(ch, sn, 6, 6);
spell_damage(ch, vch, diceroll, sn, level);
--count;
if (count <= 0)
break;
}
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_mislead)
{
CHAR_DATA *mh;
char illusionname[MAX_INPUT_LENGTH];
AFFECT_DATA af;
push_call("spell_mislead(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
//create illusory double...
mh = create_mobile( get_mob_index( MOB_VNUM_ILLUSION ) );
char_to_room( mh, ch->in_room->vnum, TRUE );
mh->level = 1;
mh->npcdata->sac_timer = level;
mh->npcdata->sac_string = STRALLOC("$n shimmers then winks out of existence.");
mh->max_hit = 1;
mh->hit = get_max_hit(mh);
mh->race = ch->race;
mh->sex = ch->sex;
sprintf(illusionname, "%s^", ch->name);
RESTRING(mh->name, illusionname);
if (IS_NPC(ch))
{
RESTRING(mh->short_descr, ch->short_descr);
}
else
{
RESTRING(mh->short_descr, ch->name);
}
RESTRING(mh->long_descr, ch->long_descr);
RESTRING(mh->description, ch->description);
//then improved invis the caster...
af.type = sn;
af.duration = level;
af.location = APPLY_CONCEALMENT;
af.modifier = 50;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_INVISIBLE;
af.level = level;
affect_join( ch, ch, &af );
//make the illusion wander
REMOVE_BIT(mh->act, ACT_SENTINEL|ACT_NOWANDER);
pop_call();
return TRUE;
}
DO_SPELL(spell_neutralize_poison)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
bool cured = FALSE;
bool failed = FALSE;
int caster_check;
AFFECT_DATA af;
push_call("spell_neutralize_poison(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
caster_check = spell_dice(ch, sn, 1, 20) + level;
if (target == TAR_CHAR_DEFENSIVE)
{
if ( is_affected( victim, gsn_poison ) )
{
if (caster_check >= 10 + get_affect_level(victim, gsn_poison))
{
affect_strip( victim, gsn_poison );
cured = TRUE;
}
else
{
act("A necromantic toxin resisted your spell.", ch, NULL, victim, TO_CHAR);
failed = TRUE;
}
}
if (victim->poison != NULL)
{
POISON_DATA *npd, *pd;
pd = victim->poison;
if (caster_check >= (pd->dc ? pd->dc : poison_table[pd->type].dc))
{
while (pd != NULL)
{
npd = pd->next;
FREEMEM( pd );
pd = npd;
}
cured = TRUE;
}
else
{
act("The toxins have resisted your spell.", ch, NULL, victim, TO_CHAR);
failed = TRUE;
}
}
if (!IS_NPC(victim) && drunk_level(victim))
{
victim->pcdata->condition[COND_DRUNK] = 0;
act( "You are feeling sober now.", victim, NULL, NULL, TO_CHAR );
act( "$n looks less groggy.", victim, NULL, NULL, TO_ROOM );
}
if ( cured )
{
if (ch != victim)
{
act( "You have purged toxins from $N's body.", ch, NULL, victim, TO_CHAR );
}
act( "A warm feeling runs through your body.", victim, NULL, NULL, TO_CHAR );
}
else if (!failed)
{
af.type = sn;
af.duration = 5 * turn * level;
af.location = APPLY_IMM_POISON;
af.modifier = 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.level = level;
affect_join( ch, victim, &af );
act( "{128}You feel a ward against poison fill your body.", victim, NULL, NULL, TO_CHAR );
if ( ch != victim )
act( "{128}$N is filled with a ward against poisons.", ch, NULL, victim, TO_CHAR );
}
}
else if (target == TAR_OBJ_INV)
{
if (obj->poison != NULL)
{
POISON_DATA *npd, *pd;
pd = obj->poison;
if (caster_check >= (pd->dc ? pd->dc : poison_table[pd->type].dc))
{
while (pd != NULL)
{
npd = pd->next;
FREEMEM( pd );
pd = npd;
}
cured = TRUE;
}
}
if ( cured )
{
act( "$p is purged of its toxins.", ch, obj, NULL, TO_CHAR );
}
else
{
act( "$p did not seem to be affected.", ch, obj, NULL, TO_CHAR );
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_nightmare)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_nightmare(%p,%p,%p,%p)",sn,level,ch,vo);
if (is_affected(victim, sn))
{
act( "$N is still recovering from $S last fright!", ch, NULL, victim, TO_CHAR );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (get_apply(victim, APPLY_RES_EVIL) > 0)
{
act( "$N is warded from your evil visions!", ch, NULL, victim, TO_CHAR );
pop_call();
return FALSE;
}
if (victim->position != POS_SLEEPING)
{
act( "$N cannot receive your dream.", ch, NULL, victim, TO_CHAR );
pop_call();
return FALSE;
}
if (save_resist(ch, victim, sn, level))
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = level;
af.bitvector = 0;
af.bittype = AFFECT_TO_NONE;
af.location = APPLY_SAVES;
af.modifier = 0 - 2;
af.level = level;
affect_to_char( ch, victim, &af );
update_pos(victim, POS_SITTING);
act( "{118}A nightmarish apparition invades your dream!", ch, NULL, victim, TO_VICT );
act( "You project your nightmare into $N's mind.", ch, NULL, victim, TO_CHAR );
act( "{118}$n awakes with a bloodcurdling scream", victim, NULL, NULL, TO_ROOM );
damage( ch, victim, spell_dice(ch, sn, 1, 10), sn, NULL );
pop_call();
return TRUE;
}
DO_SPELL(spell_null)
{
push_call("spell_null(%p,%p,%p,%p)",sn,level,ch,vo);
send_to_char( "We haven't done that one yet!\n\r", ch );
pop_call();
return FALSE;
}
/*
* Permanency spell made easy -
* Simply change duration on current
* effect to -1, no longer expires,
* but does get purged on death. - Kregor
*/
DO_SPELL(spell_permanency)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
int paf_type, cost;
push_call("spell_permanency(%p,%p,%p,%p)",sn,level,ch,vo);
if (*target_name == '\0')
{
act("Make what spell permanent?", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if ((paf_type = skill_lookup(target_name)) == -1 || !is_spell(paf_type))
{
act("That is not a valid spell.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!is_affected(victim, paf_type))
{
act("That spell is not currently active.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!IS_SET(skill_table[paf_type].flags, SF_PERMANENCY))
{
act("$t cannot be made permanent.", ch, skill_table[paf_type].name, NULL, TO_CHAR);
pop_call();
return FALSE;
}
// must be 8 levels higher than the spell circle
if (skill_table[paf_type].native_level + 8 > level)
{
act("You are not powerful enough to make $t permanent.", ch, skill_table[paf_type].name, NULL, TO_CHAR);
pop_call();
return FALSE;
}
//material cost = 2500gp per spell circle
if ((cost = skill_table[paf_type].native_level * 250000) > ch->gold)
{
act("You need $t to make $T permanent.", ch, format_coins(cost, FALSE), skill_table[paf_type].name, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
for ( paf = victim->first_affect; paf ; paf = paf_next )
{
paf_next = paf->next;
if (paf->type == paf_type)
{
affect_modify(victim, paf, FALSE);
paf->duration = -2;
paf->level = level;
if (!IS_NPC(ch))
paf->caster = STRALLOC(ch->name);
else
paf->caster = STRALLOC(format("m%d", ch->pIndexData->vnum));
affect_modify(victim, paf, TRUE);
}
}
gold_transaction(ch, 0 - cost);
act("You expended $t and made $T permanent.", ch, format_coins(cost, FALSE), skill_table[paf_type].name, TO_CHAR);
pop_call();
return TRUE;
}
/*
* Used for both phantasmal killer and wierd, based on spell flag - Kregor
*/
DO_SPELL(spell_phantasmal_killer)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch;
CHAR_DATA *vch_next;
int save;
push_call("spell_phantasmal_killer)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
// if (!can_mass_cast(ch, vch, sn))
// continue;
//
if (sn == gsn_phantasmal_killer && vch != victim)
continue;
if (!is_same_group(victim, vch))
continue;
if (will_save(vch, ch, level, sn))
{
act("{138}$N scoffs at your illusion!", ch, NULL, vch, TO_CHAR);
act("{138}You see through the illusion $n has put before you.", ch, NULL, vch, TO_VICT);
continue;
}
if ((save = save_resist(ch, vch, sn, level)) == TRUE)
{
continue;
}
else
{
act("{118}$N screams in terror!", ch, NULL, vch, TO_CHAR);
act("{118}You scream in terror as your worst nightmare devours you!", ch, NULL, vch, TO_VICT);
act("{118}$N screams in terror at something only $E can see!", ch, NULL, vch, TO_NOTVICT);
if (save == PARTIAL)
{
damage( ch, vch, dice(3,6), sn, NULL );
if (IS_AWAKE(vch))
{
AFFECT_DATA af;
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
af.level = level;
af.duration = 1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_DAZED;
affect_join( ch, vch, &af );
}
continue;
}
else
{
damage( ch, vch, vch->hit + 10, sn, NULL );
continue;
}
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_poison)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_poison(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_AFFECTED(victim, AFF_POISON))
{
act( "$N is already poisoned.", ch, NULL, victim, TO_CHAR );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (save_resist(ch, victim, sn, level))
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = 6;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_POISON;
af.level = level;
affect_to_char( ch,victim, &af );
stat_damage(ch, victim, APPLY_CON_DAMAGE, gsn_poison);
act( "{128}You feel poison coursing through your veins.", victim, NULL, NULL, TO_CHAR );
act( "{128}$N shivers and suffers as if poisoned!", victim, NULL, NULL, TO_ROOM );
pop_call();
return TRUE;
}
/*
* Unified SPELL_FUN for all polymorph
* spells, filtering thru the morphing
* function to do the magic; this just
* decides who gets funneled thru it - Kregor
*/
DO_SPELL(spell_polymorph)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
char buf1[MAX_INPUT_LENGTH];
char buf2[MAX_INPUT_LENGTH];
int cnt, save, race, hitdice, maxdice;
bool area = FALSE;
push_call("spell_polymorph(%p,%p,%p,%p)",sn,level,ch,vo);
if (!is_string(target_name))
{
ch_printf_color(ch, "Transmute into what?\n\r");
pop_call();
return FALSE;
}
two_arguments(target_name, buf1, buf2);
if (is_polymorph(ch))
{
if (victim == ch)
ch_printf_color(ch, "You are already in an alternate form.");
else
act("$N is already in an alternate form.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (target != TAR_CHAR_OFFENSIVE && !is_same_group(ch, victim))
{
act("$N is not a willing target ($e must be grouped).", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if ((race = lookup_race(target_name)) == -1)
{
if ((race = lookup_race(buf2)) == -1)
{
if ((race = lookup_race(buf1)) == -1)
{
act("That is not a valid race.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
}
maxdice = level + polymorph_synergy(ch, race_table[race].type);
if ((hitdice = race_table[race].hit_dice) > maxdice)
{
act("That form is too powerful for you.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (IS_SET(race_table[race].flags, RSPEC_INCORPOREAL))
{
act("That race is not possible with this spell.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (sn == gsn_alter_self)
{
if (race_table[race].type != race_table[ch->race].type)
{
act("You can only assume a form that is the same racial type.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (race_table[race].size < SIZE_SMALL || race_table[race].size > SIZE_MEDIUM)
{
act("You can only assume the form of a small or medium creature.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (hitdice > race_table[ch->race].hit_dice)
{
act("That creature is too strong.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
if (sn == gsn_beast_shape)
{
if (race_table[race].type != RTYPE_ANIMAL)
{
act("That race is not an animal.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (race_table[race].size < race_table[ch->race].size - 1)
{
act("That creature is too small.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (race_table[race].size > race_table[ch->race].size + 1)
{
act("That creature is too big.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
if (sn == gsn_polymorph)
{
if (race_table[race].size < race_table[ch->race].size - 2)
{
act("That creature is too small.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (race_table[race].size > race_table[ch->race].size + 2)
{
act("That creature is too big.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
if (sn == gsn_baleful_polymorph)
{
if (hitdice > 1)
{
act("That creature is too strong.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (race_table[race].type != RTYPE_ANIMAL)
{
act("That race is not an animal.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
if (sn == gsn_animal_shapes && race_table[race].type != RTYPE_ANIMAL)
{
act("That is not an animal.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (sn != gsn_shapechange)
{
if (hitdice > 15)
{
act("That creature is too strong.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
switch (race_table[race].type)
{
case RTYPE_UNDEAD:
case RTYPE_OUTSIDER:
case RTYPE_CONSTRUCT:
case RTYPE_OOZE:
act("That race type is not possible with this spell.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
case RTYPE_DRAGON:
case RTYPE_PLANT:
case RTYPE_ABERRATION:
if (sn != gsn_greater_polymorph)
{
act("That race type is not possible with this spell.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
break;
default:
break;
}
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (IS_AREA_SPELL(sn))
area = TRUE;
for (cnt = 0, vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!area && vch != victim)
continue;
if (cnt && cnt >= level)
break;
// willing target = in same group as caster - Kregor
if (target == TAR_CHAR_OFFENSIVE)
{
if (!can_mass_cast(ch, vch, sn))
continue;
}
else if (!is_same_group(ch, vch))
continue;
if (is_polymorph(vch))
{
act("$N is already in an alternate form.", ch, NULL, vch, TO_CHAR);
continue;
}
if (race == get_race(vch))
continue;
if (vch->level < race_table[race].hit_dice)
{
act("$N is too weak to assume that form.", ch, NULL, vch, TO_CHAR);
continue;
}
if ((save = save_resist(ch, vch, sn, level)) != FALSE)
continue;
if (!morph(ch, vch, race, sn, level))
continue;
cnt++;
if (!area)
break;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_power_word_blind)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_power_word_blind(%p,%p,%p,%p)",sn,level,ch,vo);
if (victim == ch)
{
send_to_char_color("You shouldn't shout at yourself that way...", ch);
pop_call();
return FALSE;
}
if (IS_AFFECTED(victim, AFF_BLIND))
{
act( "$N is already blinded.", ch, NULL, victim, TO_CHAR );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if ( victim->hit > 200 )
{
act( "{078}You bark out a single word, and nothing happens...", ch, NULL, victim, TO_CHAR );
act( "{078}$n barks out a single word, and nothing happens...", ch, NULL, victim, TO_VICT );
act( "{078}$n barks out a single word, and nothing happens...", ch, NULL, victim, TO_NOTVICT );
pop_call();
return TRUE;
}
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
if ( victim->hit <= 50 )
af.duration = -1;
else if ( victim->hit <= 100 )
af.duration = spell_dice(ch, sn, 1, 4) + 1 * turn;
else if ( victim->hit <= 200 )
af.duration = spell_dice(ch, sn, 1, 4) + 1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_BLIND;
af.level = level;
affect_to_char( ch, victim, &af );
act( "{138}You bark out a single word, blinding $N!", ch, NULL, victim, TO_CHAR );
act( "{138}$n barks out a single word, blinding you!", ch, NULL, victim, TO_VICT );
act( "{138}$n barks out a single word, blinding $N!", ch, NULL, victim, TO_NOTVICT );
pop_call();
return TRUE;
}
DO_SPELL(spell_power_word_stun)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_power_word_stun(%p,%p,%p,%p)",sn,level,ch,vo);
if (victim == ch)
{
send_to_char_color("You shouldn't shout at yourself that way...", ch);
pop_call();
return FALSE;
}
if ( IS_AFFECTED(victim, AFF2_STUNNED) )
{
act( "$N is already srunned.", ch, NULL, victim, TO_CHAR );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if ( victim->hit > 150 )
{
act( "{078}You bark out a single word, and nothing happens...", ch, NULL, victim, TO_CHAR );
act( "{078}$n barks out a single word, and nothing happens...", ch, NULL, victim, TO_VICT );
act( "{078}$n barks out a single word, and nothing happens...", ch, NULL, victim, TO_NOTVICT );
pop_call();
return TRUE;
}
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
if ( victim->hit <= 50 )
af.duration = spell_dice(ch, sn, 4, 4);
else if ( victim->hit <= 100 )
af.duration = spell_dice(ch, sn, 2, 4);
else if ( victim->hit <= 150 )
af.duration = spell_dice(ch, sn, 1, 4);
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_STUNNED;
af.level = level;
affect_to_char( ch, victim, &af );
act( "{138}You bark out a single word, leaving $N stunned!", ch, NULL, victim, TO_CHAR );
act( "{138}$n barks out a single word, leaving you stunned!", ch, NULL, victim, TO_VICT );
act( "{138}$n barks out a single word, leaving $N stunned!", ch, NULL, victim, TO_NOTVICT );
pop_call();
return TRUE;
}
DO_SPELL(spell_power_word_kill)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam = get_max_hit(victim) + 11;
push_call("spell_power_word_kill(%p,%p,%p,%p)",sn,level,ch,vo);
if (victim == ch)
{
send_to_char_color("You shouldn't shout at yourself that way...", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if ( victim->hit > 100 )
{
act( "{078}You bark out a single word, and nothing happens...", ch, NULL, victim, TO_CHAR );
act( "{078}$n barks out a single word, and nothing happens...", ch, NULL, victim, TO_VICT );
act( "{078}$n barks out a single word, and nothing happens...", ch, NULL, victim, TO_NOTVICT );
pop_call();
return TRUE;
}
act( "{138}You bark out a single word, which tears the soul from $N!", ch, NULL, victim, TO_CHAR );
act( "{138}$n barks out a single word, which tears the soul from you!", ch, NULL, victim, TO_VICT );
act( "{138}$n barks out a single word, which tears the soul from $N!", ch, NULL, victim, TO_NOTVICT );
damage(ch, victim, dam, sn, NULL);
pop_call();
return TRUE;
}
DO_SPELL(spell_produce_flame)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
OBJ_DATA *fire;
push_call("spell_produce_flame(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (target == TAR_CHAR_OFFENSIVE)
{
int dam = spell_dice(ch, sn, 1, 6) + UMIN(level, 5);
act("{118}You hurl a ball of flame at $N.", ch, NULL, victim, TO_CHAR);
act("{118}$n hurls a ball of flame at $N.", ch, NULL, victim, TO_NOTVICT);
act("{118}$n hurls a ball of flame at you.", ch, NULL, victim, TO_VICT);
spell_damage(ch, victim, dam, sn, level);
}
else if (target == TAR_OBJ_INV)
{
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
{
act( "$p cannot be ignited.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
switch (obj->material)
{
default:
send_to_char("That is not flammable.\n\r", ch);
pop_call();
return TRUE;
case MATERIAL_HARDWOOD:
case MATERIAL_SOFTWOOD:
case MATERIAL_OAK:
case MATERIAL_YEW:
case MATERIAL_EBONY:
case MATERIAL_PAPER:
case MATERIAL_OIL:
break;
}
if ((fire = create_object( get_obj_index( OBJ_VNUM_FIRE ), 0 )) == NULL)
{
bug("do_burn: OBJ_VNUM_FIRE not created.", 0);
pop_call();
return FALSE;
}
fire->value[2] = obj->size * obj->size;
act( "You set fire to $p.", ch, obj, NULL, TO_CHAR );
act( "$n sets fire to $p.", ch, obj, NULL, TO_ROOM );
obj_to_room( fire, ch->in_room->vnum );
junk_obj(obj);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_remove_disease)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj = (OBJ_DATA *) vo;
DISEASE_DATA *dis, *dis_next;
bool cured = FALSE;
int caster_check;
push_call("spell_remove_disease(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
caster_check = spell_dice(ch, sn, 1, 20) + level;
if (target == TAR_CHAR_DEFENSIVE)
{
if (victim->first_disease != NULL)
{
for (dis = victim->first_disease ; dis ; dis = dis_next)
{
dis_next = dis->next;
if (dis->dc && caster_check < dis->dc)
continue;
if (!dis->dc && caster_check < disease_table[dis->type].dc)
continue;
disease_from_char(victim, dis);
}
if (!victim->first_disease)
cured = TRUE;
}
if ( cured )
{
act( "{138}You feel the wrackings of your sickness fade.", victim, NULL, NULL, TO_CHAR );
act( "{138}$n begins to look healthier.", victim, NULL, NULL, TO_ROOM );
}
else
{
act("Your spell alleviated nothing.", ch, NULL, NULL, TO_CHAR);
}
}
else if (target == TAR_OBJ_INV)
{
if (obj->first_disease != NULL)
{
for (dis = obj->first_disease ; dis ; dis = dis_next)
{
dis_next = dis->next;
if (caster_check < disease_table[dis->type].dc)
continue;
disease_from_obj(obj, dis);
}
if (!obj->first_disease)
cured = TRUE;
}
if ( cured )
{
act( "$p is cleansed of its disease.", ch, obj, NULL, TO_CHAR );
}
else
{
act( "$p did not seem to be affected.", ch, obj, NULL, TO_CHAR );
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_secure_shelter)
{
char buf[MAX_INPUT_LENGTH];
EXIT_DATA *pExit;
ROOM_INDEX_DATA *pRoomIndex;
int door, rip_door, vnum, range;
push_call("spell_secure_shelter(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_NPC(ch))
{
pop_call();
return FALSE;
}
if (!IS_SET(ch->in_room->room_flags, ROOM_RIP))
{
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE)
|| IS_SET(ch->in_room->room_flags, ROOM_NO_RIP)
|| IS_SET(ch->in_room->area->flags, AFLAG_NORIP)
|| IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
|| IS_SET(ch->in_room->area->flags, AFLAG_NORECALL))
{
send_to_char("You are prevented from ripping space here!\n\r",ch);
pop_call();
return FALSE;
}
}
else
{
send_to_char("You can't create a rip within another rip in space.\n\r",ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
for (door = range = 0 ; door < 6 ; door++)
{
if (ch->in_room->exit[door] == NULL)
{
range++;
}
}
if (range == 0)
{
send_to_char("You failed to find space to create a rip here.\n\r", ch);
pop_call();
return FALSE;
}
vnum = number_range(1, range);
rip_door = 0;
for (door = 0 ; door < 6 ; door++)
{
if (ch->in_room->exit[door] == NULL)
{
if (--vnum == 0)
{
rip_door = door;
break;
}
}
}
/* find valid vnum */
for (vnum = ROOM_VNUM_RIFT ; vnum < MAX_VNUM && get_room_index(vnum) != NULL ; vnum++);
if (vnum >= MAX_VNUM)
{
send_to_char("You are prevented from ripping up the Realm!\n\r",ch);
pop_call();
return FALSE;
}
create_room(vnum);
pRoomIndex = room_index[vnum];
pRoomIndex->description = STRDUPE(str_empty);
pRoomIndex->listen_desc = STRDUPE(str_empty);
pRoomIndex->night_desc = STRDUPE(str_empty);
sprintf(buf, "%s's Secure Shelter", ch->name);
pRoomIndex->name = STRALLOC(buf);
pRoomIndex->area = room_index[ROOM_VNUM_LIMBO]->area;
pRoomIndex->vnum = vnum;
pRoomIndex->description = STRALLOC("You see an area that defies all description.\n\r");
pRoomIndex->room_flags = ROOM_RIP|ROOM_NO_MOB|ROOM_INDOORS|ROOM_NO_RECALL|ROOM_NO_SAVE|ROOM_SAFE|ROOM_INN;
pRoomIndex->sector_type = SECT_INSIDE;
pRoomIndex->creator_pvnum = ch->pcdata->pvnum;
for (door = 0 ; door < MAX_LAST_LEFT ; door++)
{
pRoomIndex->last_left[door] = STRDUPE(str_empty);
}
/* new room exit points to old room */
create_exit(pRoomIndex, rev_dir[rip_door]);
pExit = pRoomIndex->exit[rev_dir[rip_door]];
RESTRING(pExit->description, "You see an opening exiting the fabric of space and time.");
pExit->to_room = ch->in_room->vnum;
create_exit(ch->in_room, rip_door);
pExit = ch->in_room->exit[rip_door];
RESTRING(pExit->description, "You see an opening in the fabric of space and time.");
SET_BIT(pExit->exit_info, EX_RIP);
pExit->pvnum = ch->pcdata->pvnum;
pExit->to_room = pRoomIndex->vnum;
act( "$n creates a room of haven $twards.", ch, dir_name[rip_door], NULL, TO_ROOM);
ch_printf_color(ch, "You create a room of haven %swards.\n\r", dir_name[rip_door]);
pop_call();
return TRUE;
}
DO_SPELL(spell_shatter)
{
CHAR_DATA *victim = NULL;
OBJ_DATA *obj = NULL;
ROOM_INDEX_DATA *to_room;
EXIT_DATA *pExit, *pExit_rev;
int diceroll, dmg, dc;
int door = -1;
push_call("spell_shatter(%p,%p,%p,%p)",sn,level,ch,vo);
if (is_string(target_name))
{
if ((victim = get_char_room(ch, target_name)) == NULL)
{
if ((obj = get_obj_room(ch, target_name)) == NULL)
{
if ((door = find_door(ch, target_name)) == -1)
{
act("You cannot find any $t here.", ch, target_name, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
}
}
if (door != -1)
{
pExit = ch->in_room->exit[door];
if (IS_SET(pExit->exit_info, EX_BASHED))
{
send_to_char( "It's already been bashed off its hinges!\n\r", ch );
pop_call();
return FALSE;
}
if (!IS_SET(pExit->exit_info, EX_CLOSED))
{
send_to_char( "It is already open.\n\r", ch );
pop_call();
return FALSE;
}
if (!IS_SET(pExit->exit_info, EX_BASHPROOF|EX_MAGICPROOF))
{
send_to_char( "It resists your spell.\n\r", ch );
pop_call();
return FALSE;
}
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act("{178}A loud ringing noise pulses out from you!", ch, NULL, NULL, TO_CHAR);
act("{178}A loud ringing noise pulses out from $n!", ch, NULL, NULL, TO_CHAR);
// hacked bash code to work shatter against a door - Kregor
if (door != -1)
{
pExit = ch->in_room->exit[door];
diceroll = spell_dice(ch, sn, 1, 20) + level;
if (IS_SET(pExit->exit_info, EX_IRON_DOOR))
dc = 28;
else if (IS_SET(pExit->exit_info, EX_HEAVY_DOOR))
dc = 23;
else if (IS_SET(pExit->exit_info, EX_WEAK_DOOR))
dc = 13;
else
dc = 18;
if (IS_SET(pExit->exit_info, EX_MAGICAL_LOCK))
dc += 10;
else if (IS_SET(pExit->exit_info, EX_BARRED))
dc += 5;
if (!IS_SET(pExit->exit_info, EX_BASHPROOF) && diceroll >= dc)
{
REMOVE_BIT(pExit->exit_info, EX_CLOSED);
REMOVE_BIT(pExit->exit_info, EX_LOCKED);
SET_BIT( pExit->exit_info, EX_BASHED );
act( "$d shatters off its hinges!", ch, NULL, pExit->keyword, TO_CHAR );
act( "$d shatters off its hinges!", ch, NULL, pExit->keyword, TO_ROOM );
if ((to_room = room_index[pExit->to_room]) != NULL
&& (pExit_rev = room_index[pExit->to_room]->exit[rev_dir[door]]) != NULL
&& room_index[pExit_rev->to_room] == ch->in_room )
{
CHAR_DATA *rch;
REMOVE_BIT(pExit_rev->exit_info, EX_CLOSED);
REMOVE_BIT(pExit_rev->exit_info, EX_LOCKED);
SET_BIT( pExit_rev->exit_info, EX_BASHED );
for (rch = to_room->first_person ; rch ; rch = rch->next_in_room)
{
act( "$d shatters off its hinges!", rch, NULL, pExit_rev->keyword, TO_CHAR);
}
}
}
else
{
act( "$d holds firm against your sundering.", ch, NULL, pExit->keyword, TO_CHAR );
act( "Nothing seems to happen....", ch, NULL, NULL, TO_ROOM );
}
}
else if (victim)
{
switch (material_table[race_table[get_race(victim)].material].parent)
{
case MATERIAL_TYPE_GEM:
case MATERIAL_TYPE_CRYSTAL:
spell_damage( ch, victim, spell_dice(ch, sn, UMIN(level,10), 6), sn, level );
break;
case MATERIAL_TYPE_ROCK:
case MATERIAL_TYPE_METAL:
spell_damage( ch, victim, spell_dice(ch, sn, 2, 6) + UMIN(level, 10), sn, level );
break;
default:
act("Your spell has no effect on $N.", ch, NULL, victim, TO_CHAR);
act("Nothing seems to happen....", ch, NULL, NULL, TO_ROOM);
break;
}
}
else if (obj)
{
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
{
act("$p is protected by its magic aura.", ch, obj, NULL, TO_CHAR);
pop_call();
return TRUE;
}
if (IS_OBJ_STAT(obj, ITEM_BROKEN))
{
act("$p is already broken!", ch, obj, NULL, TO_CHAR);
pop_call();
return TRUE;
}
if (IS_OBJ_STAT(obj, ITEM_BURIED))
{
act("$p would have to be dug up first!", ch, obj, NULL, TO_CHAR);
pop_call();
return TRUE;
}
if (IS_OBJ_STAT(obj, ITEM_INVENTORY))
{
act("$p resists your spell.", ch, obj, NULL, TO_CHAR);
pop_call();
return TRUE;
}
// 10 lbs / caster level limit
if (obj->weight > 100 * level)
{
act("$p is too heavy for you to affect.", ch, obj, NULL, TO_CHAR);
pop_call();
return TRUE;
}
dmg = spell_dice(ch,sn,2,6) + UMIN(level, 10);
dmg = obj_damage_modify(obj, NULL, dmg, DAM_SONIC);
obj->hit_points -= dmg;
if (obj->hit_points <= 0)
{
act( "$p shatters into pieces!", ch, obj, NULL, TO_ALL);
junk_obj(obj);
}
else if (dmg)
{
act( "$p is damaged.", ch, obj, NULL, TO_ALL);
}
else
{
act( "$p is unaffected.", ch, obj, NULL, TO_ALL);
}
}
// None of the above means it was non-targeted
else
{
for (obj = ch->in_room->first_content ; obj ; obj = obj->next_content)
{
if (IS_OBJ_STAT(obj, ITEM_MAGIC|ITEM_BROKEN|ITEM_INVENTORY|ITEM_BURIED))
{
continue;
}
if (obj->weight > 10 * level)
{
continue;
}
if (material_table[obj->material].parent != MATERIAL_TYPE_CRYSTAL)
{
continue;
}
dmg = spell_dice(ch,sn,2,6) + UMIN(level, 10);
dmg = obj_damage_modify(obj, NULL, dmg, DAM_SONIC);
obj->hit_points -= dmg;
if (obj->hit_points <= 0)
{
act( "$p shatters into pieces!", ch, obj, NULL, TO_ALL);
junk_obj(obj);
}
else if (dmg)
{
act( "$p is damaged.", ch, obj, NULL, TO_ALL);
}
else
{
act( "$p is undaffected.", ch, obj, NULL, TO_ALL);
}
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_shadow_bolt)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
push_call("spell_shadow_bolt(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{108}A bolt of darkness shoots from $n's finger.", ch, NULL, victim, TO_ROOM );
act( "{108}A bolt of darkness shoots from your finger.", ch, NULL, victim, TO_CHAR );
damage(ch, victim, spell_dice(ch, sn, 1,8)+1, sn, NULL );
if (valid_victim(victim) && !save_resist(ch, victim, sn, level))
{
AFFECT_DATA af;
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
af.level = level;
af.duration = 1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_DAZED;
affect_join( ch, victim, &af );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_sign_of_wrath)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch;
int dam, chroll, vchroll;
push_call("spell_sign_of_wrath(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = spell_dice(ch, sn, UMIN(level, 15), 6);
act( "{138}A powerful symbol of wrath pulses around $n!", ch, NULL, NULL, TO_ROOM);
act( "{138}A wave of force burts out around you.", ch, NULL, NULL, TO_CHAR);
spell_damage(ch, victim, dam, sn, level);
chroll = dice(1,20) + level;
for (vch = victim->in_room->first_person ; vch ; vch = vch->next_in_room)
{
if (!can_mass_cast(ch, vch, sn))
continue;
vchroll = dice(1,20) + combat_maneuver_bonus(vch) + stat_bonus(TRUE, vch, APPLY_DEX);
if (quadruped(vch))
vchroll += 4;
if (many_legged(vch))
vchroll += 8;
if (race_skill(vch, gsn_stability))
vchroll += 4;
if (chroll < vchroll)
continue;
act( "$n is knocked back by the force of the symbol!", vch, NULL, NULL, TO_ROOM );
act( "You are knocked over by the force of the symbol!", vch, NULL, NULL, TO_CHAR );
update_pos(vch, POS_RESTING);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_simulacrum)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *mh;
char illusionname[MAX_INPUT_LENGTH];
int i, cls, skill;
push_call("spell_simulacrum(%p,%p,%p,%p)",sn,level,ch,vo);
if (victim->level > ch->level * 2)
{
act("$N is too powerful for you to copy.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
mh = create_mobile(get_mob_index(MOB_VNUM_ILLUSION));
char_to_room( mh, ch->in_room->vnum, TRUE );
mh->level = victim->level/2;
mh->class = victim->class;
for (cls = CLASS_MONSTER ; cls < MAX_CLASS ; cls++)
{
if (!victim->mclass[cls])
mh->mclass[cls] = 0;
else
mh->mclass[cls] = UMAX(1, victim->mclass[cls] / 2);
}
for (skill = 0 ; skill < MAX_REAL_SKILL ; skill++)
{
if (skill_table[skill].spell_school != FSKILL_SKILL
&& skill_table[skill].spell_school != FSKILL_FEAT)
continue;
if (victim->learned[skill] == 0)
continue;
mh->learned[skill] = UMAX(1, victim->learned[skill]);
}
mh->npcdata->sac_timer = level * hr;
mh->npcdata->sac_string = STRALLOC("$n shimmers then winks out of existence.");
mh->race = victim->race;
mh->sex = victim->sex;
mh->perm_str = victim->perm_str;
mh->perm_dex = victim->perm_dex;
mh->perm_con = victim->perm_con;
mh->perm_int = victim->perm_int;
mh->perm_wis = victim->perm_wis;
mh->perm_cha = victim->perm_cha;
mh->max_hit = UMAX(1, victim->max_hit/2);
mh->hit = get_max_hit(mh);
for (illusionname[0] = '\0', i = 0 ; victim->name[i] != '\0' ; i++)
{
if (victim->name[i] == ' ')
{
strcat(illusionname, "^ ");
}
else
{
cat_sprintf(illusionname, "%c", victim->name[i]);
}
}
strcat(illusionname, "^");
RESTRING(mh->name, illusionname);
if (IS_NPC(victim))
{
RESTRING(mh->short_descr, victim->short_descr);
}
else
{
RESTRING(mh->short_descr, victim->name);
}
if (IS_NPC(victim))
{
RESTRING(mh->long_descr, victim->long_descr);
}
else
{
RESTRING(mh->long_descr, victim->long_descr);
}
RESTRING(mh->description, victim->description);
SET_BIT( mh->affected_by , AFF_DOMINATE );
act( "A duplicate of $N takes shape before your eyes.", ch, NULL, victim, TO_ALL);
add_follower( mh, ch );
pop_call();
return TRUE;
}
DO_SPELL(spell_sirocco)
{
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int rtd_type = 0;
int dam, save;
ROOM_TIMER_DATA *rtd, *rtd_next;
push_call("spell_sirocco(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act("{038}You whip up a blinding sandstorm!", ch, NULL, NULL, TO_CHAR);
act("{038}$n whips up a blinding sandstorm!", ch, NULL, NULL, TO_ROOM);
for (vch = ch->in_room->first_person ; vch ; vch = vch_next)
{
vch_next = vch->next_in_room;
//strip insect plage from victims with the gust
if (is_affected(vch, gsn_insect_plague))
{
act("{038}The insects swarming around you scatter in the winds!", vch, NULL, NULL, TO_CHAR);
act("{038}The insects swarming around $n scatter in the winds!", vch, NULL, NULL, TO_ROOM);
affect_strip(vch, gsn_insect_plague);
}
if (vch == ch)
continue;
if (!can_mass_cast(ch, vch, sn))
continue;
if ((save = save_resist(ch, vch, sn, level)) == TRUE)
continue;
switch(get_size(vch))
{
case SIZE_FINE:
case SIZE_DIMINUTIVE:
case SIZE_TINY:
if (IS_FLYING(vch))
{
act("$n is buffeted back by the winds!", vch, NULL, NULL, TO_ROOM);
act("{118}You are buffeted back by the winds!", vch, NULL, NULL, TO_CHAR);
vch->distracted = 2;
damage(ch, vch, dice(2,6), sn, NULL);
}
else
{
act("$n is bowled over by the winds!", vch, NULL, NULL, TO_ROOM);
act("{118}You are bowled over by the winds!", vch, NULL, NULL, TO_CHAR);
vch->distracted = 2;
update_pos(vch, POS_RESTING);
damage(ch, vch, dice(1,4), sn, NULL);
}
break;
case SIZE_SMALL:
if (IS_FLYING(vch))
{
if (str_roll(vch) < level / 2 + 10)
{
if (!domain_apotheosis(vch, DOMAIN_STRENGTH) || str_roll(vch) < level / 2 + 10)
{
act("$n is buffeted back by the winds!", vch, NULL, NULL, TO_ROOM);
act("{118}You are buffeted back by the winds!", vch, NULL, NULL, TO_CHAR);
vch->distracted = 2;
damage(ch, vch, dice(1,6), sn, NULL);
}
}
}
else
{
act("$n is bowled over by the winds!", vch, NULL, NULL, TO_ROOM);
act("{118}You are bowled over by the winds!", vch, NULL, NULL, TO_CHAR);
vch->distracted = 2;
update_pos(vch, POS_RESTING);
}
break;
case SIZE_MEDIUM:
if (!IS_FLYING(vch))
{
if (str_roll(vch) < level / 2 + 10)
{
if (!domain_apotheosis(vch, DOMAIN_STRENGTH) || str_roll(vch) < level / 2 + 10)
{
act("$n is bowled over by the winds!", vch, NULL, NULL, TO_ROOM);
act("{118}You are bowled over by the winds!", vch, NULL, NULL, TO_CHAR);
vch->distracted = 2;
update_pos(vch, POS_RESTING);
}
}
}
break;
default:
break;
}
dam = level + spell_dice(ch, sn, 3, 6);
if (save == PARTIAL)
dam /= 2;
damage(ch, vch, dam, sn, NULL);
if (save == PARTIAL)
continue;
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
af.duration = level / 2 + spell_dice(ch, sn, 1, 4);
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_BLIND;
af.level = level;
affect_to_char( ch, vch, &af );
}
for (rtd = mud->f_room_timer ; rtd ; rtd = rtd_next)
{
rtd_next = rtd->next;
if (rtd->vnum == ch->in_room->vnum && IS_SET(rtd->bitvector, ROOM_FOG))
{
rtd->duration = 1;
rtd_type = rtd->type;
}
if (rtd->vnum == ch->in_room->vnum && IS_SET(rtd->bitvector, ROOM_SWARM))
{
rtd->duration = 0;
}
}
if (rtd_type != 0)
{
act("{168}The clouds are blown back by the winds!", ch, NULL, NULL, TO_ALL);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_protection_energy)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
int resist;
push_call("spell_protection_energy(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
resist = UMIN(level * 12, 120);
af.type = sn;
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_IMM_ELECTRIC;
af.modifier = resist;
victim->absorption[APPLY_IMM_ELECTRIC] = resist;
affect_join( ch, victim, &af );
af.location = APPLY_IMM_ACID;
af.modifier = resist;
victim->absorption[APPLY_IMM_ACID] = resist;
affect_join( ch, victim, &af );
af.location = APPLY_IMM_COLD;
af.modifier = resist;
victim->absorption[APPLY_IMM_COLD] = resist;
affect_join( ch, victim, &af );
af.location = APPLY_IMM_FIRE;
af.modifier = resist;
victim->absorption[APPLY_IMM_FIRE] = resist;
affect_join( ch, victim, &af );
af.location = APPLY_IMM_SONIC;
af.modifier = resist;
victim->absorption[APPLY_IMM_SONIC] = resist;
affect_join( ch, victim, &af );
act( "{138}A powerful ward against the elements surrounds $n's body.", victim, NULL, NULL, TO_ROOM );
act( "{138}A powerful ward against the elements surrounds your body.", victim, NULL, NULL, TO_CHAR );
pop_call();
return TRUE;
}
DO_SPELL(spell_purify)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
push_call("spell_purify(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
switch (obj->item_type)
{
case ITEM_FOOD:
case ITEM_DRINK_CON:
if (obj->value[3] != 0)
{
act( "$p is purified.", ch, obj, NULL, TO_CHAR);
act( "$p is purified.", ch, obj, NULL, TO_ROOM);
obj->value[3] = 0;
}
break;
case ITEM_FOUNTAIN:
if (obj->value[3] != 0)
{
act( "$p runs clear once more.", ch, obj, NULL, TO_CHAR);
act( "$p runs clear once more.", ch, obj, NULL, TO_ROOM);
obj->value[3] = 0;
}
break;
default:
act( "$p is not edible.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (obj->poison != NULL)
{
POISON_DATA *pd;
while ((pd = obj->poison) != NULL)
{
obj->poison = obj->poison->next;
FREEMEM(pd);
}
act( "$p is purified.", ch, obj, NULL, TO_CHAR);
act( "$p is purified.", ch, obj, NULL, TO_ROOM);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_death_knell)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
push_call("spell_harm(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (victim->hit > -1)
{
act( "Your spell has no effect.", victim, NULL, NULL, TO_CHAR);
}
else
{
spell_damage( ch, victim, victim->hit + 10, sn, level );
if (victim->position == POS_DEAD)
{
AFFECT_DATA af;
af.type = sn;
af.duration = 5 * turn * victim->level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_STR;
af.modifier = 2;
affect_join( ch, victim, &af );
af.location = APPLY_HIT;
af.modifier = dice(1,8);
affect_join( ch, victim, &af );
act("You draw power from the dying soul of $N.", ch, NULL, victim, TO_CHAR);
act("$n draws power from your dying soul of $N.", ch, NULL, victim, TO_NOTVICT);
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_slay_living)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam, save;
push_call("spell_slay_living(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = level * 10;
if (!IS_LIVING(victim))
{
act( "Your spell has no effect.", victim, NULL, NULL, TO_CHAR);
}
else if ((save = save_resist(ch, victim, sn, level)) == PARTIAL)
{
dam = spell_dice(ch, sn, 3, 6) + level;
}
else if (save)
{
pop_call();
return TRUE;
}
damage(ch, victim, dam, sn, NULL);
pop_call();
return TRUE;
}
DO_SPELL(spell_destruction)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam, save;
push_call("spell_destruction(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = 10 * level;
if (!IS_LIVING(victim))
{
act( "Your spell has no effect.", victim, NULL, NULL, TO_CHAR);
}
else if ((save = save_resist(ch, victim, sn, level)) == PARTIAL)
{
dam = spell_dice(ch, sn, 3, 6) + level;
}
else if (save)
{
pop_call();
return TRUE;
}
damage(ch, victim, dam, sn, NULL);
pop_call();
return TRUE;
}
DO_SPELL(spell_disintegrate)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam, save;
push_call("spell_disintegrate(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = spell_dice(ch, sn, UMIN(2*level,40), 6);
act("A green ray shoots from your finger at $N.", ch, NULL, victim, TO_CHAR);
act("A green ray shoots from $n's finger at $N.", ch, NULL, victim, TO_NOTVICT);
act("A green ray shoots from $n finger at you.", ch, NULL, victim, TO_VICT);
if ((save = save_resist(ch, victim, sn, level)) == PARTIAL)
{
dam = spell_dice(ch, sn, 5, 6);
}
else if (save)
{
pop_call();
return TRUE;
}
damage(ch, victim, dam, sn, NULL);
pop_call();
return TRUE;
}
/*
* Low-end raising spell, requires corpse,
* costs 1 con, suffers stat damage
* and only humanoids can be raised - Kregor
*/
DO_SPELL (spell_raise_dead)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
OBJ_DATA *obj_content;
CHAR_DATA *victim;
AFFECT_DATA af;
push_call("spell_raise_dead(%p,%p,%p,%p)",sn,level,ch,vo);
if (!obj)
{
send_to_char("You can't find a corpse here.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_OBJ_TYPE(obj, ITEM_CORPSE_PC))
{
send_to_char("That is not a player corpse.\n\r", ch);
pop_call();
return FALSE;
}
if (IS_SET(obj->extra_flags, ITEM_NO_RAISE))
{
send_to_char("You will need a stronger prayer to return that spirit.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if ((victim = get_char_pvnum(obj->owned_by)) == NULL)
{
send_to_char("The spirit cannot be found.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_PLR(victim, PLR_DEAD))
{
send_to_char("The spirit has found a new vessel already!\n\r", ch);
pop_call();
return FALSE;
}
if (IS_PLR(victim, PLR_SOULBIND))
{
send_to_char("The spirit has been bound from the mortal plane.\n\r", ch);
pop_call();
return TRUE;
}
if (victim->perm_con <= 1)
{
send_to_char("That spirit is too weak to be raised.\n\r", ch);
pop_call();
return TRUE;
}
if (!IS_HUMANOID(victim))
{
send_to_char("Only a humanoid creature can be raised.\n\r", ch);
pop_call();
return FALSE;
}
/* cannot raise diametric aligned char */
if (number_percent() < OPPOSITE_ALIGN(ch, victim))
{
act("{118}You faled to raise $N", ch, NULL, victim, TO_CHAR);
act("{118}The gods failed to answer $n's prayer.", ch, NULL, victim, TO_ROOM);
pop_call();
return TRUE;
}
act("{138}$n's spirit departs from the beyond!", victim, NULL, NULL, TO_ROOM);
char_from_room(victim);
char_to_room(victim, ch->in_room->vnum, TRUE);
destroy_mana(victim);
victim->hit = victim->level;
victim->move = victim->level;
REMOVE_BIT(victim->act, PLR_DEAD);
victim->perm_con--;
af.type = gsn_drain;
af.duration = -1;
af.modifier = 0 - UMIN(2, victim->perm_str - 1);
af.location = APPLY_STR_DRAIN;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.level = ch->level;
affect_join( ch, victim, &af );
af.location = APPLY_CON_DRAIN;
af.modifier = 0 - UMIN(2, victim->perm_con - 1);
affect_join( ch, victim, &af );
af.location = APPLY_DEX_DRAIN;
af.modifier = 0 - UMIN(2, victim->perm_dex - 1);
affect_join( ch, victim, &af );
act("{138}You have been raised from the dead!", victim, NULL, NULL, TO_CHAR);
act("{138}$n has been raised from the dead!", victim, NULL, NULL, TO_ROOM);
while ((obj_content = obj->last_content) != NULL)
{
obj_from_obj(obj_content);
obj_to_char(obj_content, victim);
}
extract_obj(obj);
do_look(victim, "");
pop_call();
return TRUE;
}
/*
* Druids can return the dead too,
* you just have to come back in a
* new body, and you take what you can get - Kregor
*/
DO_SPELL (spell_reincarnate)
{
CHAR_DATA *victim;
char arg[MAX_INPUT_LENGTH];
int old_race, race;
push_call("spell_reincarnate(%p,%p,%p,%p)",sn,level,ch,vo);
one_argument(target_name, arg);
if (arg[0] == '\0')
{
send_to_char("Whose spirit do you wish to reincarnate?\n\r", ch);
pop_call();
return FALSE;
}
if ((victim = get_player_world_even_blinded(arg)) == NULL)
{
send_to_char("The spirit cannot be found.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (!IS_PLR(victim, PLR_DEAD))
{
send_to_char("The spirit has found a new vessel already!\n\r", ch);
pop_call();
return FALSE;
}
if (IS_PLR(victim, PLR_SOULBIND))
{
send_to_char("The spirit has been bound from the mortal plane.\n\r", ch);
pop_call();
return TRUE;
}
act("{138}$n's spirit departs from the beyond!", victim, NULL, NULL, TO_ROOM);
char_from_room(victim);
char_to_room(victim, ch->in_room->vnum, TRUE);
old_race = victim->race;
switch(number_range(1,20))
{
case 1:
race = RACE_BUGBEAR;
break;
case 2:
case 3:
race = RACE_DWARF;
break;
case 4:
case 5:
race = RACE_ELF;
break;
case 6:
race = RACE_GNOLL;
break;
case 7:
case 8:
race = RACE_GNOME;
break;
case 9:
case 10:
race = RACE_HALFELF;
break;
case 11:
case 12:
race = RACE_HALFORC;
break;
case 13:
case 14:
race = RACE_HALFLING;
break;
case 15:
case 16:
case 17:
race = RACE_HUMAN;
break;
case 18:
race = RACE_PIXIE;
break;
case 19:
race = RACE_CENTAUR;
break;
case 20:
race = old_race;
break;
}
victim->race = race;
// new body = new physical stats
victim->perm_str = 8 + dice(1,6) + race_table[race].race_mod[0];
victim->perm_dex = 8 + dice(1,6) + race_table[race].race_mod[1];
victim->perm_con = 8 + dice(1,6) + race_table[race].race_mod[2];
RESTRING(victim->description, ""); // player has to write new description
RESTRING(victim->pcdata->adjective, ""); // player has to set new adj
REMOVE_BIT(victim->act, PLR_DEAD);
victim->hit = get_max_hit(victim);
victim->move = get_max_move(victim);
restore_mana(victim);
act("{138}Your spirit rewkakens in an unfamiliar body!", victim, NULL, NULL, TO_CHAR);
act("{138}$n has been reincarnated as $t $T!", victim, a_an(race_table[race].race_name), race_table[race].race_name, TO_ROOM);
do_look(victim, "");
pop_call();
return TRUE;
}
/*
* Mid-end raising spell, requires corpse,
* does not cause level loss - Kregor
*/
DO_SPELL (spell_resurrection)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
OBJ_DATA *obj_content;
CHAR_DATA *victim;
push_call("spell_resurrection(%p,%p,%p,%p)",sn,level,ch,vo);
if (!obj)
{
send_to_char("You can't find a corpse here.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_OBJ_TYPE(obj, ITEM_CORPSE_PC))
{
send_to_char("That is not a player corpse.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if ((victim = get_char_pvnum(obj->owned_by)) == NULL)
{
send_to_char("The spirit cannot be found.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_PLR(victim, PLR_DEAD))
{
send_to_char("The spirit has found a new vessel already!\n\r", ch);
pop_call();
return FALSE;
}
if (IS_PLR(victim, PLR_SOULBIND))
{
send_to_char("The spirit has been bound from the mortal plane.\n\r", ch);
pop_call();
return TRUE;
}
if (victim->perm_con < 2)
{
send_to_char("Their spirit is too weak.\n\r", ch);
pop_call();
return TRUE;
}
/* cannot raise diametric aligned char */
if (number_percent() < OPPOSITE_ALIGN(ch, victim))
{
act("{118}You faled to resurrect $N", ch, NULL, victim, TO_CHAR);
act("{118}The gods failed to answer $n's prayer.", ch, NULL, victim, TO_ROOM);
pop_call();
return TRUE;
}
act("{138}$n's spirit departs from the beyond!", victim, NULL, NULL, TO_ROOM);
char_from_room(victim);
char_to_room(victim, ch->in_room->vnum, TRUE);
victim->hit = get_max_hit(victim);
victim->move = get_max_move(victim);
restore_mana(victim);
act("{138}You have been resurrected!", victim, NULL, NULL, TO_CHAR);
act("{138}$n has been resurrected!", victim, NULL, NULL, TO_ROOM);
REMOVE_BIT(victim->act, PLR_DEAD);
while ((obj_content = obj->last_content) != NULL)
{
obj_from_obj(obj_content);
obj_to_char(obj_content, victim);
}
extract_obj(obj);
do_look(victim, "");
pop_call();
return TRUE;
}
/*
* High-end raising spell, does not require
* corpse, no limitations at all except for
* alignment restriction - Kregor
*/
DO_SPELL (spell_true_resurrection)
{
CHAR_DATA *victim;
char arg[MAX_INPUT_LENGTH];
push_call("spell_true_resurrection(%p,%p,%p,%p)",sn,level,ch,vo);
one_argument(target_name, arg);
if (arg[0] == '\0')
{
send_to_char("Whose spirit do you wish to resurrect?\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if ((victim = get_player_world_even_blinded(arg)) == NULL)
{
send_to_char("The spirit cannot be found.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_PLR(victim, PLR_DEAD))
{
send_to_char("The spirit has found a new vessel already!\n\r", ch);
pop_call();
return FALSE;
}
/* cannot raise diametric aligned char */
if (number_percent() < OPPOSITE_ALIGN(ch, victim))
{
act("{118}You faled to resurrect $N", ch, NULL, victim, TO_CHAR);
act("{118}The gods failed to answer $n's prayer.", ch, NULL, victim, TO_ROOM);
pop_call();
return TRUE;
}
act("{138}$n's spirit departs from the beyond!", victim, NULL, NULL, TO_ROOM);
char_from_room(victim);
char_to_room(victim, ch->in_room->vnum, TRUE);
victim->hit = get_max_hit(victim);
victim->move = get_max_move(victim);
restore_mana(victim);
act("{138}You have been resurrected!", victim, NULL, NULL, TO_CHAR);
act("{138}$n has been resurrected!", victim, NULL, NULL, TO_ROOM);
REMOVE_BIT(victim->act, PLR_DEAD|PLR_SOULBIND);
do_look(victim, "");
pop_call();
return TRUE;
}
/*
* Binds soul from dead corpse to prevent raising/animation - Kregor
*/
DO_SPELL (spell_soul_bind)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
CHAR_DATA *victim;
push_call("spell_soul_bind(%p,%p,%p,%p)",sn,level,ch,vo);
if (!obj)
{
send_to_char("You can't find a corpse here.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_OBJ_TYPE(obj, ITEM_CORPSE_PC))
{
send_to_char("That is not a player corpse.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if ((victim = get_char_pvnum(obj->owned_by)) == NULL)
{
send_to_char("The spirit cannot be found to bind it.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_PLR(victim, PLR_DEAD))
{
send_to_char("The spirit has found a new vessel already!\n\r", ch);
pop_call();
return TRUE;
}
if (will_save(victim, ch, level, sn))
{
act("$N's soul resists your attempt to bind it.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
SET_BIT(victim->act, PLR_SOULBIND);
act("{108}You feel your soul being cut off from the mortal plane.", victim, NULL, NULL, TO_CHAR);
act("{108}$n's soul has been bound from the mortal plane.", victim, NULL, NULL, TO_ROOM);
pop_call();
return TRUE;
}
DO_SPELL(spell_refresh)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int move;
push_call("spell_refresh(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
move = spell_dice(ch, sn, 2, 8) + UMIN(level, 10);
victim->move = UMIN( victim->move + move, get_max_move(victim) );
act( "{138}$n looks a bit more refreshed.", victim, NULL, NULL, TO_ROOM );
act( "{138}You feel a bit more refreshed.", victim, NULL, NULL, TO_CHAR );
pop_call();
return TRUE;
}
DO_SPELL(spell_remove_blindness)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
push_call("spell_remove_blindness(%p,%p,%p,%p)",sn,level,ch,vo);
if (!IS_AFFECTED(victim, AFF_BLIND))
{
act( "$N isn't blinded.", ch, NULL, victim, TO_CHAR );
pop_call();
return FALSE;
}
if (IS_RACE_AFFECT(victim, AFF_BLIND))
{
act( "$N's blindness cannot be cured.", ch, NULL, victim, TO_CHAR );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
AFFECT_STRIP( victim, AFF_BLIND );
send_to_char( "Your vision returns!\n\r", victim );
pop_call();
return TRUE;
}
DO_SPELL(spell_remove_deafness)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
push_call("spell_remove_deafness(%p,%p,%p,%p)",sn,level,ch,vo);
if (!IS_AFFECTED(victim, AFF_DEAF))
{
act( "$N isn't deafened.", ch, NULL, victim, TO_CHAR );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
AFFECT_STRIP( victim, AFF_DEAF );
send_to_char( "Your hearing returns!\n\r", victim );
pop_call();
return TRUE;
}
DO_SPELL(spell_stone_to_flesh)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
push_call("spell_stone_to_flesh(%p,%p,%p,%p)",sn,level,ch,vo);
if (!IS_AFFECTED(victim, AFF2_PETRIFICATION))
{
act( "$N isn't petrified.", ch, NULL, victim, TO_CHAR );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (!fort_save(victim, NULL, 15, -1))
{
act("{118}$n collapses under the shock of $s transformation!", victim, NULL, NULL, TO_ROOM);
act("{118}You collapse under the shock of your transformation!", victim, NULL, NULL, TO_CHAR);
damage(victim, victim, victim->hit + 11, TYPE_NOFIGHT, NULL);
pop_call();
return TRUE;
}
affect_strip( victim, gsn_flesh_to_stone );
affect_strip( victim, gsn_stone_fist );
AFFECT_STRIP( victim, AFF2_PETRIFICATION );
send_to_char( "Your stiffened joints can move once more!\n\r", victim );
act( "$n's stony countenance reverts to flesh once more.", victim, NULL, NULL, TO_ROOM );
pop_call();
return TRUE;
}
DO_SPELL(spell_stone_shower)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
int numdice, targets;
int save;
push_call("spell_stone_shower(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{038}Stones rend from the ground and launch forward!", ch, NULL, NULL, TO_CHAR );
act( "{038}Stones rend from the ground, spraying forth from $n", ch, NULL, NULL, TO_ROOM );
targets = UMIN(level, 10);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn) || !is_same_group(victim, vch))
{
continue;
}
numdice = dice(1, targets);
targets -= numdice;
if ((save = save_resist(ch, vch, sn, level)) == TRUE)
continue;
while (numdice)
{
damage( ch, vch, spell_dice(ch, sn, 1, 6) + 1, sn, NULL );
--numdice;
}
if (targets <= 0)
break;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_storm_of_vengeance)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
ROOM_INDEX_DATA *room;
ROOM_TIMER_DATA rtd;
push_call("spell_storm_of_vengeance(%p,%p,%p,%p)",sn,level,ch,vo);
if ((room = victim->in_room) == NULL)
{
pop_call();
return FALSE;
}
if (!IS_OUTSIDE(victim))
{
send_to_char( "This storm can only take place outdoors.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = 10;
rtd.bitvector = ROOM_FOG;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{108}Ominous clouds quickly gather in the area above $n.", victim, NULL, ch, TO_VICT);
act( "{108}Ominous clouds gather and thunder rumbles!", victim, NULL, ch, TO_NOTVICT);
act( "{108}Ominous clouds gather and thunder rumbles!", victim, NULL, NULL, TO_CHAR);
pop_call();
return TRUE;
}
DO_SPELL(spell_resist_elements)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
int resist;
push_call("spell_resist_elements(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (level >= 11)
resist = 30;
else if (level >= 7)
resist = 20;
else
resist = 10;
af.type = sn;
af.duration = turn * level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
af.location = APPLY_DR_ELECTRIC;
af.modifier = resist;
victim->absorption[APPLY_DR_ELECTRIC] = 2 * resist;
affect_join( ch, victim, &af );
af.location = APPLY_DR_ACID;
af.modifier = resist;
victim->absorption[APPLY_DR_ACID] = 2 * resist;
affect_join( ch, victim, &af );
af.location = APPLY_DR_COLD;
af.modifier = resist;
victim->absorption[APPLY_DR_COLD] = 2 * resist;
affect_join( ch, victim, &af );
af.location = APPLY_DR_FIRE;
af.modifier = resist;
victim->absorption[APPLY_DR_FIRE] = 2 * resist;
affect_join( ch, victim, &af );
af.location = APPLY_DR_SONIC;
af.modifier = resist;
victim->absorption[APPLY_DR_SONIC] = 2 * resist;
affect_join( ch, victim, &af );
act( "{138}A ward against the elements surrounds $n's body.", victim, NULL, NULL, TO_ROOM );
act( "{138}A ward against the elements surrounds your body.", victim, NULL, NULL, TO_CHAR );
pop_call();
return TRUE;
}
DO_SPELL(spell_restoration)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
int mv;
push_call("spell_restoration(%p,%p,%p,%p)",sn,level,ch,vo);
if (!CAN_CRITICAL(victim))
{
act("$N cannot be restored.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{138}Restoring energy fills your body.", victim, NULL, NULL, TO_CHAR);
act( "{138}Restoring energy fills $n's body.", victim, NULL, NULL, TO_ROOM);
for ( paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
switch (paf->location)
{
case APPLY_STR_DAMAGE:
case APPLY_DEX_DAMAGE:
case APPLY_CON_DAMAGE:
case APPLY_INT_DAMAGE:
case APPLY_WIS_DAMAGE:
case APPLY_CHA_DAMAGE:
{
affect_strip(victim,paf->type);
continue;
}
break;
case APPLY_STR:
case APPLY_DEX:
case APPLY_CON:
case APPLY_INT:
case APPLY_WIS:
case APPLY_CHA:
if (paf->modifier < 0)
{
affect_strip(victim,paf->type);
continue;
}
break;
}
if (sn == gsn_lesser_restoration)
continue;
switch (paf->location)
{
case APPLY_STR_DRAIN:
case APPLY_DEX_DRAIN:
case APPLY_CON_DRAIN:
case APPLY_INT_DRAIN:
case APPLY_WIS_DRAIN:
case APPLY_CHA_DRAIN:
{
affect_strip(victim,paf->type);
continue;
}
break;
case APPLY_LEVEL:
if (paf->duration >= 0)
{
affect_strip(victim,paf->type);
continue;
}
else if (sn == gsn_greater_restoration)
{
affect_strip(victim,paf->type);
continue;
}
else if ((paf->modifier += 1) >= 0)
{
affect_strip(victim,paf->type);
continue;
}
}
if (sn == gsn_restoration)
continue;
if (IS_SET(paf->bitvector, AFF2_CONFUSION))
{
affect_strip(victim,paf->type);
continue;
}
}
if (sn == gsn_lesser_restoration)
mv = get_max_move(victim) / 3;
else if (sn == gsn_restoration)
mv = get_max_move(victim) * 2 / 3;
else
mv = get_max_move(victim);
victim->move = UMIN(victim->move + mv, get_max_move(victim));
update_pos(victim,-1);
pop_call();
return TRUE;
}
DO_SPELL (spell_gentle_repose)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
push_call("spell_gentle_repose(%p,%p,%p,%p)",sn,level,ch,vo);
if (!obj)
{
send_to_char("You can't find a corpse here.\n\r", ch);
pop_call();
return FALSE;
}
if (is_obj_affected(obj, gsn_gentle_repose))
{
send_to_char("This corpse is already preserved.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_OBJ_TYPE(obj, ITEM_CORPSE_PC) && !IS_OBJ_TYPE(obj, ITEM_CORPSE_NPC))
{
send_to_char("That is not a player corpse.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = -1;
af.bittype = AFFECT_TO_NONE;
af.level = level;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_to_obj( ch,obj, &af);
obj->timer = 1440;
act("{138}$p has been preserved.", ch, obj, NULL, TO_ALL);
pop_call();
return TRUE;
}
DO_SPELL(spell_gust_of_wind)
{
CHAR_DATA *gch, *gch_next;
int rtd_type = 0;
ROOM_TIMER_DATA *rtd, *rtd_next;
push_call("spell_gust_of_wind(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act("{178}A powerful gust of wind blasts from you!", ch, NULL, NULL, TO_CHAR);
act("{178}A powerful gust of wind blasts from $n!", ch, NULL, NULL, TO_ROOM);
for (gch = ch->in_room->first_person ; gch ; gch = gch_next)
{
gch_next = gch->next_in_room;
//strip insect plage from victims with the gust
if (is_affected(gch, gsn_insect_plague))
{
act("{038}The insects swarming around you scatter in the winds!", gch, NULL, NULL, TO_CHAR);
act("{038}The insects swarming around $n scatter in the winds!", gch, NULL, NULL, TO_ROOM);
affect_strip(gch, gsn_insect_plague);
}
if (gch == ch)
continue;
if (!can_mass_cast(ch, gch, sn))
continue;
if (save_resist(ch, gch, sn, level))
continue;
switch(get_size(gch))
{
case SIZE_FINE:
case SIZE_DIMINUTIVE:
case SIZE_TINY:
if (IS_FLYING(gch))
{
act("$n is buffeted back by the winds!", gch, NULL, NULL, TO_ROOM);
act("{118}You are buffeted back by the winds!", gch, NULL, NULL, TO_CHAR);
gch->distracted = 2;
damage(ch, gch, dice(2,6), sn, NULL);
}
else
{
act("$n is bowled over by the winds!", gch, NULL, NULL, TO_ROOM);
act("{118}You are bowled over by the winds!", gch, NULL, NULL, TO_CHAR);
gch->distracted = 2;
update_pos(gch, POS_RESTING);
damage(ch, gch, dice(1,4), sn, NULL);
}
break;
case SIZE_SMALL:
if (IS_FLYING(gch))
{
if (str_roll(gch) < 20)
{
if (!domain_apotheosis(gch, DOMAIN_STRENGTH) || str_roll(gch) < 20)
{
act("$n is buffeted back by the winds!", gch, NULL, NULL, TO_ROOM);
act("{118}You are buffeted back by the winds!", gch, NULL, NULL, TO_CHAR);
gch->distracted = 2;
damage(ch, gch, dice(1,6), sn, NULL);
}
}
}
else
{
act("$n is bowled over by the winds!", gch, NULL, NULL, TO_ROOM);
act("{118}You are bowled over by the winds!", gch, NULL, NULL, TO_CHAR);
gch->distracted = 2;
update_pos(gch, POS_RESTING);
}
break;
case SIZE_MEDIUM:
if (!IS_FLYING(gch))
{
if (str_roll(gch) < 15)
{
if (!domain_apotheosis(gch, DOMAIN_STRENGTH) || str_roll(gch) < 15)
{
act("$n is bowled over by the winds!", gch, NULL, NULL, TO_ROOM);
act("{118}You are bowled over by the winds!", gch, NULL, NULL, TO_CHAR);
gch->distracted = 2;
update_pos(gch, POS_RESTING);
}
}
}
break;
default:
break;
}
}
for (rtd = mud->f_room_timer ; rtd ; rtd = rtd_next)
{
rtd_next = rtd->next;
if (rtd->vnum == ch->in_room->vnum && IS_SET(rtd->bitvector, ROOM_FOG))
{
rtd->duration = 1;
rtd_type = rtd->type;
}
if (rtd->vnum == ch->in_room->vnum && IS_SET(rtd->bitvector, ROOM_SWARM))
{
rtd->duration = 0;
}
}
if (rtd_type != 0)
{
act("{168}The clouds are blown back by the winds!", ch, NULL, NULL, TO_ALL);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_remove_curse)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj;
AFFECT_DATA *paf, *paf_next;
int paf_type;
bool removed = FALSE;
push_call("spell_remove_curse(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for ( paf_type = 0, paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (!IS_SET(paf->bitvector, AFF_CURSE))
continue;
if (dice(1,20) + level <= 11 + paf->level)
continue;
if (paf->duration >= 0)
{
if (skill_table[paf->type].msg_off)
{
act( skill_table[paf->type].msg_off, victim, NULL, NULL, TO_CHAR);
}
if (skill_table[paf->type].msg_off_room)
{
act( skill_table[paf->type].msg_off_room, victim, NULL, NULL, TO_ROOM);
}
}
paf_type = paf->type;
affect_from_char(victim, paf);
}
for (obj = victim->first_carrying; obj != NULL ; obj = obj->next_content)
{
if(IS_SET(obj->extra_flags, ITEM_NOREMOVE))
{
REMOVE_BIT( obj->extra_flags, ITEM_NOREMOVE);
act("$p is no longer cursed.", ch, obj, NULL, TO_ALL);
removed = TRUE;
}
}
if (paf_type == 0 && !removed)
{
send_to_char_color( "Nothing seems to happen.\n\r", ch);
send_to_char_color( "Nothing seems to happen.\n\r", victim);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_remove_fear)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
AFFECT_DATA af;
int casterlvl;
bool scared = FALSE;
push_call("spell_remove_fear(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
casterlvl = dice(1, 20) + level;
for ( paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (IS_SET(skill_table[paf->type].spell_desc, SDESC_FEAR))
{
if (casterlvl >= paf->level + 11)
{
affect_strip(victim, paf->type);
}
else
{
scared = TRUE;
}
}
}
if (!scared)
{
victim->fear_level = 0;
act( "{138}You become flushed with bravery!", ch, NULL, victim, TO_VICT );
act( "{138}$N becomes flushed with bravery!", ch, NULL, victim, TO_CHAR );
}
else
{
act("You fail to quell $N's fears!", ch, NULL, victim, TO_CHAR);
}
af.type = sn;
af.duration = hr;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.location = APPLY_SAVE_FEAR;
af.modifier = UMIN(level/4, 4) + 4;
af.level = level;
affect_join( ch,victim, &af);
pop_call();
return TRUE;
}
DO_SPELL(spell_remove_paralysis)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
int paf_type;
push_call("spell_remove_paralysis(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for ( paf_type = 0, paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (IS_SET(paf->bitvector, AFF2_STAGGERED) || IS_SET(paf->bitvector, AFF2_PARALYSIS))
{
if (dice(1,20) + level <= 11 + paf->level)
continue;
if (paf->duration >= 0)
{
if (skill_table[paf->type].msg_off)
{
act( skill_table[paf->type].msg_off, victim, NULL, NULL, TO_CHAR);
}
if (skill_table[paf->type].msg_off_room)
{
act( skill_table[paf->type].msg_off_room, victim, NULL, NULL, TO_ROOM);
}
}
paf_type = paf->type;
affect_from_char(victim, paf);
}
}
if (paf_type == 0)
{
send_to_char_color( "Nothing seems to happen.\n\r", ch);
send_to_char_color( "Nothing seems to happen.\n\r", victim);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_freedom)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
int paf_type;
push_call("spell_freedom(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for ( paf_type = 0, paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (IS_SET(paf->bitvector, AFF2_STAGGERED)
|| IS_SET(paf->bitvector, AFF2_PARALYSIS)
|| IS_SET(paf->bitvector, AFF2_PETRIFICATION)
|| IS_SET(paf->bitvector, AFF2_STAGGERED)
|| IS_SET(paf->bitvector, AFF_SLEEP)
|| IS_SET(paf->bitvector, AFF2_ENTANGLED)
|| IS_SET(paf->bitvector, AFF2_STUNNED))
{
if (paf->duration >= 0)
{
if (skill_table[paf->type].msg_off)
{
act( skill_table[paf->type].msg_off, victim, NULL, NULL, TO_CHAR);
}
if (skill_table[paf->type].msg_off_room)
{
act( skill_table[paf->type].msg_off_room, victim, NULL, NULL, TO_ROOM);
}
}
paf_type = paf->type;
affect_from_char(victim, paf);
}
}
if (paf_type == 0)
{
send_to_char_color( "Nothing seems to happen.\n\r", ch);
send_to_char_color( "Nothing seems to happen.\n\r", victim);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_revive)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int move, cond;
push_call("spell_revive(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
move = UMIN(level * 10, 200);
victim->move = UMIN( victim->move + move, victim->max_move );
act( "{138}$n beams with renewed energy.", victim, NULL, NULL, TO_ROOM );
act( "{138}You feel revitalized!", victim, NULL, NULL, TO_CHAR );
if (!IS_NPC(victim))
{
cond = 48 - victim->pcdata->condition[COND_FULL];
gain_condition(victim, COND_FULL, cond);
cond = 48 - victim->pcdata->condition[COND_THIRST];
gain_condition(victim, COND_THIRST, cond);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_rusting_grasp)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj;
int cnt, pick;
bool hit = FALSE;
push_call("spell_rusting_grasp(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
switch (race_table[get_race(victim)].material)
{
case MATERIAL_STEEL:
case MATERIAL_COLD_IRON:
damage( ch, victim, spell_dice(ch, sn, 3, 6) + UMIN(level, 15), sn, NULL );
pop_call();
return TRUE;
default:
break;
}
for (cnt = 0, obj = victim->first_carrying ; obj ; obj = obj->next)
{
if (!IS_WORN(obj))
{
continue;
}
if (obj->material != MATERIAL_STEEL
&& obj->material != MATERIAL_COLD_IRON)
{
continue;
}
if (!IS_OBJ_TYPE(obj, ITEM_ARMOR) || IS_OBJ_STAT(obj, ITEM_MAGIC|ITEM_BROKEN))
{
continue;
}
cnt++;
}
if (cnt)
{
pick = number_range(1,cnt);
for (obj = victim->first_carrying ; obj ; obj = obj->next)
{
if (!IS_WORN(obj))
{
continue;
}
if (obj->material != MATERIAL_STEEL
&& obj->material != MATERIAL_COLD_IRON)
{
continue;
}
if (!IS_OBJ_TYPE(obj, ITEM_ARMOR) || IS_OBJ_STAT(obj, ITEM_MAGIC|ITEM_BROKEN))
{
continue;
}
if (cnt == pick)
{
damage_equipment(ch, victim, obj, dice(1,6) + UMIN(level/2,10), sn, NULL);
hit = TRUE;
break;
}
}
}
if (!hit)
{
act("Your touch had no affect.", ch, NULL, NULL, TO_CHAR);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_sanctify)
{
ROOM_INDEX_DATA *room;
ROOM_TIMER_DATA rtd;
CHAR_DATA *fch;
char buf[MAX_INPUT_LENGTH];
push_call("spell_sanctify(%p,%p,%p,%p)",sn,level,ch,vo);
if (ch->in_room == NULL)
{
pop_call();
return FALSE;
}
room = ch->in_room;
if (IS_SET(room->room_flags, ROOM_SAFE))
{
send_to_char( "This area is already safe enough.\n\r", ch );
pop_call();
return FALSE;
}
for (fch = room->first_person ; fch ; fch = fch->next_in_room)
{
if (in_combat(fch))
{
send_to_char( "There is too much violence present to sanctify.\n\r", ch );
pop_call();
return FALSE;
}
}
if (ch->in_room->area->low_r_vnum == ROOM_VNUM_ARENA)
{
send_to_char("The arena may not be sanctified.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = hr * level;
rtd.bitvector = ROOM_SAFE;
rtd.level = level;
set_room_timer(ch, &rtd);
send_to_char( "The area becomes sanctified, and is a sanctuary for all.\n\r", ch);
sprintf(buf, "$n prays to %s and makes this area a sanctuary to all.", get_god_name(which_god(ch)));
act( buf, ch, NULL, NULL, TO_ROOM);
pop_call();
return TRUE;
}
DO_SPELL(spell_scintillating_pattern)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *gch;
AFFECT_DATA af;
int count, lvl, duration;
push_call("spell_scintillating_pattern(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act("{138}You weave {118}a tw{128}isti{138}ng pa{148}ttern{158} of co{168}rusca{118}ting c{128}olors.", ch, NULL, NULL, TO_CHAR);
act("{138}$n weaves {118}a tw{128}isti{138}ng pa{148}ttern{158} of co{168}rusca{118}ting c{128}olors.", ch, NULL, NULL, TO_ROOM);
for (count = lvl = 0 ; lvl <= level ; lvl++)
{
for (gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (gch->level != lvl)
continue;
if (!is_same_group(victim, gch))
continue;
if (count + gch->level > level)
{
act( "$N resists your spell.\n\r", ch, NULL, gch, TO_CHAR );
continue;
}
if (save_resist(ch, gch, sn, level))
continue;
duration = dice(1,4);
act("{138}OOooooh... pretty colors....", ch, NULL, gch, TO_VICT);
af.type = sn;
af.duration = gch->level <= 6 ? duration * 3 : gch->level <= 12 ? duration * 2 : duration;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_CONFUSION;
af.level = level;
affect_to_char( ch, gch, &af );
if (gch->level <= 12)
{
af.duration = gch->level <= 6 ? duration * 2 : duration;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_STUNNED;
af.level = level;
affect_to_char( ch, gch, &af );
}
if (gch->level <= 6)
{
af.duration = duration;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_UNCONSCIOUS;
af.level = level;
affect_to_char( ch, gch, &af );
}
count += gch->level;
if (count >= level)
break;
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_scrying)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
OBJ_DATA *obj;
AFFECT_DATA af;
push_call("spell_scrying(%p,%p,%p,%p)",sn,level,ch,vo);
if (victim == ch)
{
send_to_char("You see yourself perfectly clearly.", ch);
pop_call();
return FALSE;
}
if ((obj = get_obj_wear_type(ch, ITEM_WINDOW)) == NULL)
{
send_to_char("You are not holding a mirror to scry with.\n\r", ch);
pop_call();
return FALSE;
}
if ((victim = get_player_world(ch, target_name)) == NULL || !victim->in_room)
{
send_to_char("You cannot locate anyone by that name.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (IS_SET(victim->in_room->room_flags, ROOM_NOSCRY)
|| victim->in_room->sector_type == SECT_ASTRAL
|| victim->in_room->sector_type == SECT_ETHEREAL)
{
send_to_char("You cannot envision your subject.\n\r", ch);
pop_call();
return TRUE;
}
if (!knows_char(ch, victim))
{
send_to_char("You are not familiar enough with your subject.\n\r", ch);
pop_call();
return TRUE;
}
if (check_nondetection(ch, victim, gsn_scrying))
{
send_to_char("Your subject is wared against your scrying.\n\r", ch);
pop_call();
return TRUE;
}
if (is_affected(victim, gsn_detect_scrying))
{
if (dice(1,20) + get_affect_level(victim, gsn_detect_scrying) >= dice(1,20) + level)
act("You sense that $n is watching you.", ch, NULL, victim, TO_VICT);
else
act("You sense that someone is watching you.", ch, NULL, victim, TO_VICT);
}
if (save_resist(ch, victim, sn, level))
{
act("$N resists your attempt to scry $M.", ch, NULL, victim, TO_CHAR);
pop_call();
return TRUE;
}
af.type = sn;
af.duration = turn * level;
af.bittype = AFFECT_TO_OBJ;
af.level = level;
af.bitvector = ITEM_MAGIC;
af.location = APPLY_OBJVAL_0;
af.modifier = victim->in_room->vnum;
affect_to_obj( ch, obj, &af);
obj->owned_by = ch->pcdata->pvnum;
act( "$p {178}attunes your vision to $N.", ch, obj, victim, TO_CHAR);
act( "$p {178}glows momentarily in $n's hand.", ch, obj, NULL, TO_ROOM);
look_scrying(ch, obj, "");
pop_call();
return TRUE;
}
DO_SPELL(spell_searing_light)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
int diceroll, save;
push_call("spell_searing_light(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act("{178}A bright beam of light bursts from your hand!", victim, NULL, NULL, TO_CHAR);
act("{178}A bright beam of light bursts from $n's hand!", victim, NULL, NULL, TO_ROOM);
if ((save = save_resist(ch, victim, sn, level)) == TRUE)
{
pop_call();
return TRUE;
}
if (!save)
{
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
af.level = level;
af.duration = URANGE(1, level/2, 5);
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_DAZZLED;
affect_join( ch, victim, &af );
act("{178}You are dazzled by the brilliant light!", victim, NULL, NULL, TO_CHAR);
}
if (IS_UNDEAD(victim))
{
if (race_skill(victim, gsn_light_vulnerability))
diceroll = spell_dice(ch, sn, UMIN(level, 10), 8);
else
diceroll = spell_dice(ch, sn, UMIN(level, 10), 6);
}
else if (race_type(victim) == RTYPE_CONSTRUCT)
{
diceroll = spell_dice(ch, sn, URANGE(1, level/2, 5), 6);
}
else
{
diceroll = spell_dice(ch, sn, URANGE(1, level/2, 5), 8);
}
damage(ch, victim, diceroll, sn, NULL);
pop_call();
return TRUE;
}
DO_SPELL(spell_sending)
{
CHAR_DATA *victim;
char arg[MAX_INPUT_LENGTH];
push_call("spell_sending(%p,%p,%p,%p)",sn,level,ch,vo);
target_name = one_argument(target_name, arg);
if (arg[0] == '\0' || target_name[0] == '\0')
{
send_to_char ("Tell whom what?\n\r", ch);
pop_call();
return FALSE;
}
if ((victim = get_player_world(ch, arg)) == NULL)
{
send_to_char ("They aren't here.\n\r", ch);
pop_call();
return FALSE;
}
if (victim->desc == NULL)
{
ch_printf_color(ch, "That player is link-dead.\n\r");
pop_call();
return FALSE;
}
if (victim->desc && victim->desc->connected == CON_EDITING && get_trust (ch) < LEVEL_IMMORTAL)
{
ch_printf_color(ch, "They are currently in a writing buffer. Please try again in a few minutes.\n\r");
pop_call();
return FALSE;
}
if (blocking(victim, ch) || IS_MUTED(victim))
{
ch_printf_color(ch, "That person refuses to hear you.\n\r");
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (!IS_IMMORTAL(ch) && !knows_char(ch, victim))
{
ch_printf_color(ch, "That person refuses to hear you.\n\r");
pop_call();
return TRUE;
}
if (IS_SET(victim->act, PLR_AFK))
{
ch_printf_color(ch, "That player is afk and may not see your message.\n\r");
}
tell(ch, victim, target_name);
if (!IS_NPC(ch) && !IS_NPC(victim))
{
victim->pcdata->reply = ch;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_shillelagh)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
push_call("spell_shillelagh(%p,%p,%p,%p)",sn,level,ch,vo);
if (obj->item_type != ITEM_WEAPON)
{
send_to_char( "That object cannot be enchanted.\n\r", ch);
pop_call();
return FALSE;
}
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
{
act( "$p is already enchanted.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
switch (obj->value[0])
{
case WEAPON_TYPE_QUARTERSTAFF:
case WEAPON_TYPE_CLUB:
case WEAPON_TYPE_GREATCLUB:
break;
default:
send_to_char( "You can only enchant a club or staff.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
af.type = sn;
af.duration = turn * level;
af.bittype = AFFECT_TO_OBJ;
af.level = level;
af.bitvector = ITEM_MAGIC;
af.location = APPLY_HITROLL;
af.modifier = 1;
affect_to_obj( ch,obj, &af);
af.location = APPLY_DAMROLL;
af.modifier = 1;
affect_to_obj( ch,obj, &af);
act( "$p {138}glows {078}momentarily in your hand.", ch, obj, NULL, TO_CHAR);
act( "$p {138}glows {078}momentarily in $n's hand.", ch, obj, NULL, TO_ROOM);
pop_call();
return TRUE;
}
DO_SPELL(spell_shocking_grasp)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam;
push_call("spell_shocking_grasp(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = spell_dice(ch, sn, UMIN(level, 5), 6);
spell_damage(ch, victim, dam, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_shout)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int diceroll;
push_call("spell_shout(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
diceroll = spell_dice(ch, sn, URANGE(5, level/2, 10), 6);
spell_damage(ch, victim, diceroll, sn, level);
pop_call();
return TRUE;
}
DO_SPELL(spell_sleep)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *gch;
AFFECT_DATA af;
int count, lvl, dice;
push_call("spell_sleep(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (sn == gsn_sleep)
dice = 4;
else if (sn == gsn_deep_slumber)
dice = 10;
else
dice = level;
for (count = lvl = 0 ; lvl <= dice ; lvl++)
{
for (gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (gch->level != lvl)
continue;
if (!is_same_group(victim, gch))
continue;
if (IS_AFFECTED(gch, AFF_SLEEP) )
continue;
if (count + gch->level > dice)
{
act( "$N resists your sleep spell.\n\r", ch, NULL, gch, TO_CHAR );
continue;
}
if (sn == gsn_power_word_sleep && gch->hit > 100)
{
act( "$N resists your sleep spell.\n\r", ch, NULL, gch, TO_CHAR );
continue;
}
if (save_resist(ch, gch, sn, level))
continue;
af.type = sn;
af.duration = turn * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_SLEEP;
af.level = level;
affect_to_char( ch, gch, &af );
if (IS_AWAKE(gch))
{
/* Add to make fighting people stop fighting to sleep */
stop_fighting(gch, FALSE);
act( "You feel very sleepy ..... zzzzzz.", gch, NULL, NULL, TO_CHAR );
act( "$n closes $s eyes and drifts to sleep.", gch, NULL, NULL, TO_ROOM );
update_pos(gch, POS_RESTING);
count += gch->level;
}
if (count >= dice)
break;
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_sleet_storm)
{
ROOM_TIMER_DATA rtd;
push_call("spell_sleet_storm(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(ch->in_room->room_flags, ROOM_ICE))
{
send_to_char("This area is already covered by ice.\n\r", ch );
pop_call();
return FALSE;
}
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
{
send_to_char( "Wards prevent you from doing that here.\n\r", ch );
pop_call();
return FALSE;
}
switch (ch->in_room->sector_type)
{
case SECT_ETHEREAL:
case SECT_ASTRAL:
case SECT_UNDER_WATER:
send_to_char("That cannot be cast here.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = ch->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = level;
rtd.bitvector = ROOM_ICE;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{178}Sleet begins to fall at your command, freezing into sheets of ice.", ch, NULL, NULL, TO_CHAR);
act( "{178}Sleet falls at $n's command, freezing into sheets of ice.", ch, NULL, NULL, TO_ROOM);
pop_call();
return TRUE;
}
DO_SPELL(spell_snake_dart)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
int dam, save;
push_call("spell_snake_dart(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = spell_dice(ch, sn, 1, 6);
if (can_backstab(ch, victim, sn) && number_percent() > get_apply(victim, APPLY_FORTIFICATION))
{
int bs_dice = ROUNDUP(multi_skill_level(ch, gsn_backstab) / 2);
int bs_dam = 0;
if (get_monk_style(ch) == STYLE_SLEEPING_TIGER && class_level(ch, CLASS_MONK) >= 12)
bs_dice++;
if (bs_dice > 0)
{
if (learned(ch, gsn_greater_sneak_attack))
{
bs_dam = dice(bs_dice, 8);
}
else
{
bs_dam = dice(bs_dice, 6);
}
}
dam += bs_dam;
}
if ((save = save_resist(ch, victim, sn, level)) == TRUE)
{
damage(ch, victim, dam, sn, NULL);
}
else
{
damage(ch, victim, dam, sn, NULL);
if (save != PARTIAL)
{
if (!IS_AFFECTED(victim, AFF_POISON))
{
AFFECT_DATA af;
af.type = gsn_poison;
af.location = APPLY_CON;
af.modifier = 0-spell_dice(ch, sn, 1,10);
af.duration = level;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_POISON;
af.level = level;
affect_to_char( ch, victim, &af );
send_to_char( "You feel poison coursing through your veins.\n\r", victim );
if (ch != victim)
{
act( "$N now feels your poison.\n\r", ch, NULL, victim, TO_CHAR );
}
}
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_private_sanctum)
{
ROOM_INDEX_DATA *room;
ROOM_TIMER_DATA rtd;
push_call("spell_private_sanctum(%p,%p,%p,%p)",sn,level,ch,vo);
if (ch->in_room == NULL)
{
pop_call();
return FALSE;
}
room = ch->in_room;
if (IS_SET(room->room_flags, ROOM_PRIVATE|ROOM_NOSCRY))
{
send_to_char( "This place is already warded against such intrusion.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = 2 * hr * level;
rtd.bitvector = ROOM_PRIVATE|ROOM_NOSCRY;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{108}The area becomes secure from external observation.", ch, NULL, NULL, TO_ALL);
pop_call();
return TRUE;
}
DO_SPELL(spell_dimensional_lock)
{
ROOM_INDEX_DATA *room;
ROOM_TIMER_DATA rtd;
push_call("spell_dimensional_lock(%p,%p,%p,%p)",sn,level,ch,vo);
if (ch->in_room == NULL)
{
pop_call();
return FALSE;
}
room = ch->in_room;
if (IS_SET(room->room_flags, ROOM_NO_ASTRAL))
{
send_to_char( "This place is already warded against dimensional travel\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = hr * level;
rtd.bitvector = ROOM_NO_ASTRAL;
rtd.level = level;
set_room_timer(ch, &rtd);
act( "{128}The area glows with a shimmering emerald barrier.", ch, NULL, NULL, TO_ALL);
pop_call();
return TRUE;
}
DO_SPELL(spell_rainbow_pattern)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *gch;
AFFECT_DATA af;
int count, lvl;
push_call("spell_rainbow_pattern(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
act("{138}A glowing {118}rain{128}bow{138} patt{148}ern sw{158}irls {168}befor{118}e you.", ch, NULL, NULL, TO_ALL);
for (count = lvl = 0 ; lvl <= 24 ; lvl++)
{
for (gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (gch->level != lvl)
continue;
if (!is_same_group(victim, gch))
continue;
if (count + gch->level > level)
{
act( "$N resists your spell.\n\r", ch, NULL, gch, TO_CHAR );
continue;
}
if (save_resist(ch, gch, sn, level))
continue;
act("{138}OOooooh... pretty colors....", ch, NULL, gch, TO_VICT);
af.type = sn;
af.duration = level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_FASCINATED;
af.level = level;
affect_to_char( ch, gch, &af );
count += gch->level;
if (count >= 24)
break;
}
}
pop_call();
return TRUE;
}
/*
* Retribution domain spell c/o Paizo - Kregor
*/
DO_SPELL(spell_rebuke)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int vchsave, dam;
push_call("spell_rebuke(%p,%p,%p,%p)",sn,level,ch,vo);
if (!CAN_TALK(ch))
{
act("You are unable to utter your rebuke.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "{138}$n rebukes his foes!", ch, NULL, NULL, TO_ROOM );
act( "{138}You rebuke your foes!", ch, NULL, NULL, TO_CHAR );
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if (!is_same_group(victim, vch) && who_fighting(vch) != ch)
continue;
if ((vchsave = save_resist(ch, vch, sn, level)) == TRUE)
continue;
if (which_god(ch) == which_god(vch))
dam = spell_dice(ch, sn, UMIN(level, 10), 6);
else
dam = spell_dice(ch, sn, UMIN(level/2, 8), 8);
if (vchsave == PARTIAL)
dam /= 2;
dam /= 2;
damage(ch, vch, dam, sn, NULL);
damage(ch, vch, dam, gsn_divine_hit, NULL);
if (!valid_fight(ch, vch))
continue;
if (!vchsave)
{
if (which_god(ch) == which_god(vch))
{
af.type = sn;
af.duration = dice(1,4);
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_STUNNED;
af.level = level;
affect_join( ch, vch, &af );
}
else
{
af.type = sn;
af.duration = 1;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_STAGGERED;
af.level = level;
affect_join( ch, vch, &af );
}
}
}
pop_call();
return TRUE;
}
/*
* Target a player corpse to be able to
* send tells back and forth to player - Kregor
*/
DO_SPELL (spell_speak_with_dead)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
CHAR_DATA *victim;
PLAYER_GAME *fpl;
AFFECT_DATA af;
char buf[MAX_STRING_LENGTH];
push_call("spell_speak_with_dead(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_NPC(ch))
{
pop_call();
return FALSE;
}
if (!obj)
{
send_to_char("You can't find a corpse here.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_OBJ_TYPE(obj, ITEM_CORPSE_PC) && !IS_OBJ_TYPE(obj, ITEM_CORPSE_NPC))
{
send_to_char("That is not a corpse.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
// if corpse is npc, summon GM to play the spirit - Kregor
if (IS_OBJ_TYPE(obj, ITEM_CORPSE_NPC))
{
act( "{108}You attempt to reach the spirit of $p.", ch, obj, NULL, TO_CHAR);
act( "{108}OOC: Attempting to find a GM to interact with you...", ch, obj, NULL, TO_CHAR);
for (fpl = mud->f_player ; fpl ; fpl = fpl->next)
{
if (!IS_IMMORTAL(fpl->ch))
continue;
if (fpl->ch == ch)
continue;
sprintf(buf, "%s[IMM] $n is attempting SPEAK WITH DEAD upon $p.", get_color_string(fpl->ch, COLOR_TALK, VT102_BOLD));
act(buf, ch, obj, fpl->ch, TO_VICT);
}
pop_call();
return TRUE;
}
if ((victim = get_char_pvnum(obj->owned_by)) == NULL)
{
send_to_char("The spirit cannot be found.\n\r", ch);
pop_call();
return FALSE;
}
if (!IS_PLR(victim, PLR_DEAD))
{
send_to_char("The spirit has found a new vessel already!\n\r", ch);
pop_call();
return FALSE;
}
if (IS_PLR(victim, PLR_SOULBIND))
{
send_to_char("The spirit has been bound from the mortal plane.\n\r", ch);
pop_call();
return TRUE;
}
af.type = sn;
af.location = APPLY_NONE;
af.duration = level * turn;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.level = level;
affect_join( ch, victim, &af);
act( "{108}You see a spiritual manifestation of $N.", ch, NULL, victim, TO_CHAR);
act( "{108}You see a spiritual manifestation of $n.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
DO_SPELL(spell_suggestion)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_suggestion(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_AFFECTED(victim, AFF_DOMINATE))
{
act("$N is already under someone's influence.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (!can_understand(victim, ch, FALSE))
{
act("$N cannot understand your suggestion.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (save_resist(ch, victim, sn, level))
{
pop_call();
return TRUE;
}
af.type = sn;
af.location = APPLY_NONE;
af.duration = hr * level;
af.modifier = 0;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_join( ch,victim, &af);
act( "{138}$n's words seem so compelling.", ch, NULL, victim, TO_VICT);
act( "$N {138}seems to hang onto your words.", ch, NULL, victim, TO_CHAR );
pop_call();
return TRUE;
}
DO_SPELL(spell_suffocate)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
ROOM_INDEX_DATA *room;
ROOM_TIMER_DATA rtd;
push_call("spell_suffocate(%p,%p,%p,%p)",sn,level,ch,vo);
if ((room = victim->in_room) == NULL)
{
pop_call();
return FALSE;
}
if (IS_SET(room->room_flags, ROOM_SAFE))
{
send_to_char( "You cannot remove the air from this area.\n\r", ch );
pop_call();
return FALSE;
}
if (IS_SET(room->room_flags, ROOM_NO_AIR))
{
send_to_char( "This place is already devoid of oxygen.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = 0;
rtd.duration = level;
rtd.bitvector = ROOM_NO_AIR;
rtd.level = level;
set_room_timer(ch, &rtd);
if (ch->in_room != room)
act( "{108}The area around $N suddenly becomes devoid of breathable air.", ch, NULL, victim, TO_CHAR);
act( "{108}The area around you suddenly becomes devoid of breathable air.", victim, NULL, NULL, TO_CHAR);
act( "{108}The area around you suddenly becomes devoid of breathable air.", victim, NULL, NULL, TO_ROOM);
pop_call();
return TRUE;
}
DO_SPELL(spell_sunbeam)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
ROOM_INDEX_DATA *tar_room; //might need in case victim dies before spell runs out
int diceroll, count, save;
push_call("spell_sunbeam(%p,%p,%p,%p)",sn,level,ch,vo);
if ((tar_room = victim->in_room) == NULL)
{
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act("{178}bright beams of {138}sunlight {178}burst from your hand!", ch, NULL, NULL, TO_CHAR);
act("{178}bright beams of {138}sunlight {178}burst from $n's hand!", ch, NULL, NULL, TO_ROOM);
//1 sunbeam for every 3 caster levels
for (count = UMIN(level/3, 6), vch = tar_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (vch == victim || is_same_group(vch, victim))
{
if ((save = save_resist(ch, vch, sn, level)) != TRUE)
{
if (!save)
{
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
af.level = level;
af.duration = -1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_BLIND;
affect_join( ch, vch, &af );
act("The light burns your eyes and you cannot see!", vch, NULL, NULL, TO_CHAR);
affect_strip_desc(vch, SDESC_DARKNESS);
}
if (IS_UNDEAD(vch) || race_type(vch) == RTYPE_OOZE)
diceroll = spell_dice(ch, sn, UMIN(level, 20), 6);
else
diceroll = spell_dice(ch, sn, 4, 6);
if (race_skill(vch, gsn_light_vulnerability))
diceroll *= 2;
if (save == PARTIAL)
diceroll /= 2;
damage(ch, vch, diceroll, sn, NULL);
}
//beam is used up, even if the beam is resisted
--count;
if (count <= 0)
break;
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_sunburst)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
ROOM_INDEX_DATA *tar_room; //might need in case victim dies before spell runs out
int diceroll, save;
push_call("spell_sunburst(%p,%p,%p,%p)",sn,level,ch,vo);
if ((tar_room = victim->in_room) == NULL)
{
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act("{178}A large solar flare bursts around you!", victim, NULL, NULL, TO_ALL);
if (ch->in_room != victim->in_room)
act("{178}A large solar flare bursts around $N!", ch, NULL, victim, TO_ALL);
affect_room_strip_desc(tar_room, SDESC_DARKNESS);
for (vch = tar_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if ((save = save_resist(ch, vch, sn, level)) == TRUE)
continue;
if (!save)
{
af.type = sn;
af.location = APPLY_NONE;
af.modifier = 0;
af.level = level;
af.duration = -1;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_BLIND;
affect_join( ch, vch, &af );
act("The light burns your eyes and you cannot see!", vch, NULL, NULL, TO_CHAR);
affect_strip_desc(vch, SDESC_DARKNESS);
}
if (IS_UNDEAD(vch) || race_type(vch) == RTYPE_OOZE)
diceroll = spell_dice(ch, sn, UMIN(level, 25), 6);
else
diceroll = spell_dice(ch, sn, 6, 6);
if (race_skill(vch, gsn_light_vulnerability))
diceroll *= 2;
if (save == PARTIAL)
diceroll /= 2;
damage(ch, vch, diceroll, sn, NULL);
}
pop_call();
return TRUE;
}
/*
* Pipe all summon X spells though these functions - Kregor
*/
DO_SPELL(spell_summon_creature)
{
MOB_INDEX_DATA *pMob;
CHAR_DATA *mh;
int race, hitdice, duration, count, bloodline, cnt, rdm;
bool fMatch = FALSE;
push_call("spell_summon_creature(%p,%p,%p,%p)",sn,level,ch,vo);
if (!is_string(skill_table[sn].name))
{
bug("spell_summon_creature: no skill name for sn %d", sn);
act("Something went wrong.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
hitdice = skill_table[sn].native_level * 4 / 3;
if (sn == gsn_summon_swarm)
{
race = RACE_SWARM_RATS;
duration = UMAX(2, level / 2);
count = 1;
}
else if (sn == gsn_shambler)
{
race = RACE_SHAMBLING_MOUND;
duration = hr * 72;
count = dice(1,4) + 2;
}
else
{
// choose a race based on hitdice. nature's ally depends on sector
// summon monster picks random extraplanar creature - Kregor
for (cnt = race = 0 ; race < MAX_RACE ; race++)
{
if (race_table[race].hit_dice != hitdice && race_table[race].hit_dice != hitdice + 1)
continue;
if (sn == gsn_natures_ally_I || sn == gsn_natures_ally_II || sn == gsn_natures_ally_III
|| sn == gsn_natures_ally_IV || sn == gsn_natures_ally_V || sn == gsn_natures_ally_VI
|| sn == gsn_natures_ally_VII || sn == gsn_natures_ally_VIII || sn == gsn_natures_ally_IX)
{
// if (!IS_SET(race_table[race].sectors, 1 << ch->in_room->sector_type))
// continue;
if (race_table[race].type != RTYPE_ANIMAL
&& race_table[race].type != RTYPE_MAGICAL
&& race_table[race].type != RTYPE_VERMIN
&& race_table[race].type != RTYPE_FEY)
continue;
fMatch = TRUE;
cnt++;
}
else if (sn == gsn_summon_monster_I || sn == gsn_summon_monster_II || sn == gsn_summon_monster_III
|| sn == gsn_summon_monster_IV || sn == gsn_summon_monster_V || sn == gsn_summon_monster_VI
|| sn == gsn_summon_monster_VII || sn == gsn_summon_monster_VIII || sn == gsn_summon_monster_IX)
{
if (!IS_SET(race_table[race].flags, RSPEC_EXTRAPLANAR))
continue;
fMatch = TRUE;
cnt++;
}
else if (sn == gsn_create_lesser_undead
|| sn == gsn_create_minor_undead
|| sn == gsn_create_greater_undead
|| sn == gsn_create_undead)
{
if (race_table[race].type != RTYPE_UNDEAD)
continue;
if (race_table[race].nonability[STAT_INT])
continue;
fMatch = TRUE;
cnt++;
}
}
if (!fMatch)
{
act( "You can't seem to summon forth an ally.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
rdm = number_range(1,cnt);
for (cnt = race = 0 ; race < MAX_RACE ; race++)
{
if (race_table[race].hit_dice != hitdice && race_table[race].hit_dice != hitdice + 1)
continue;
if (sn == gsn_natures_ally_I || sn == gsn_natures_ally_II || sn == gsn_natures_ally_III
|| sn == gsn_natures_ally_IV || sn == gsn_natures_ally_V || sn == gsn_natures_ally_VI
|| sn == gsn_natures_ally_VII || sn == gsn_natures_ally_VIII || sn == gsn_natures_ally_IX)
{
// if (!IS_SET(race_table[race].sectors, 1 << ch->in_room->sector_type))
// continue;
if (race_table[race].type != RTYPE_ANIMAL
&& race_table[race].type != RTYPE_MAGICAL
&& race_table[race].type != RTYPE_VERMIN
&& race_table[race].type != RTYPE_FEY)
continue;
if (cnt++ == rdm)
break;
}
else if (sn == gsn_summon_monster_I || sn == gsn_summon_monster_II || sn == gsn_summon_monster_III
|| sn == gsn_summon_monster_IV || sn == gsn_summon_monster_V || sn == gsn_summon_monster_VI
|| sn == gsn_summon_monster_VII || sn == gsn_summon_monster_VIII || sn == gsn_summon_monster_IX)
{
if (!IS_SET(race_table[race].flags, RSPEC_EXTRAPLANAR))
continue;
if (cnt++ == rdm)
break;
}
else if (sn == gsn_create_lesser_undead
|| sn == gsn_create_minor_undead
|| sn == gsn_create_greater_undead
|| sn == gsn_create_undead)
{
if (race_table[race].type != RTYPE_UNDEAD)
continue;
if (race_table[race].nonability[STAT_INT])
continue;
if (cnt++ == rdm)
break;
}
}
duration = level;
count = 1;
}
pMob = get_mob_index(MOB_VNUM_SUMMONS);
while (count)
{
mh = create_mobile(pMob);
char_to_room( mh, ch->in_room->vnum, TRUE );
mh->race = race;
mh->level = race_table[race].hit_dice;
mh->perm_str = 10 + race_table[race].race_mod[0];
mh->perm_dex = 10 + race_table[race].race_mod[1];
mh->perm_con = 10 + race_table[race].race_mod[2];
mh->perm_int = 10 + race_table[race].race_mod[3];
mh->perm_wis = 10 + race_table[race].race_mod[4];
mh->perm_cha = 10 + race_table[race].race_mod[5];
mh->size = race_table[race].size;
mh->height = race_table[race].height;
mh->weight = race_table[race].weight;
mh->speak = race_table[race].speaks;
mh->language = race_table[race].understands;
mh->alignment = race_table[race].alignment;
mh->ethos = race_table[race].ethos;
if (sn == gsn_create_lesser_undead
|| sn == gsn_create_minor_undead
|| sn == gsn_create_greater_undead
|| sn == gsn_create_undead)
{
if (arcane_mastery(ch, SCHOOL_NECROMANCY))
{
mh->perm_str += 4;
mh->max_hit += mh->level * 2;
AFFECT_DATA af;
af.type = sn;
af.duration = -1;
af.location = APPLY_TURN_RESIST;
af.modifier = 4;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_to_char( ch, mh, &af );
}
}
else
{
if (learned(ch, gsn_augment_summoning))
{
mh->perm_str += 4;
mh->perm_con += 4;
}
if (arcane_mastery(ch, SCHOOL_CONJURATION))
{
mh->perm_str += 4;
mh->perm_con += 4;
}
}
mh->max_hit = dice(mh->level, race_type_table[race_table[race].type].hit_die);
mh->max_hit = UMAX(mh->level * race_type_table[race_table[race].type].hit_die / 2, mh->max_hit);
mh->hit = get_max_hit(mh);
RESTRING(mh->name, format("summoned %s", race_table[race].race_name));
RESTRING(mh->short_descr, format("a summoned %s", race_table[race].race_name));
RESTRING(mh->long_descr, format("A summoned %s is here.", race_table[race].race_name));
mh->npcdata->sac_timer = duration;
if (ch->cast_class == CLASS_SORCERER)
{
if ((bloodline = get_bloodline(ch)) == BLOODLINE_CELESTIAL || bloodline == BLOODLINE_ABYSSAL)
{
AFFECT_DATA af;
af.type = sn;
if (bloodline == BLOODLINE_ABYSSAL)
af.location = APPLY_DR_GOOD;
else
af.location = APPLY_DR_EVIL;
af.modifier = UMAX(1, class_level(ch, CLASS_SORCERER) / 2);
af.level = level;
af.duration = -1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, mh, &af );
}
}
if (!IS_UNDEAD(mh))
{
mh->npcdata->sac_string = STRALLOC("{178}$n shimmers and vanishes!");
act( "{178}$n appears in a shimmer of light.", mh, NULL, NULL, TO_ALL);
}
else
{
mh->npcdata->sac_string = STRALLOC("{108}$n disperses into inky blackness");
act( "{108}$n appears in a coalescing black miasma.", mh, NULL, NULL, TO_ALL);
}
SET_BIT(mh->act, ACT_SUMMONED);
char_reset(mh);
SET_BIT( mh->affected_by, AFF_DOMINATE );
add_follower( mh , ch );
--count;
}
pop_call();
return TRUE;
}
/*
* Fiendish and Celestial summoning ability - Kregor
*/
DO_SPELL(spell_summon_ally)
{
MOB_INDEX_DATA *pMob;
CHAR_DATA *mh;
int race, hitdice, count, cnt, rdm;
bool fMatch = FALSE;
push_call("spell_summon_creature(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if (level * 5 < number_percent())
{
act("Your summons failed.", ch, NULL, NULL, TO_CHAR);
act("Noone answers $n's summons.", ch, NULL, NULL, TO_ROOM);
pop_call();
return TRUE;
}
for (cnt = race = 0 ; race < MAX_RACE ; race++)
{
if (race_table[race].type != race_table[ch->race].type)
continue;
if (race_table[race].flags != race_table[ch->race].flags)
continue;
if (race_table[race].hit_dice > level)
continue;
cnt++;
fMatch = TRUE;
}
if (!fMatch)
{
act( "You can't seem to summon forth an ally.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
rdm = number_range(1, cnt);
for (cnt = race = 0 ; race < MAX_RACE ; race++)
{
if (race_table[race].type != race_table[ch->race].type)
continue;
if (race_table[race].flags != race_table[ch->race].flags)
continue;
if (race_table[race].hit_dice > level)
continue;
if (cnt++ == rdm)
break;
}
hitdice = race_table[race].hit_dice;
count = level / hitdice;
pMob = get_mob_index(MOB_VNUM_SUMMONS);
while (count)
{
mh = create_mobile(pMob);
char_to_room( mh, ch->in_room->vnum, TRUE );
mh->race = race;
mh->level = race_table[race].hit_dice;
mh->perm_str = 10 + race_table[race].race_mod[0];
mh->perm_dex = 10 + race_table[race].race_mod[1];
mh->perm_con = 10 + race_table[race].race_mod[2];
mh->perm_int = 10 + race_table[race].race_mod[3];
mh->perm_wis = 10 + race_table[race].race_mod[4];
mh->perm_cha = 10 + race_table[race].race_mod[5];
mh->size = race_table[race].size;
mh->height = race_table[race].height;
mh->weight = race_table[race].weight;
mh->speak = race_table[race].speaks;
mh->language = race_table[race].understands;
mh->alignment = race_table[race].alignment;
mh->ethos = race_table[race].ethos;
mh->max_hit = dice(mh->level, race_type_table[race_table[race].type].hit_die);
mh->max_hit = UMAX(mh->level * race_type_table[race_table[race].type].hit_die / 2, mh->max_hit);
mh->hit = get_max_hit(mh);
RESTRING(mh->name, format("summoned %s", race_table[race].race_name));
RESTRING(mh->short_descr, format("a summoned %s", race_table[race].race_name));
RESTRING(mh->long_descr, format("A summoned %s is here.", race_table[race].race_name));
mh->npcdata->sac_timer = level;
if (!IS_EVIL(mh))
{
mh->npcdata->sac_string = STRALLOC("{178}$n shimmers and vanishes!");
act( "{178}$n appears in a shimmer of light.", mh, NULL, NULL, TO_ALL);
}
else
{
mh->npcdata->sac_string = STRALLOC("{108}$n vanishes in a puff black smoke!");
act( "{118}$n appears in a burst of hellish flames!", mh, NULL, NULL, TO_ALL);
}
SET_BIT(mh->act, ACT_SUMMONED);
char_reset(mh);
if (who_fighting(ch))
fight(mh, who_fighting(ch));
--count;
}
pop_call();
return TRUE;
}
DO_SPELL(spell_conj_elemental)
{
MOB_INDEX_DATA *pMob;
AFFECT_DATA af;
CHAR_DATA *mh;
char arg[MAX_INPUT_LENGTH];
int race, hitdice, mod, bloodline, class;
push_call("spell_conj_elemental(%p,%p,%p,%p)",sn,level,ch,vo);
hitdice = skill_table[sn].native_level * 4 / 3;
hitdice = URANGE(hitdice - 1, level, hitdice + 1);
if (sn == gsn_elemental_swarm)
hitdice = hitdice / 4 * 3;
class = ch->cast_class;
if (sn == gsn_elemental_swarm || *target_name == '\0')
{
race = number_range(RACE_ELEMENTAL_AIR, RACE_ELEMENTAL_WATER);
if (class == CLASS_CLERIC)
{
if (has_domain(ch, DOMAIN_AIR))
race = RACE_ELEMENTAL_AIR;
else if (has_domain(ch, DOMAIN_EARTH))
race = RACE_ELEMENTAL_EARTH;
else if (has_domain(ch, DOMAIN_FIRE))
race = RACE_ELEMENTAL_FIRE;
else if (has_domain(ch, DOMAIN_WATER))
race = RACE_ELEMENTAL_WATER;
}
else if (class == CLASS_SORCERER)
{
if (get_bloodline(ch) == BLOODLINE_AIR)
race = RACE_ELEMENTAL_AIR;
else if (get_bloodline(ch) == BLOODLINE_EARTH)
race = RACE_ELEMENTAL_EARTH;
else if (get_bloodline(ch) == BLOODLINE_FIRE)
race = RACE_ELEMENTAL_FIRE;
else if (get_bloodline(ch) == BLOODLINE_WATER)
race = RACE_ELEMENTAL_WATER;
}
}
else
{
one_argument(target_name, arg);
if (!strcasecmp(arg, "air"))
race = RACE_ELEMENTAL_AIR;
else if (!strcasecmp(arg, "earth"))
race = RACE_ELEMENTAL_EARTH;
else if (!strcasecmp(arg, "fire"))
race = RACE_ELEMENTAL_FIRE;
else if (!strcasecmp(arg, "water"))
race = RACE_ELEMENTAL_WATER;
else
{
send_to_char("That is not an element.\n\r", ch);
pop_call();
return FALSE;
}
}
if (class == CLASS_CLERIC || class == CLASS_SORCERER)
{
if ((race == RACE_ELEMENTAL_AIR && !has_domain(ch, DOMAIN_AIR) && get_bloodline(ch) != BLOODLINE_AIR)
|| (race == RACE_ELEMENTAL_EARTH && !has_domain(ch, DOMAIN_EARTH) && get_bloodline(ch) != BLOODLINE_EARTH)
|| (race == RACE_ELEMENTAL_FIRE && !has_domain(ch, DOMAIN_FIRE) && get_bloodline(ch) != BLOODLINE_FIRE)
|| (race == RACE_ELEMENTAL_WATER && !has_domain(ch, DOMAIN_WATER) && get_bloodline(ch) != BLOODLINE_WATER))
{
act("You have no control over that elemental domain.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
if ((pMob = get_mob_index(MOB_VNUM_SUMMONS)) == NULL)
{
send_to_char( "You cannot create an elemental now.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
// sets up continuous affect to continue summoning
if (sn == gsn_elemental_swarm && !is_affected(ch, gsn_elemental_swarm))
{
af.type = sn;
af.duration = turn * level;
af.level = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = dice(3,4);
affect_to_char( ch, ch, &af );
act("You open up a portal to the elemental planes.", ch, NULL, NULL, TO_CHAR);
act("$n opens up a portal to the elemental planes.", ch, NULL, NULL, TO_ROOM);
}
mh = create_mobile( pMob );
char_to_room( mh, ch->in_room->vnum, TRUE );
mh->npcdata->sac_timer = turn * level;
switch (hitdice)
{
case 1:
case 2:
case 3:
mh->size = SIZE_SMALL;
mod = 0;
break;
case 4:
case 5:
case 6:
mh->size = SIZE_MEDIUM;
mod = 1;
break;
case 7:
case 8:
case 9:
mh->size = SIZE_LARGE;
mod = 2;
break;
default:
mh->size = SIZE_HUGE;
mod = 3;
break;
}
mh->race = race;
mh->level = hitdice;
mh->perm_str = 10 + race_table[race].race_mod[0];
mh->perm_dex = 10 + race_table[race].race_mod[1];
mh->perm_con = 10 + race_table[race].race_mod[2];
mh->perm_int = 10 + race_table[race].race_mod[3];
mh->perm_wis = 10 + race_table[race].race_mod[4];
mh->perm_cha = 10 + race_table[race].race_mod[5];
mh->height = race_table[race].height;
mh->weight = race_table[race].weight;
mh->speak = race_table[race].speaks;
mh->language = race_table[race].understands;
mh->alignment = race_table[race].alignment;
mh->ethos = race_table[race].ethos;
if (mod)
{
mh->height *= 2 * mod;
mh->weight *= 8 * mod;
}
if (learned(ch, gsn_augment_summoning))
{
mh->perm_str += 4;
mh->perm_con += 4;
}
mh->perm_str += mod * 4;
mh->perm_con += mod * 2;
if (race == RACE_ELEMENTAL_AIR)
mh->perm_dex += mod * 4;
mh->max_hit = dice(mh->level, race_type_table[race_table[mh->race].type].hit_die);
mh->max_hit = UMAX(mh->level * race_type_table[race_table[mh->race].type].hit_die / 2, mh->max_hit);
mh->hit = get_max_hit(mh);
RESTRING(mh->name, format("summoned %s", race_table[race].race_name));
RESTRING(mh->short_descr, format("a summoned %s", race_table[race].race_name));
RESTRING(mh->long_descr, format("A summoned %s is here.", race_table[race].race_name));
if (mh->size >= SIZE_LARGE)
{
af.type = -1;
af.duration = -1;
af.level = level;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_DR_NONE;
af.modifier = mh->size == SIZE_LARGE ? 5 : 10;
affect_to_char( mh, mh, &af );
}
SET_BIT( mh->affected_by , AFF_DOMINATE );
if ((bloodline = get_bloodline(ch)) == BLOODLINE_CELESTIAL || bloodline == BLOODLINE_ABYSSAL)
{
AFFECT_DATA af;
af.type = sn;
if (bloodline == BLOODLINE_ABYSSAL)
af.location = APPLY_DR_GOOD;
else
af.location = APPLY_DR_EVIL;
af.modifier = UMAX(1, class_level(ch, CLASS_SORCERER) / 2);
af.level = level;
af.duration = -1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, mh, &af );
}
switch(race)
{
case RACE_ELEMENTAL_FIRE:
act( "{118}A fiery humanoid forms from a swirl of flames.", mh, NULL, NULL, TO_ROOM );
break;
case RACE_ELEMENTAL_WATER:
act( "{148}A swirl of water forms into a humanoid shape.", mh, NULL, NULL, TO_ROOM );
break;
case RACE_ELEMENTAL_AIR:
act( "{168}A blast of wind swirls into a whispy figure.", mh, NULL, NULL, TO_ROOM );
break;
case RACE_ELEMENTAL_EARTH:
act( "{038}A large creature of rock rises out of the ground.", mh, NULL, NULL, TO_ROOM );
break;
}
add_follower( mh , ch );
pop_call();
return TRUE;
}
DO_SPELL(spell_contraption)
{
MOB_INDEX_DATA *pMob;
CHAR_DATA *mh;
int race, hitdice, mod;
push_call("spell_contraption(%p,%p,%p,%p)",sn,level,ch,vo);
if (sn == gsn_major_contraption)
{
hitdice = level;
}
else
{
hitdice = skill_table[sn].native_level * 4 / 3;
hitdice = URANGE(hitdice - 1, level, hitdice + 1);
}
if (sn == gsn_major_contraption)
race = RACE_GOLEM_CLOCKWORK;
else
race = RACE_ANIMATED_OBJ;
if ((pMob = get_mob_index(MOB_VNUM_SUMMONS)) == NULL)
{
send_to_char( "You cannot seem to conjure your contraption.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
mh = create_mobile( pMob );
char_to_room( mh, ch->in_room->vnum, TRUE );
mh->npcdata->sac_timer = turn * level;
if (sn == gsn_major_contraption)
{
mod = 0;
}
else
{
switch (hitdice)
{
case 1:
case 2:
case 3:
mh->size = SIZE_SMALL;
mod = 0;
break;
case 4:
case 5:
case 6:
mh->size = SIZE_MEDIUM;
mod = 1;
break;
case 7:
case 8:
case 9:
mh->size = SIZE_LARGE;
mod = 2;
break;
default:
mh->size = SIZE_HUGE;
mod = 3;
break;
}
}
mh->race = race;
mh->level = hitdice;
mh->perm_str = 10 + race_table[race].race_mod[0];
mh->perm_dex = 10 + race_table[race].race_mod[1];
mh->perm_con = 10 + race_table[race].race_mod[2];
mh->perm_int = 10 + race_table[race].race_mod[3];
mh->perm_wis = 10 + race_table[race].race_mod[4];
mh->perm_cha = 10 + race_table[race].race_mod[5];
mh->height = race_table[race].height;
mh->weight = race_table[race].weight;
mh->speak = race_table[race].speaks;
mh->language = race_table[race].understands;
mh->alignment = race_table[race].alignment;
mh->ethos = race_table[race].ethos;
if (mod)
{
mh->height *= 2 * mod;
mh->weight *= 8 * mod;
}
if (learned(ch, gsn_augment_summoning))
{
mh->perm_str += 4;
mh->perm_con += 4;
}
mh->perm_str += mod * 4;
mh->perm_con += mod * 2;
mh->max_hit = dice(mh->level, race_type_table[race_table[mh->race].type].hit_die);
mh->max_hit = UMAX(mh->level * race_type_table[race_table[mh->race].type].hit_die / 2, mh->max_hit);
mh->hit = get_max_hit(mh);
RESTRING(mh->name, format("clockwork golem %s m%s", size_types[get_size(mh)], pMob->vnum));
RESTRING(mh->short_descr, format("a %s clockwork golem", size_types[get_size(mh)]));
RESTRING(mh->long_descr, format("{038}A %s shambling clockwork golem wizzes and clanks.", size_types[get_size(mh)]));
if (race == RACE_GOLEM_CLOCKWORK)
{
mh->learned[gsn_rock_throwing]++;
}
SET_BIT( mh->affected_by , AFF_DOMINATE );
act( "{078}$n rises from the ground in a swirl of gears and cogs!", mh, NULL, NULL, TO_ROOM );
add_follower( mh , ch );
pop_call();
return TRUE;
}
DO_SPELL(spell_contagion)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
DISEASE_DATA *dis, *dis_next;
char buf1[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
int disease;
push_call("spell_contagion(%p,%p,%p,%p)",sn,level,ch,vo);
if (!is_string(target_name))
{
disease = DIS_BLINDING_SICKNESS;
}
else
{
two_arguments(target_name, buf1, buf2);
if ((disease = lookup_disease(target_name)) == -1)
{
if ((disease = lookup_disease(buf2)) == -1)
{
if ((disease = lookup_disease(buf1)) == -1)
{
act("That is not a valid disease.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
}
}
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (save_resist(ch, victim, sn, level))
{
pop_call();
return TRUE;
}
infect_char(ch, victim, disease);
for (dis = victim->first_disease ; dis ; dis = dis_next)
{
dis_next = dis->next;
if (dis->type != disease)
continue;
if (dis->incubation < disease_table[dis->type].incubation)
{
dis->incubation = disease_table[dis->type].incubation;
disease_update(victim);
break;
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_summon_shadow)
{
MOB_INDEX_DATA *pMob;
CHAR_DATA *mh;
int roll, number, bloodline;
push_call("spell_summon_shadow(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (roll = spell_dice(ch, sn, 1,3), number = 0 ; number < roll ; number++)
{
pMob = get_mob_index( 23 );
mh = create_mobile( pMob );
char_to_room( mh, ch->in_room->vnum, TRUE );
SET_BIT(mh->affected_by , AFF_DOMINATE);
SET_BIT(mh->act, ACT_SUMMONED);
mh->npcdata->sac_timer = level;
mh->npcdata->sac_string = STRALLOC("$n dissipates into swirling shadows.");
if ((bloodline = get_bloodline(ch)) == BLOODLINE_CELESTIAL || bloodline == BLOODLINE_ABYSSAL)
{
AFFECT_DATA af;
af.type = sn;
if (bloodline == BLOODLINE_ABYSSAL)
af.location = APPLY_DR_GOOD;
else
af.location = APPLY_DR_EVIL;
af.modifier = UMAX(1, class_level(ch, CLASS_SORCERER) / 2);
af.level = level;
af.duration = -1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
affect_join( ch, mh, &af );
}
act( "A shadow appears out of a rift in the light.", ch, NULL, NULL, TO_CHAR);
act( "A shadow appears out of a rift in the light.", ch, NULL, NULL, TO_ROOM);
add_follower(mh, ch);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_time_stop)
{
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
push_call("spell_time_stop(%p,%p,%p,%p)",sn,level,ch,vo);
if (is_safe(ch, NULL))
{
act("You may not freeze time in this area.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
for (vch = ch->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (ch == vch)
continue;
af.type = sn;
af.level = level;
af.duration = dice(1,4) + 1;
af.bittype = AFFECT_TO_NONE;
af.bitvector = AFF_NONE;
af.location = APPLY_NONE;
af.modifier = 0;
affect_join( ch, vch, &af);
act( "{118}You stop in mid-action!", vch, NULL, NULL, TO_CHAR);
act( "{118}$n freezes in mid-action!", vch, NULL, NULL, TO_ROOM);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_transmute_metal)
{
OBJ_DATA *obj = (OBJ_DATA *) vo;
AFFECT_DATA af;
int value;
push_call("spell_transmute_metal(%p,%p,%p,%p)",sn,level,ch,vo);
if (material_table[obj->material].parent != MATERIAL_TYPE_METAL)
{
act( "You can only transmute metal to another metal.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!is_string(target_name))
{
act( "Transmute $p to what?", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if ((value = get_flag(target_name, material_types)) == -1
|| material_table[value].parent != MATERIAL_TYPE_METAL)
{
act( "$t is not a valid type of metal.", ch, target_name, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (value == obj->material)
{
act( "$p is already that type of metal.", ch, obj, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "$p transmutes into $T!", ch, obj, material_types[value], TO_ALL);
af.type = sn;
af.duration = turn*level;
af.location = APPLY_MATERIAL;
af.modifier = value - obj->material;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.level = level;
affect_to_obj( ch,obj, &af);
pop_call();
return TRUE;
}
DO_SPELL(spell_telepathic_bond)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *gch;
AFFECT_DATA af;
int cnt;
push_call("spell_telepathic_bond(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (cnt = 0, gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (!is_same_group(gch, victim))
continue;
if (is_affected(gch, sn))
continue;
if (gch->perm_int < 3)
continue;
if (cnt >= level / 3)
break;
af.type = sn;
af.location = APPLY_NONE;
af.duration = level * hr;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_TELEPATHY;
af.level = level;
affect_to_char( ch, gch, &af);
cnt++;
act( "{138}You open a channel in your mind to $N.", ch, NULL, gch, TO_CHAR);
act( "{138}You feel your mind attune to $n.", ch, NULL, gch, TO_VICT );
}
pop_call();
return TRUE;
}
/*
* REAL Teleport spell!
* targets room names, has percent chance to go wrong,
* PC can teleport to his recall point with no error.
* Kregor - 6/29/07
*/
DO_SPELL(spell_teleport)
{
char dest[MAX_INPUT_LENGTH];
int room, roll, point, attempts, sector, low_room, max_room;
ROOM_INDEX_DATA *old_room;
CHAR_DATA *rch, *rch_next;
bool Mishap = FALSE;
bool Random = FALSE;
bool OffTarget = FALSE;
push_call("spell_teleport(%p,%p,%p,%p)",sn,level,ch,vo);
if (!is_string(target_name))
{
send_to_char( "Teleport where?\n\r", ch );
pop_call();
return FALSE;
}
target_name = one_argument(target_name, dest);
roll = number_range(1,100);
old_room = ch->in_room;
if (!strcasecmp(dest, "waypoint"))
{
if (is_number(target_name))
{
point = atol(target_name);
if ((room = ch->pcdata->waypoint[point]) <= 0)
{
send_to_char("You do not have that waypoint set.\n\r", ch);
pop_call();
return FALSE;
}
if (roll == 100)
Random = TRUE;
else if (roll >= 98)
OffTarget = TRUE;
}
else
{
send_to_char("The waypoint must be a number.\n\r", ch);
pop_call();
return FALSE;
}
}
else if (!strcasecmp(dest, "home"))
{
if ((room = ch->pcdata->recall) <= 0)
{
send_to_char( "You do not have a recall point set.\n\r", ch);
pop_call();
return FALSE;
}
}
else if (!ForReal)
{
pop_call();
return TRUE;
}
else
{
ch_printf_color(ch, "You envision in your mind, '%s'.\n\r", dest);
if (roll == 100)
Mishap = TRUE;
else if (roll >= 95)
Random = TRUE;
else if (roll >= 89)
OffTarget = TRUE;
for (room = 200 ; room < MAX_VNUM ; room++)
{
if (room == ch->in_room->vnum)
continue;
if (room_index[room] == NULL)
continue;
if (is_multi_name_list_short(dest, room_index[room]->name)
&& is_room_good_for_teleport(ch, room))
{
break;
}
}
}
if ( room == MAX_VNUM )
{
send_to_char_color("{138}The weave can't seem to find your destination.\n\r", ch);
pop_call();
return TRUE;
}
if (!is_room_good_for_teleport(ch, ch->in_room->vnum))
{
send_to_char( "Mystic wards prevent you from leaving.\n\r", ch );
pop_call();
return TRUE;
}
if (domain_apotheosis(ch, DOMAIN_TRAVEL))
{
Random = Mishap = OffTarget = FALSE;
}
if (Random || Mishap)
{
for (attempts = 0 ; attempts < 1000 ; attempts++)
{
room = number_range(1, MAX_VNUM-1);
if (room == ch->in_room->vnum)
continue;
if (room_index[room] == NULL)
continue;
if (is_room_good_for_teleport(ch, room))
{
break;
}
}
if (Mishap)
{
send_to_char_color("{118}The weave scrambles you in your attempt!\n\r", ch);
damage(ch, ch, dice(1, 10), TYPE_NOFIGHT, NULL);
for (rch = old_room->first_person ; rch ; rch = rch_next)
{
rch_next = rch->next_in_room;
if (is_master(rch, ch))
{
send_to_char_color("{118}The weave scrambles you in your teleport!\n\r", rch);
damage(rch, rch, dice(1, 10), TYPE_NOFIGHT, NULL);
}
}
}
if (attempts >= 1000)
{
send_to_char_color("{138}The weave decides you should remain where you are.\n\r", ch);
pop_call();
return TRUE;
}
else if (!Mishap)
{
send_to_char_color("{138}Your attempt transported you somewhere else!\n\r", ch);
}
}
if (OffTarget)
{
low_room = room_index[room]->area->low_r_vnum;
max_room = room_index[room]->area->hi_r_vnum;
sector = room_index[room]->sector_type;
for (attempts = 0 ; attempts < 1000 ; attempts++)
{
room = number_range(low_room, max_room);
if (room == ch->in_room->vnum)
continue;
if (room_index[room] == NULL)
continue;
if (is_room_good_for_teleport(ch, room))
{
break;
}
}
if (attempts >= 1000)
{
send_to_char_color("{138}The weave decides you should remain where you are.\n\r", ch);
pop_call();
return TRUE;
}
else
{
send_to_char_color("{138}The weave deposits you a little off from your target.\n\r", ch);
}
}
act( "{138}$n disappears suddenly in a flash of light!", ch, NULL, NULL, TO_ROOM );
if (in_combat(ch))
withdraw_combat(ch);
char_from_room( ch );
char_to_room( ch, room, TRUE );
act( "{138}$n arrives suddenly in a flash of light!", ch, NULL, NULL, TO_ROOM );
act( "{138}You appear in a flash of light!", ch, NULL, NULL, TO_CHAR );
do_look( ch, "auto" );
for (rch = old_room->first_person ; rch ; rch = rch_next)
{
rch_next = rch->next_in_room;
if (is_master(rch, ch))
{
act( "$n disappears suddenly in a flash of light.", rch, NULL, NULL, TO_ROOM);
char_from_room(rch);
char_to_room(rch, room, TRUE);
act( "$n arrives suddenly in a flash of light.", rch, NULL, NULL, TO_ROOM);
act( "{138}You appear in a flash of light!", rch, NULL, NULL, TO_CHAR );
do_look(rch, "auto");
}
}
if (!IS_NPC(ch))
{
mprog_greet_trigger(ch);
oprog_greet_trigger(ch);
rprog_greet_trigger(ch);
}
pop_call();
return TRUE;
}
/*
* Greater teleport adds targeting characters, no misteleport,
* group argument will teleport entire group - Kregor 10/20/07
* added code support for Pass Plant, Shadow Walk - Kregor 2/4/11
* merged in teleportation circle - Kregor 3/16/11
*/
DO_SPELL(spell_greater_teleport)
{
char dest[MAX_INPUT_LENGTH];
char charmssg[MAX_INPUT_LENGTH];
char bamfout[MAX_INPUT_LENGTH];
char bamfin[MAX_INPUT_LENGTH];
int room, point;
ROOM_INDEX_DATA *old_room = NULL;
ROOM_INDEX_DATA *to_room = NULL;
OBJ_DATA *gate;
CHAR_DATA *victim, *rch, *rch_next;
bool fGroup = FALSE;
push_call("spell_greater_teleport(%p,%p,%p,%p)",sn,level,ch,vo);
if (!is_string(target_name))
{
send_to_char( "Teleport where?\n\r", ch );
pop_call();
return FALSE;
}
target_name = one_argument(target_name, dest);
if (!strcasecmp(dest, "group"))
{
if (sn == gsn_dimension_door || sn == gsn_shadow_jump || sn == gsn_abundant_step || sn == gsn_earthwalk)
{
send_to_char("You cannot transport your group with this spell.\n\r", ch);
pop_call();
return FALSE;
}
fGroup = TRUE;
target_name = one_argument(target_name, dest);
}
old_room = ch->in_room;
if (!strcasecmp(dest, "waypoint"))
{
if (is_number(target_name))
{
point = atol(target_name);
if ((room = ch->pcdata->waypoint[point]) <= 0)
{
send_to_char("You do not have that waypoint set.\n\r", ch);
pop_call();
return FALSE;
}
}
else
{
send_to_char("The waypoint must be a number.\n\r", ch);
pop_call();
return FALSE;
}
}
else if (!strcasecmp(dest, "home"))
{
if ((room = ch->pcdata->recall) <= 0)
{
send_to_char( "You do not have a recall point set.\n\r", ch);
pop_call();
return FALSE;
}
}
else if ((victim = get_char_world(ch, dest)) != NULL)
{
if ((to_room = victim->in_room) == NULL || !is_room_good_for_teleport(ch, to_room->vnum))
{
send_to_char( "That character can't be reached.\n\r", ch);
pop_call();
return FALSE;
}
room = victim->in_room->vnum;
}
else if (!ForReal)
{
pop_call();
return TRUE;
}
else
{
ch_printf_color(ch, "You envision in your mind, '%s'.\n\r", dest);
for (room = 200 ; room <= MAX_VNUM ; room++)
{
if (room == ch->in_room->vnum)
continue;
if (room_index[room] == NULL)
continue;
if ((sn == gsn_dimension_door || sn == gsn_abundant_step || sn == gsn_shadow_jump) && room_index[room]->area != old_room->area)
continue;
if (is_multi_name_list_short(dest, room_index[room]->name)
&& is_room_good_for_teleport(ch, room))
{
break;
}
}
}
if (IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
|| IS_SET(ch->in_room->area->flags, ROOM_NO_ASTRAL)
|| IS_SET(ch->in_room->area->flags, AFLAG_NOTELEPORT)
|| IS_SET(ch->in_room->area->flags, AFLAG_NORECALL)
|| is_affected(ch, gsn_dimensional_anchor))
{
send_to_char( "Mystic energies prevent you from leaving.\n\r", ch );
pop_call();
return TRUE;
}
if ((to_room = get_room_index(room)) == NULL)
{
send_to_char_color("{138}The mystic energies can't seem to find your destination.\n\r", ch);
pop_call();
return TRUE;
}
if (!is_room_good_for_teleport(ch, room))
{
send_to_char_color("{138}The mystic energies can't seem to find your destination.\n\r", ch);
pop_call();
return TRUE;
}
if (sn == gsn_teleportation_circle)
{
gate = create_object(get_obj_index(OBJ_VNUM_GATE), 0);
if (!gate)
{
ch_printf_color(ch,"You try to create a portal, but it does not seem possible somehow.\n\r");
pop_call();
return FALSE;
}
gate->value[0] = -1;
gate->value[3] = to_room->vnum;
gate->sac_timer = level * turn;
obj_to_room(gate, ch->in_room->vnum);
act( "$p opens before you.", ch, gate, NULL, TO_CHAR);
act( "$p opens before $n.", ch, gate, NULL, TO_ROOM);
pop_call();
return TRUE;
}
if (sn == gsn_shadow_walk || sn == gsn_shadow_jump)
{
if (mud->sunlight != SUN_DARK)
{
if (get_room_light(ch->in_room) >= LIGHT_NORMAL || get_room_light(to_room) >= LIGHT_NORMAL)
{
send_to_char_color("{108}It is not dark enough to walk the shadows to there.\n\r", ch);
pop_call();
return TRUE;
}
}
}
if (sn == gsn_pass_plant)
{
switch (ch->in_room->sector_type)
{
case SECT_FIELD:
case SECT_FOREST:
case SECT_HILLS:
case SECT_SWAMP:
break;
default:
send_to_char_color("{028}You cannot find suitable plant life to pass through.\n\r", ch);
pop_call();
return TRUE;
}
switch (to_room->sector_type)
{
case SECT_FIELD:
case SECT_FOREST:
case SECT_HILLS:
case SECT_SWAMP:
break;
default:
send_to_char_color("{028}You cannot find suitable plant life to pass through.\n\r", ch);
pop_call();
return TRUE;
}
}
if (sn == gsn_earthwalk)
{
switch (ch->in_room->sector_type)
{
case SECT_MOUNTAIN:
case SECT_UNDER_GROUND:
case SECT_DEEP_EARTH:
case SECT_TUNDRA:
case SECT_BARREN:
break;
default:
send_to_char_color("{028}You are not in stony terrain.\n\r", ch);
pop_call();
return TRUE;
}
switch (to_room->sector_type)
{
case SECT_MOUNTAIN:
case SECT_UNDER_GROUND:
case SECT_DEEP_EARTH:
case SECT_TUNDRA:
case SECT_BARREN:
break;
default:
send_to_char_color("{028}You cannot find stony terrain in your destination.\n\r", ch);
pop_call();
return TRUE;
}
}
if (sn == gsn_shadow_walk || sn == gsn_shadow_jump)
{
strcpy(charmssg, "{108}You emerge from the shadows!");
strcpy(bamfin, "{108}$n swirls out of the shadows!");
strcpy(bamfout, "{108}$n melts into the shadows!");
}
else if (sn == gsn_pass_plant)
{
strcpy(charmssg, "{028}You emerge from the foliage!");
strcpy(bamfin, "{028}$n emerges from the foliage!");
strcpy(bamfout, "{028}$n merges into the foliage!");
}
else if (sn == gsn_earthwalk)
{
strcpy(charmssg, "{038}You emerge from the earth!");
strcpy(bamfin, "{038}$n forms out of earth!");
strcpy(bamfout, "{038}$n melds into the earth!");
}
else if (sn == gsn_abundant_step)
{
strcpy(charmssg, "{188}You step into another space!");
strcpy(bamfin, "{168}$n steps in out of nowhere!");
strcpy(bamfout, "{168}$n seems to step into nowhere!");
}
else
{
strcpy(charmssg, "{138}You appear in a flash of light!");
strcpy(bamfin, "{138}$n appears in a flash of light!");
strcpy(bamfout, "{138}$n disappears in a flash of light!");
}
act( bamfout, ch, NULL, NULL, TO_ROOM );
if (in_combat(ch))
withdraw_combat(ch);
char_from_room( ch );
char_to_room( ch, room, TRUE );
act( bamfin, ch, NULL, NULL, TO_ROOM );
act( charmssg, ch, NULL, NULL, TO_CHAR );
do_look( ch, "auto" );
if (sn != gsn_shadow_jump)
{
for (rch = old_room->first_person ; rch ; rch = rch_next)
{
rch_next = rch->next_in_room;
if (is_master(rch, ch) || (fGroup && is_same_group(rch, ch)))
{
act( bamfout, rch, NULL, NULL, TO_ROOM);
char_from_room(rch);
char_to_room(rch, room, TRUE);
act( bamfin, rch, NULL, NULL, TO_ROOM);
act( charmssg, rch, NULL, NULL, TO_CHAR );
do_look(rch, "auto");
}
}
}
if (!IS_NPC(ch))
{
mprog_greet_trigger(ch);
oprog_greet_trigger(ch);
rprog_greet_trigger(ch);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_teleport_object)
{
CHAR_DATA *victim;
OBJ_DATA *obj = (OBJ_DATA *) vo;
push_call("spell_teleport_object(%p,%p,%p,%p)",sn,level,ch,vo);
if ((victim = get_player_world(ch, target_name)) == NULL
|| !is_room_good_for_teleport(ch, ch->in_room->vnum)
|| !is_room_good_for_teleport(ch, victim->in_room->vnum))
{
send_to_char("Your cannot reach your target.\n\r", ch);
pop_call();
return TRUE;
}
if (victim == ch)
{
send_to_char("Transport it to yourself??", ch);
pop_call();
return FALSE;
}
if (IS_OBJ_STAT(obj, ITEM_NODROP|ITEM_NOREMOVE))
{
send_to_char( "You can't seem to let go of it.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
act( "$p {108}slowly dematerializes...", ch, obj, NULL, TO_CHAR );
act( "$p {108}slowly dematerializes from $n's hands...", ch, obj, NULL, TO_ROOM );
obj_from_char( obj );
if (get_carry_w(victim) + get_obj_weight (obj) > can_carry_w(victim))
{
obj_to_room( obj, victim->in_room->vnum );
act( "$p {138}from $n appears before you.", ch, obj, victim, TO_VICT);
act( "$p {138}appears before $n!", victim, obj, NULL, TO_ROOM );
}
else
{
obj_to_char( obj, victim );
act( "$p {138}from $n appears in your hands!", ch, obj, victim, TO_VICT);
act( "$p {138}appears in $n's hands!", victim, obj, NULL, TO_ROOM );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_tongues)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
AFFECT_DATA *paf, *paf_next;
push_call("spell_tongues(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
if ( is_affected(victim, sn) )
{
for ( paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if( paf->type == sn )
{
paf->duration = hr * level;
}
}
if (ch != victim)
act( "{178}$n's spell of tongues is refreshed.", ch, NULL, victim, TO_CHAR );
act( "{178}Your spell of tongues is refreshed.", victim, NULL, NULL, TO_CHAR );
pop_call();
return TRUE;
}
if ( IS_AFFECTED(victim, AFF_TONGUES))
{
send_to_char( "That person is already speaking in tongues.\n\r", ch);
pop_call();
return FALSE;
}
act( "{178}$n starts speaking in tongues.", victim, NULL, NULL, TO_ROOM);
act( "{178}You start speaking in tongues.", victim, NULL, NULL, TO_CHAR);
af.type = sn;
af.duration = hr * level;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_TONGUES;
af.level = level;
affect_to_char( ch, victim, &af);
pop_call();
return TRUE;
}
DO_SPELL(spell_true_form)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA *paf, *paf_next;
int paf_type, diceroll;
push_call("spell_true_form(%p,%p,%p,%p)",sn,level,ch,vo);
diceroll = dice(1, 20) + UMIN(level, 20);
if (!ForReal)
{
pop_call();
return TRUE;
}
for ( paf_type = 0, paf = victim->first_affect; paf != NULL; paf = paf_next )
{
paf_next = paf->next;
if (!IS_SET(skill_table[paf->type].spell_desc, SDESC_POLYMORPH))
{
continue;
}
else if (is_spell(paf->type))
{
if (diceroll < 11 + paf->level)
continue;
}
else
{
if (save_resist(ch, victim, sn, paf->level))
continue;
}
paf_type = paf->type;
revert_morph(victim, FALSE);
}
if (paf_type == 0)
{
send_to_char( "Nothing appears to happen.\n\r", ch );
}
else
{
act("$N morphs back into a $T.", victim, race_table[get_race(victim)].race_name, NULL, TO_ROOM);
act("You morph back into a $T.", victim, race_table[get_race(victim)].race_name, NULL, TO_CHAR);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_vampiric_touch)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
int dam;
push_call("spell_vampiric_touch(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
dam = spell_dice(ch, sn, UMIN(level/2, 10), 6);
dam = UMIN(dam, ch->hit + 10);
damage( ch, victim, dam, sn, NULL );
af.type = sn;
af.duration = hr;
af.bittype = AFFECT_TO_NONE;
af.bitvector = 0;
af.location = APPLY_HIT;
af.modifier = dam;
af.level = level;
affect_join( ch, ch, &af );
pop_call();
return TRUE;
}
DO_SPELL(spell_ventriloquate)
{
char buf1[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
char text1[MAX_STRING_LENGTH];
char text2[MAX_STRING_LENGTH];
char speaker[MAX_INPUT_LENGTH];
CHAR_DATA *vch, *victim;
bool fVictim = FALSE;
push_call("spell_ventriloquate(%p,%p,%p,%p)",sn,level,ch,vo);
if( ch->in_room == NULL )
{
pop_call();
return FALSE;
}
target_name = one_argument( target_name, speaker );
if ((victim = get_char_room (ch, speaker)) != NULL)
{
fVictim = TRUE;
}
if (fVictim && victim->level >= LEVEL_IMMORTAL)
{
act("You cannot victimize $N.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
strcpy(text2, target_name);
sprintf(text1, "%s'%s'", get_color_string(ch, COLOR_SPEECH, VT102_DIM), text2);
act( "You try to make $T say, $t", ch, text1, fVictim ? PERS(victim, ch) : speaker, TO_CHAR);
for (text1[0] = '\0', vch = ch->in_room->first_person ; vch ; vch = vch->next_in_room)
{
if (vch == ch)
{
continue;
}
sprintf(text1, "%s'%s'", get_color_string(IS_NPC(ch) ? vch : ch, COLOR_SPEECH, VT102_DIM), text2);
sprintf (buf1, "%s says, %s", fVictim ? PERS(victim, vch) : capitalize(speaker), text1);
sprintf (buf2, "Someone nearby says, %s", text2);
if (fVictim && vch == victim)
{
act( "Someone that sounds like you says, $t", victim, text1, fVictim ? PERS(victim, ch) : speaker, TO_CHAR);
}
else if (will_save(vch, ch, level, sn))
{
act( "$t", ch, buf2, vch, TO_VICT);
}
else
{
act( "$t", ch, buf1, vch, TO_VICT);
}
}
pop_call();
return TRUE;
}
DO_SPELL(spell_wall)
{
ROOM_TIMER_DATA rtd;
EXIT_DATA *pExitData;
int dir;
push_call("spell_wall(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(ch->in_room->room_flags, ROOM_BLOCK))
{
send_to_char("This area is already blocked.\n\r", ch );
pop_call();
return FALSE;
}
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
{
send_to_char( "Magical wards prevent your conjuration.\n\r", ch );
pop_call();
return FALSE;
}
if (!is_string(target_name) || (dir = direction_door(target_name)) == -1)
{
send_to_char("Block what direction?\n\r",ch);
pop_call();
return FALSE;
}
if ((pExitData = get_exit(ch->in_room->vnum, dir)) == NULL)
{
send_to_char("There is no exit in that direction!\n\r",ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
rtd.vnum = ch->in_room->vnum;
rtd.type = sn;
rtd.location = APPLY_NONE;
rtd.modifier = dir;
rtd.duration = sn == gsn_wall_of_force ? level : sn == gsn_wall_of_iron ? -1 : turn * level;
rtd.bitvector = ROOM_BLOCK;
rtd.level = level;
set_room_timer(ch, &rtd);
if (sn == gsn_wall_of_stone)
{
act( "{108}A wall of stone springs up to the $t", ch, dir_name[dir], NULL, TO_CHAR);
act( "{108}A wall of stone springs up to the $t", ch, dir_name[dir], NULL, TO_ROOM);
}
if (sn == gsn_wall_of_iron)
{
act( "{108}A wall of iron springs up to the $t", ch, dir_name[dir], NULL, TO_CHAR);
act( "{108}A wall of iron springs up to the $t", ch, dir_name[dir], NULL, TO_ROOM);
}
if (sn == gsn_wall_of_ice)
{
act( "{168}A wall of ice springs up to the $t", ch, dir_name[dir], NULL, TO_CHAR);
act( "{168}A wall of ice springs up to the $t", ch, dir_name[dir], NULL, TO_ROOM);
}
if (sn == gsn_wall_of_force)
{
act( "{168}You conjure wall of force to the $t", ch, dir_name[dir], NULL, TO_CHAR);
}
pop_call();
return TRUE;
}
DO_SPELL(spell_water_breathing)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *gch;
AFFECT_DATA af;
int count;
push_call("spell_water_breathing(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (count = 0, gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (!is_same_group(victim, gch))
{
continue;
}
count ++;
}
for (gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (!is_same_group(victim, gch))
{
continue;
}
af.type = sn;
af.duration = (hr * level * 2) / count;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_WATER_BREATH;
af.level = level;
affect_to_char( ch, gch, &af );
act( "{068}$N gains the ability to breathe water.", ch, NULL, gch, TO_CHAR );
act( "{068}You gain the ability to breathe water.", gch, NULL, NULL, TO_CHAR );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_water_walk)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *gch;
AFFECT_DATA af;
int count;
push_call("spell_water_walk(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
for (count = 0, gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (!is_same_group(victim, gch))
{
continue;
}
count ++;
}
for (gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
{
if (!is_same_group(victim, gch))
{
continue;
}
af.type = sn;
af.duration = (hr * level) / count;
af.location = APPLY_NONE;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF_WATER_WALK;
af.level = level;
affect_to_char( ch, gch, &af );
act( "{068}$N gains the ability to walk on water.", ch, NULL, gch, TO_CHAR );
act( "{068}You gain the ability to walk on water.", gch, NULL, NULL, TO_CHAR );
}
pop_call();
return TRUE;
}
DO_SPELL(spell_water_to_wine)
{
OBJ_DATA *obj = (OBJ_DATA *)vo;
char arg3[MAX_INPUT_LENGTH];
int liquid;
push_call("spell_water_to_wine(%p,%p,%p,%p)",sn,level,ch,vo);
if (obj == NULL)
{
send_to_char("You are not carrying that.\n\r",ch);
pop_call();
return FALSE;
}
target_name = one_argument(target_name, arg3);
target_name = one_argument(target_name, arg3);
if (obj->item_type != ITEM_DRINK_CON)
{
send_to_char("That is not a drink container.\n\r",ch);
pop_call();
return FALSE;
}
if (!strlen(arg3))
{
send_to_char("Metamorphose to what kind of liquid?\n\r",ch);
pop_call();
return FALSE;
}
for (liquid = 0 ; liquid < LIQ_MAX ; liquid++)
{
if (!str_prefix(arg3, liq_table[liquid].liq_name))
{
break;
}
}
if (liquid == LIQ_MAX)
{
send_to_char("There is no such liquid.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (obj->value[2] == liquid)
{
ch_printf_color(ch, "%s is already filled with %s\n\r", capitalize(obj->short_descr), liq_table[liquid].liq_name);
pop_call();
return TRUE;
}
else
{
ch_printf_color(ch, "You transform the %s in %s to %s.\n\r", liq_table[obj->value[2]].liq_name, obj->short_descr, liq_table[liquid].liq_name);
obj->value[2] = liquid;
}
pop_call();
return TRUE;
}
/*
* Function for the Word of Faith alignment spells:
* Blasphemy, Dictum, Holy Word and Word of Chaos
* all pass thru this - Kregor
*/
DO_SPELL(spell_word_of_faith)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
CHAR_DATA *vch, *vch_next;
AFFECT_DATA af;
int vchsave, diff;
char name[20];
push_call("word_of_faith(%p,%p,%p,%p)",sn,level,ch,vo);
if (!CAN_TALK(ch))
{
act("You are unable to utter a word of faith.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (sn == gsn_blasphemy)
{
act( "{138}$n rebukes the powers of good for $s god!", ch, NULL, NULL, TO_ROOM );
act( "{138}You rebuke the powers of good for your god!", ch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_dictum)
{
act( "{138}$n rebukes the powers of entropy for $s god!", ch, NULL, NULL, TO_ROOM );
act( "{138}You rebuke the powers of entropy for your god!", ch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_holy_word)
{
act( "{138}$n rebukes the powers of evil for $s god!", ch, NULL, NULL, TO_ROOM );
act( "{138}You rebuke the powers of evil for your god!", ch, NULL, NULL, TO_CHAR );
}
if (sn == gsn_word_of_chaos)
{
act( "{138}$n rebukes the powers of law for $s god!", ch, NULL, NULL, TO_ROOM );
act( "{138}You rebuke the powers of law for your god!", ch, NULL, NULL, TO_CHAR );
}
strcpy(name, skill_table[sn].noun_damage);
for (vch = victim->in_room->last_person ; vch ; vch = vch_next)
{
vch_next = vch->prev_in_room;
if (!can_mass_cast(ch, vch, sn))
continue;
if ((sn == gsn_blasphemy && IS_EVIL(vch))
|| (sn == gsn_holy_word && IS_GOOD(vch))
|| (sn == gsn_word_of_chaos && IS_CHAOTIC(vch))
|| (sn == gsn_dictum && IS_LAWFUL(vch)))
continue;
if ((diff = level - vch->level) < 0)
{
act( "$N is unaffected by your $t.", ch, name, vch, TO_CHAR);
act( "You are unaffected by $n's $t.", ch, name, vch, TO_VICT);
act( "$N is unaffected by $N's $t.", ch, name, vch, TO_NOTVICT);
continue;
}
if ((vchsave = save_resist(ch, vch, sn, level)) == TRUE)
continue;
if (IS_NPC(vch) && race_type(vch) == RTYPE_OUTSIDER && rspec_req(vch, RSPEC_EXTRAPLANAR))
{
act( "You are banished back to your home plane!", ch, name, vch, TO_VICT);
act( "$N is banished back to $S home plane!", ch, name, vch, TO_ROOM);
junk_mob(vch);
continue;
}
if (diff >= 10)
{
if (vchsave == PARTIAL)
{
damage(ch, vch, dice(3,6)+UMIN(level,25), sn, NULL);
if (!valid_fight(ch, vch))
continue;
}
else
{
damage(ch, vch, ch->level * 10, sn, NULL);
continue;
}
}
if (diff >= 5)
{
af.type = sn;
af.duration = vchsave ? 2 : dice(1,10)*turn;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_PARALYSIS;
af.level = level;
affect_join( ch, vch, &af );
}
af.type = sn;
af.duration = vchsave ? 2 : dice(2,4);
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
if (sn == gsn_blasphemy)
af.bitvector = AFF2_SICKENED;
else if (sn == gsn_word_of_chaos)
af.bitvector = AFF2_CONFUSION;
else if (sn == gsn_dictum)
af.bitvector = AFF2_STAGGERED;
else
af.bitvector = AFF_BLIND;
af.level = level;
affect_join( ch, vch, &af );
}
pop_call();
return TRUE;
}
/*
* Added group option for word of recall - Kregor
*/
DO_SPELL(spell_word_of_recall)
{
CHAR_DATA *rch, *rch_next;
ROOM_INDEX_DATA *old_room;
int vnum;
bool fGroup = FALSE;
push_call("spell_word_of_recall(%p,%p,%p,%p)",sn,level,ch,vo);
if (ch->in_room->vnum == ch->pcdata->recall)
{
send_to_char("You are already in your recall room.\n\r", ch);
pop_call();
return FALSE;
}
if (!is_room_good_for_teleport(ch, ch->in_room->vnum)
|| !is_room_good_for_teleport(ch, ch->pcdata->recall))
{
act("You cannot reach that destination.", ch, NULL, NULL, TO_CHAR);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (!strcasecmp(target_name, "group"))
fGroup = TRUE;
if (ch->pcdata->recall == ROOM_VNUM_SCHOOL)
{
if (ch->in_room->area->low_r_vnum != ROOM_VNUM_SCHOOL)
{
ch->pcdata->recall = ROOM_VNUM_TEMPLE;
}
}
if (ch->pcdata->recall < 3 || room_index[ch->pcdata->recall] == NULL)
{
ch->pcdata->recall = ROOM_VNUM_TEMPLE;
}
old_room = ch->in_room;
vnum = ch->pcdata->recall;
if (!recall(ch, ch->pcdata->recall))
{
pop_call();
return TRUE;
}
if (fGroup)
{
for (rch = old_room->first_person ; rch ; rch = rch_next)
{
rch_next = rch->next_in_room;
if (is_same_group(rch, ch))
{
recall(rch, vnum);
}
}
}
pop_call();
return TRUE;
}
/*
* Spell functions of currently unused spells
*/
DO_SPELL(spell_summon)
{
CHAR_DATA *victim;
push_call("spell_summon(%p,%p,%p,%p)",sn,level,ch,vo);
if (target_name[0] == '\0')
{
send_to_char("Whom would you like to summon?\n\r", ch);
pop_call();
return FALSE;
}
if ((victim = get_char_area(ch, target_name)) == NULL)
{
send_to_char( "You cannot find anyone by that name.\n\r", ch);
pop_call();
return FALSE;
}
if (victim == ch || IS_NPC(victim))
{
send_to_char( "You can only summon other PCs.\n\r", ch );
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
if (is_safe(ch, victim)
|| !is_room_good_for_teleport(victim, ch->in_room->vnum)
|| !is_room_good_for_teleport(victim, victim->in_room->vnum))
{
send_to_char( "You failed to summon your target.\n\r", ch );
pop_call();
return TRUE;
}
if (!is_same_group(ch, victim) && save_resist(ch, victim, sn, level))
{
act( "$N resists your summoning spell.", ch, NULL, NULL, TO_CHAR);
act( "You feel a strange magical force pulling at you.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}
act( "{138}$n disappears in a flash of light!", victim, NULL, NULL, TO_ROOM );
act( "{138}You disappear suddenly.", victim, NULL, NULL, TO_CHAR );
if (in_combat(victim))
withdraw_combat(victim);
char_from_room( victim );
char_to_room( victim, ch->in_room->vnum, TRUE );
act( "{138}$n arrives in a flash of light!", victim, NULL, NULL, TO_ROOM );
act( "{138}You appear somewhere else, in a flash of light!", victim, NULL, NULL, TO_CHAR );
do_look( victim, "auto" );
pop_call();
return TRUE;
}
DO_SPELL(spell_winged_call)
{
CHAR_DATA *mob;
push_call("spell_winged_call(%p,%p,%p,%p)",sn,level,ch,vo);
if (!ForReal)
{
pop_call();
return TRUE;
}
mob = create_mobile(mob_index[MOB_VNUM_WINGED_CALL]);
char_to_room(mob, ch->in_room->vnum, TRUE);
mob->level = level / 2;
mob->max_hit = level * 5;
mob->hit = get_max_hit(mob);
SET_BIT(mob->affected_by , AFF_DOMINATE);
act( "You summon $N from the high mountains.", ch, NULL, mob, TO_CHAR);
act( "$n summons $N from the high mountains.", ch, NULL, mob, TO_ROOM);
add_follower(mob, ch);
pop_call();
return TRUE;
}
DO_SPELL(spell_possess)
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
push_call("spell_posses(%p,%p,%p,%p)",sn,level,ch,vo);
if (IS_SET(ch->in_room->room_flags, ROOM_SAFE))
{
send_to_char("You are forbidden from casting that here.\n\r", ch);
pop_call();
return FALSE;
}
if (IS_NPC(ch) || ch->desc->original)
{
send_to_char("You are not in your original state.\n\r", ch);
pop_call();
return FALSE;
}
if (victim == ch)
{
send_to_char("You already have control over yourself.\n\r", ch);
pop_call();
return FALSE;
}
if (victim->desc)
{
ch_printf_color(ch, "%s is already possessed.\n\r", victim->short_descr);
pop_call();
return FALSE;
}
if (!IS_NPC(victim) || !can_mass_cast(ch, victim, sn))
{
send_to_char("They seem to be unaffected by your magic.\n\r", ch);
pop_call();
return TRUE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
SET_BIT(victim->act,ACT_SENTINEL);
REMOVE_BIT(victim->act, ACT_AGGRESSIVE);
af.type = sn;
af.duration = 12;
af.location = 0;
af.modifier = 0;
af.bittype = AFFECT_TO_CHAR;
af.bitvector = AFF2_POSSESS;
af.level = level;
affect_to_char( ch, victim, &af );
log_printf("%s has possessed %s",get_name(ch), victim->short_descr);
ch->desc->character = victim;
ch->desc->original = ch;
victim->desc = ch->desc;
ch->desc = NULL;
ch->pcdata->switched = TRUE;
ch_printf_color(victim, "You have possessed %s.\n\r", get_name(victim));
pop_call();
return TRUE;
}
DO_SPELL(spell_totem)
{
OBJ_DATA *totem;
push_call("spell_totem(%p,%p,%p,%p)",sn,level,ch,vo);
for (totem = ch->in_room->first_content ; totem ; totem = totem->next_content)
{
if (totem->item_type == ITEM_TOTEM)
{
send_to_char("There is already a totem here.\n\r", ch);
pop_call();
return FALSE;
}
}
switch (ch->in_room->sector_type)
{
case SECT_AIR:
case SECT_ETHEREAL:
case SECT_ASTRAL:
case SECT_LAKE:
case SECT_RIVER:
case SECT_OCEAN:
send_to_char("You cannot cast a totem here.\n\r", ch);
pop_call();
return FALSE;
}
if (!ForReal)
{
pop_call();
return TRUE;
}
totem = create_object( get_obj_index( OBJ_VNUM_TOTEM ), 0 );
totem->timer = level;
totem->level = level;
act( "A totem rises up from the ground.", ch, NULL, NULL, TO_CHAR );
act( "A totem rises up from the ground.", ch, NULL, NULL, TO_ROOM );
obj_to_room( totem, ch->in_room->vnum );
switch (tolower(target_name[0]))
{
case 'c':
totem->value[0] = skill_lookup("neutralize poison");
totem->value[1] = skill_lookup("remove blindness");
totem->value[2] = skill_lookup("remove curse");
totem->value[3] = skill_lookup("cure critical");
break;
case 'p':
totem->value[0] = skill_lookup("bulls strength");
totem->value[1] = skill_lookup("bears endurance");
totem->value[2] = skill_lookup("bless");
if (ch->alignment < 0)
{
totem->value[3] = skill_lookup("protection from good");
}
else
{
totem->value[3] = skill_lookup("protection from evil");
}
break;
default:
totem->value[0] = skill_lookup("heal");
totem->value[1] = skill_lookup("cure light");
totem->value[2] = skill_lookup("cure serious");
totem->value[3] = skill_lookup("cure critical");
break;
}
pop_call();
return TRUE;
}