/*************************************************************************** * 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; }