/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /* MurkMUD++ - A Windows compatible, C++ compatible Merc 2.2 Mud. \author Jon A. Lambert \date 01/02/2007 \version 1.5 \remarks This source code copyright (C) 2005, 2006, 2007 by Jon A. Lambert All rights reserved. Use governed by the MurkMUD++ public license found in license.murk++ */ #include "os.hpp" #include "config.hpp" #include "globals.hpp" #include "utils.hpp" #include "object.hpp" #include "room.hpp" #include "affect.hpp" #include "objproto.hpp" #include "mobproto.hpp" #include "world.hpp" // temp externs extern void damage(Character *ch, Character *victim, int dam, int dt); extern std::string extra_bit_name (int extra_flags); extern std::string affect_loc_name (int location); extern bool is_same_group (Character * ach, Character * bch); /* * Spell functions. */ void Character::spell_acid_blast (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int dam; dam = dice (lvl, 6); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_armor (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->has_affect(sn)) return; af.type = sn; af.duration = 24; af.modifier = -20; af.location = APPLY_AC; af.bitvector = 0; victim->affect_to_char(&af); victim->send_to_char ("You feel someone protecting you.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_bless (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->position == POS_FIGHTING || victim->has_affect(sn)) return; af.type = sn; af.duration = 6 + lvl; af.location = APPLY_HITROLL; af.modifier = lvl / 8; af.bitvector = 0; victim->affect_to_char(&af); af.location = APPLY_SAVING_SPELL; af.modifier = 0 - lvl / 8; victim->affect_to_char(&af); victim->send_to_char ("You feel righteous.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_blindness (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_BLIND) || victim->saves_spell (lvl)) return; af.type = sn; af.location = APPLY_HITROLL; af.modifier = -4; af.duration = 1 + lvl; af.bitvector = AFF_BLIND; victim->affect_to_char(&af); victim->send_to_char ("You are blinded!\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_burning_hands (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; static const sh_int dam_each[] = { 0, 0, 0, 0, 0, 14, 17, 20, 23, 26, 29, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48 }; lvl = std::min (lvl, (int) (sizeof (dam_each) / sizeof (dam_each[0]) - 1)); lvl = std::max (0, lvl); int dam = number_range (dam_each[lvl] / 2, dam_each[lvl] * 2); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_call_lightning (int sn, int lvl, void *vo) { Character *vch; if (!is_outside()) { send_to_char ("You must be out of doors.\r\n"); return; } if (!g_world->is_raining()) { send_to_char ("You need bad weather.\r\n"); return; } int dam = dice (lvl / 2, 8); send_to_char ("God's lightning strikes your foes!\r\n"); act ("$n calls God's lightning to strike $s foes!", NULL, NULL, TO_ROOM); CharIter c, next; for (c = char_list.begin(); c != char_list.end(); c = next) { vch = *c; next = ++c; if (vch->in_room == NULL) continue; if (vch->in_room == in_room) { if (vch != this && (is_npc () ? !vch->is_npc () : vch->is_npc ())) damage (this, vch, vch->saves_spell (lvl) ? dam / 2 : dam, sn); continue; } if (vch->in_room->area == in_room->area && vch->is_outside() && vch->is_awake ()) vch->send_to_char ("Lightning flashes in the sky.\r\n"); } return; } void Character::spell_cause_light (int sn, int lvl, void *vo) { damage (this, (Character *) vo, dice (1, 8) + lvl / 3, sn); return; } void Character::spell_cause_critical (int sn, int lvl, void *vo) { damage (this, (Character *) vo, dice (3, 8) + lvl - 6, sn); return; } void Character::spell_cause_serious (int sn, int lvl, void *vo) { damage (this, (Character *) vo, dice (2, 8) + lvl / 2, sn); return; } void Character::spell_change_sex (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->has_affect(sn)) return; af.type = sn; af.duration = 10 * lvl; af.location = APPLY_SEX; do { af.modifier = number_range (0, 2) - victim->sex; } while (af.modifier == 0); af.bitvector = 0; victim->affect_to_char(&af); victim->send_to_char ("You feel different.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_charm_person (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim == this) { send_to_char ("You like yourself even better!\r\n"); return; } if (victim->is_affected (AFF_CHARM) || is_affected (AFF_CHARM) || lvl < victim->level || victim->saves_spell (lvl)) return; if (victim->master) victim->stop_follower(); victim->add_follower(this); af.type = sn; af.duration = number_fuzzy (lvl / 4); af.location = 0; af.modifier = 0; af.bitvector = AFF_CHARM; victim->affect_to_char(&af); act ("Isn't $n just so nice?", NULL, victim, TO_VICT); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_chill_touch (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; static const sh_int dam_each[] = { 0, 0, 0, 6, 7, 8, 9, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 26, 26, 26, 27 }; Affect af; lvl = std::min (lvl, (int) (sizeof (dam_each) / sizeof (dam_each[0]) - 1)); lvl = std::max (0, lvl); int dam = number_range (dam_each[lvl] / 2, dam_each[lvl] * 2); if (!victim->saves_spell (lvl)) { af.type = sn; af.duration = 6; af.location = APPLY_STR; af.modifier = -1; af.bitvector = 0; victim->affect_join (&af); } else { dam /= 2; } damage (this, victim, dam, sn); return; } void Character::spell_colour_spray (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; static const sh_int dam_each[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 35, 40, 45, 50, 55, 55, 55, 56, 57, 58, 58, 59, 60, 61, 61, 62, 63, 64, 64, 65, 66, 67, 67, 68, 69, 70, 70, 71, 72, 73, 73, 74, 75, 76, 76, 77, 78, 79, 79 }; lvl = std::min (lvl, (int) (sizeof (dam_each) / sizeof (dam_each[0]) - 1)); lvl = std::max (0, lvl); int dam = number_range (dam_each[lvl] / 2, dam_each[lvl] * 2); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_continual_light (int sn, int lvl, void *vo) { Object *light; light = get_obj_index(OBJ_VNUM_LIGHT_BALL)->create_object(0); light->obj_to_room (in_room); act ("$n twiddles $s thumbs and $p appears.", light, NULL, TO_ROOM); act ("You twiddle your thumbs and $p appears.", light, NULL, TO_CHAR); return; } void Character::spell_control_weather (int sn, int lvl, void *vo) { int change = dice (lvl / 3, 4); if (!str_cmp (target_name, "better")) change *= 1; else if (!str_cmp (target_name, "worse")) change *= -1; else send_to_char ("Do you want it to get better or worse?\r\n"); g_world->change_weather(change); send_to_char ("Ok.\r\n"); return; } void Character::spell_create_food (int sn, int lvl, void *vo) { Object* mushroom = get_obj_index(OBJ_VNUM_MUSHROOM)->create_object(0); mushroom->value[0] = 5 + lvl; mushroom->obj_to_room (in_room); act ("$p suddenly appears.", mushroom, NULL, TO_ROOM); act ("$p suddenly appears.", mushroom, NULL, TO_CHAR); return; } void Character::spell_create_spring (int sn, int lvl, void *vo) { Object* spring = get_obj_index(OBJ_VNUM_SPRING)->create_object(0); spring->timer = lvl; spring->obj_to_room (in_room); act ("$p flows from the ground.", spring, NULL, TO_ROOM); act ("$p flows from the ground.", spring, NULL, TO_CHAR); return; } void Character::spell_create_water (int sn, int lvl, void *vo) { Object *obj = (Object *) vo; if (obj->item_type != ITEM_DRINK_CON) { send_to_char ("It is unable to hold water.\r\n"); return; } if (obj->value[2] != LIQ_WATER && obj->value[1] != 0) { send_to_char ("It contains some other liquid.\r\n"); return; } int water = std::min (lvl * (g_world->is_raining() ? 4 : 2), obj->value[0] - obj->value[1] ); if (water > 0) { obj->value[2] = LIQ_WATER; obj->value[1] += water; if (!is_name ("water", obj->name)) { obj->name = obj->name + " water"; } act ("$p is filled.", obj, NULL, TO_CHAR); } return; } void Character::spell_cure_blindness (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; if (!victim->has_affect(skill_lookup("blindness"))) return; victim->affect_strip (skill_lookup("blindness")); victim->send_to_char ("Your vision returns!\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_cure_critical (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int heal = dice (3, 8) + lvl - 6; victim->hit = std::min (victim->hit + heal, victim->max_hit); victim->update_pos(); victim->send_to_char ("You feel better!\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_cure_light (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int heal = dice (1, 8) + lvl / 3; victim->hit = std::min (victim->hit + heal, victim->max_hit); victim->update_pos(); victim->send_to_char ("You feel better!\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_cure_poison (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int pois = skill_lookup("poison"); if (victim->has_affect(pois)) { victim->affect_strip (pois); act ("$N looks better.", NULL, victim, TO_NOTVICT); victim->send_to_char ("A warm feeling runs through your body.\r\n"); send_to_char ("Ok.\r\n"); } return; } void Character::spell_cure_serious (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int heal = dice (2, 8) + lvl / 2; victim->hit = std::min (victim->hit + heal, victim->max_hit); victim->update_pos(); victim->send_to_char ("You feel better!\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_curse (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_CURSE) || victim->saves_spell (lvl)) return; af.type = sn; af.duration = 4 * lvl; af.location = APPLY_HITROLL; af.modifier = -1; af.bitvector = AFF_CURSE; victim->affect_to_char(&af); af.location = APPLY_SAVING_SPELL; af.modifier = 1; victim->affect_to_char(&af); victim->send_to_char ("You feel unclean.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_detect_evil (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_DETECT_EVIL)) return; af.type = sn; af.duration = lvl; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_EVIL; victim->affect_to_char(&af); victim->send_to_char ("Your eyes tingle.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_detect_hidden (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_DETECT_HIDDEN)) return; af.type = sn; af.duration = lvl; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = AFF_DETECT_HIDDEN; victim->affect_to_char(&af); victim->send_to_char ("Your awareness improves.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_detect_invis (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_DETECT_INVIS)) return; af.type = sn; af.duration = lvl; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_INVIS; victim->affect_to_char(&af); victim->send_to_char ("Your eyes tingle.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_detect_magic (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_DETECT_MAGIC)) return; af.type = sn; af.duration = lvl; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_DETECT_MAGIC; victim->affect_to_char(&af); victim->send_to_char ("Your eyes tingle.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_detect_poison (int sn, int lvl, void *vo) { Object *obj = (Object *) vo; if (obj->item_type == ITEM_DRINK_CON || obj->item_type == ITEM_FOOD) { if (obj->value[3] != 0) send_to_char ("You smell poisonous fumes.\r\n"); else send_to_char ("It looks very delicious.\r\n"); } else { send_to_char ("It doesn't look poisoned.\r\n"); } return; } void Character::spell_dispel_magic (int sn, int lvl, void *vo) { send_to_char ("Sorry but this spell has been disabled.\r\n"); return; } void Character::spell_dispel_evil (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; if (!is_npc () && is_evil ()) victim = this; if (victim->is_good ()) { act ("God protects $N.", NULL, victim, TO_ROOM); return; } if (victim->is_neutral ()) { act ("$N does not seem to be affected.", NULL, victim, TO_CHAR); return; } int dam = dice (lvl, 4); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_earthquake (int sn, int lvl, void *vo) { send_to_char ("The earth trembles beneath your feet!\r\n"); act ("$n makes the earth tremble and shiver.", NULL, NULL, TO_ROOM); CharIter c, next; for (c = char_list.begin(); c != char_list.end(); c = next) { Character* vch = *c; next = ++c; if (vch->in_room == NULL) continue; if (vch->in_room == in_room) { if (vch != this && (is_npc () ? !vch->is_npc () : vch->is_npc ())) damage (this, vch, lvl + dice (2, 8), sn); continue; } if (vch->in_room->area == in_room->area) vch->send_to_char ("The earth trembles and shivers.\r\n"); } return; } void Character::spell_enchant_weapon (int sn, int lvl, void *vo) { Object *obj = (Object *) vo; Affect *paf; if (obj->item_type != ITEM_WEAPON || obj->is_obj_stat(ITEM_MAGIC) || !obj->affected.empty()) return; paf = new Affect(); paf->type = sn; paf->duration = -1; paf->location = APPLY_HITROLL; paf->modifier = lvl / 5; paf->bitvector = 0; obj->affected.push_back(paf); paf = new Affect(); paf->type = -1; paf->duration = -1; paf->location = APPLY_DAMROLL; paf->modifier = lvl / 10; paf->bitvector = 0; obj->affected.push_back(paf); obj->level = number_fuzzy (level - 5); if (is_good ()) { SET_BIT (obj->extra_flags, ITEM_ANTI_EVIL); act ("$p glows blue.", obj, NULL, TO_CHAR); } else if (is_evil ()) { SET_BIT (obj->extra_flags, ITEM_ANTI_GOOD); act ("$p glows red.", obj, NULL, TO_CHAR); } else { SET_BIT (obj->extra_flags, ITEM_ANTI_EVIL); SET_BIT (obj->extra_flags, ITEM_ANTI_GOOD); act ("$p glows yellow.", obj, NULL, TO_CHAR); } send_to_char ("Ok.\r\n"); return; } /* * Drain XP, MANA, HP. * Caster gains HP. */ void Character::spell_energy_drain (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int dam; if (victim->saves_spell (lvl)) return; alignment = std::max (-1000, alignment - 200); if (victim->level <= 2) { dam = hit + 1; } else { victim->gain_exp(0 - number_range (lvl / 2, 3 * lvl / 2)); victim->mana /= 2; victim->move /= 2; dam = dice (1, lvl); hit += dam; } damage (this, victim, dam, sn); return; } void Character::spell_fireball (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; static const sh_int dam_each[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130 }; lvl = std::min (lvl, (int) (sizeof (dam_each) / sizeof (dam_each[0]) - 1)); lvl = std::max (0, lvl); int dam = number_range (dam_each[lvl] / 2, dam_each[lvl] * 2); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_flamestrike (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int dam = dice (6, lvl); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_faerie_fire (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_FAERIE_FIRE)) return; af.type = sn; af.duration = lvl; af.location = APPLY_AC; af.modifier = 2 * lvl; af.bitvector = AFF_FAERIE_FIRE; victim->affect_to_char(&af); victim->send_to_char ("You are surrounded by a pink outline.\r\n"); victim->act ("$n is surrounded by a pink outline.", NULL, NULL, TO_ROOM); return; } void Character::spell_faerie_fog (int sn, int lvl, void *vo) { act ("$n conjures a cloud of purple smoke.", NULL, NULL, TO_ROOM); send_to_char ("You conjure a cloud of purple smoke.\r\n"); CharIter ich; for (ich = in_room->people.begin(); ich != in_room->people.end(); ich++) { if (*ich == this || (*ich)->saves_spell (lvl)) continue; (*ich)->affect_strip (skill_lookup("invis")); (*ich)->affect_strip (skill_lookup("mass invis")); (*ich)->affect_strip (skill_lookup("sneak")); REMOVE_BIT ((*ich)->affected_by, AFF_HIDE); REMOVE_BIT ((*ich)->affected_by, AFF_INVISIBLE); REMOVE_BIT ((*ich)->affected_by, AFF_SNEAK); (*ich)->act ("$n is revealed!", NULL, NULL, TO_ROOM); (*ich)->send_to_char ("You are revealed!\r\n"); } return; } void Character::spell_fly (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_FLYING)) return; af.type = sn; af.duration = lvl + 3; af.location = 0; af.modifier = 0; af.bitvector = AFF_FLYING; victim->affect_to_char(&af); victim->send_to_char ("Your feet rise off the ground.\r\n"); victim->act ("$n's feet rise off the ground.", NULL, NULL, TO_ROOM); return; } void Character::spell_gate (int sn, int lvl, void *vo) { get_mob_index(MOB_VNUM_VAMPIRE)->create_mobile()->char_to_room(in_room); return; } /* * Spell for mega1.are from Glop/Erkenbrand. */ void Character::spell_general_purpose (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int dam = number_range (25, 100); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_giant_strength (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->has_affect(sn)) return; af.type = sn; af.duration = lvl; af.location = APPLY_STR; af.modifier = 1 + (lvl >= 18) + (lvl >= 25); af.bitvector = 0; victim->affect_to_char(&af); victim->send_to_char ("You feel stronger.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_harm (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int dam; dam = std::max (20, victim->hit - dice (1, 4)); if (victim->saves_spell (lvl)) dam = std::min (50, dam / 4); dam = std::min (100, dam); damage (this, victim, dam, sn); return; } void Character::spell_heal (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; victim->hit = std::min (victim->hit + 100, victim->max_hit); victim->update_pos(); victim->send_to_char ("A warm feeling fills your body.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } /* * Spell for mega1.are from Glop/Erkenbrand. */ void Character::spell_high_explosive (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int dam = number_range (30, 120); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_identify (int sn, int lvl, void *vo) { Object *obj = (Object *) vo; char buf[MAX_STRING_LENGTH]; snprintf (buf, sizeof buf, "Object '%s' is type %s, extra flags %s.\r\nWeight is %d, value is %d, lvl is %d.\r\n", obj->name.c_str(), obj->item_type_name().c_str(), extra_bit_name (obj->extra_flags).c_str(), obj->weight, obj->cost, obj->level); send_to_char (buf); switch (obj->item_type) { case ITEM_SCROLL: case ITEM_POTION: snprintf (buf, sizeof buf, "Level %d spells of:", obj->value[0]); send_to_char (buf); if (obj->value[1] >= 0 && obj->value[1] < MAX_SKILL) { send_to_char (" '"); send_to_char (skill_table[obj->value[1]].name); send_to_char ("'"); } if (obj->value[2] >= 0 && obj->value[2] < MAX_SKILL) { send_to_char (" '"); send_to_char (skill_table[obj->value[2]].name); send_to_char ("'"); } if (obj->value[3] >= 0 && obj->value[3] < MAX_SKILL) { send_to_char (" '"); send_to_char (skill_table[obj->value[3]].name); send_to_char ("'"); } send_to_char (".\r\n"); break; case ITEM_WAND: case ITEM_STAFF: snprintf (buf, sizeof buf, "Has %d(%d) charges of level %d", obj->value[1], obj->value[2], obj->value[0]); send_to_char (buf); if (obj->value[3] >= 0 && obj->value[3] < MAX_SKILL) { send_to_char (" '"); send_to_char (skill_table[obj->value[3]].name); send_to_char ("'"); } send_to_char (".\r\n"); break; case ITEM_WEAPON: snprintf (buf, sizeof buf, "Damage is %d to %d (average %d).\r\n", obj->value[1], obj->value[2], (obj->value[1] + obj->value[2]) / 2); send_to_char (buf); break; case ITEM_ARMOR: snprintf (buf, sizeof buf, "Armor class is %d.\r\n", obj->value[0]); send_to_char (buf); break; } AffIter af; for (af = obj->pIndexData->affected.begin(); af != obj->pIndexData->affected.end(); af++) { if ((*af)->location != APPLY_NONE && (*af)->modifier != 0) { snprintf (buf, sizeof buf, "Affects %s by %d.\r\n", affect_loc_name ((*af)->location).c_str(), (*af)->modifier); send_to_char (buf); } } for (af = obj->affected.begin(); af != obj->affected.end(); af++) { if ((*af)->location != APPLY_NONE && (*af)->modifier != 0) { snprintf (buf, sizeof buf, "Affects %s by %d.\r\n", affect_loc_name ((*af)->location).c_str(), (*af)->modifier); send_to_char (buf); } } return; } void Character::spell_infravision (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_INFRARED)) return; act ("$n's eyes glow red.\r\n", NULL, NULL, TO_ROOM); af.type = sn; af.duration = 2 * lvl; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = AFF_INFRARED; victim->affect_to_char(&af); victim->send_to_char ("Your eyes glow red.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_invis (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_INVISIBLE)) return; victim->act ("$n fades out of existence.", NULL, NULL, TO_ROOM); af.type = sn; af.duration = 24; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = AFF_INVISIBLE; victim->affect_to_char(&af); victim->send_to_char ("You fade out of existence.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_know_alignment (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; const char *msg; int ap = victim->alignment; if (ap > 700) msg = "$N has an aura as white as the driven snow."; else if (ap > 350) msg = "$N is of excellent moral character."; else if (ap > 100) msg = "$N is often kind and thoughtful."; else if (ap > -100) msg = "$N doesn't have a firm moral commitment."; else if (ap > -350) msg = "$N lies to $S friends."; else if (ap > -700) msg = "$N's slash DISEMBOWELS you!"; else msg = "I'd rather just not say anything at all about $N."; act (msg, NULL, victim, TO_CHAR); return; } void Character::spell_lightning_bolt (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; static const sh_int dam_each[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 28, 31, 34, 37, 40, 40, 41, 42, 42, 43, 44, 44, 45, 46, 46, 47, 48, 48, 49, 50, 50, 51, 52, 52, 53, 54, 54, 55, 56, 56, 57, 58, 58, 59, 60, 60, 61, 62, 62, 63, 64 }; lvl = std::min (lvl, (int) (sizeof (dam_each) / sizeof (dam_each[0]) - 1)); lvl = std::max (0, lvl); int dam = number_range (dam_each[lvl] / 2, dam_each[lvl] * 2); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_locate_object (int sn, int lvl, void *vo) { std::string buf; bool found = false; ObjIter o; for (o = object_list.begin(); o != object_list.end(); o++) { Object *in_obj; if (!can_see_obj(*o) || !is_name (target_name, (*o)->name)) continue; found = true; for (in_obj = *o; in_obj->in_obj != NULL; in_obj = in_obj->in_obj) ; if (in_obj->carried_by != NULL) { buf = (*o)->short_descr + " carried by " + in_obj->carried_by->describe_to(this) + "\r\n"; } else { buf = (*o)->short_descr + " in " + (in_obj->in_room == NULL ? "somewhere" : in_obj->in_room->name.c_str()) + ".\r\n"; } buf[0] = toupper (buf[0]); send_to_char (buf); } if (!found) send_to_char ("Nothing like that in hell, earth, or heaven.\r\n"); return; } void Character::spell_magic_missile (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; static const sh_int dam_each[] = { 0, 3, 3, 4, 4, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14 }; lvl = std::min (lvl, (int) (sizeof (dam_each) / sizeof (dam_each[0]) - 1)); lvl = std::max (0, lvl); int dam = number_range (dam_each[lvl] / 2, dam_each[lvl] * 2); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_mass_invis (int sn, int lvl, void *vo) { Affect af; CharIter gch; for (gch = in_room->people.begin(); gch != in_room->people.end(); gch++) { if (!is_same_group (*gch, this) || (*gch)->is_affected (AFF_INVISIBLE)) continue; (*gch)->act ("$n slowly fades out of existence.", NULL, NULL, TO_ROOM); (*gch)->send_to_char ("You slowly fade out of existence.\r\n"); af.type = sn; af.duration = 24; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = AFF_INVISIBLE; (*gch)->affect_to_char(&af); } send_to_char ("Ok.\r\n"); return; } void Character::spell_null (int sn, int lvl, void *vo) { send_to_char ("That's not a spell!\r\n"); return; } void Character::spell_pass_door (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_PASS_DOOR)) return; af.type = sn; af.duration = number_fuzzy (lvl / 4); af.location = APPLY_NONE; af.modifier = 0; af.bitvector = AFF_PASS_DOOR; victim->affect_to_char(&af); victim->act ("$n turns translucent.", NULL, NULL, TO_ROOM); victim->send_to_char ("You turn translucent.\r\n"); return; } void Character::spell_poison (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->saves_spell (lvl)) return; af.type = sn; af.duration = lvl; af.location = APPLY_STR; af.modifier = -2; af.bitvector = AFF_POISON; victim->affect_join (&af); victim->send_to_char ("You feel very sick.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_protection (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_PROTECT)) return; af.type = sn; af.duration = 24; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = AFF_PROTECT; victim->affect_to_char(&af); victim->send_to_char ("You feel protected.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_refresh (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; victim->move = std::min (victim->move + lvl, victim->max_move); victim->send_to_char ("You feel less tired.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } void Character::spell_remove_curse (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; if (victim->has_affect(skill_lookup("curse"))) { victim->affect_strip (skill_lookup("curse")); victim->send_to_char ("You feel better.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); } return; } void Character::spell_sanctuary (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_SANCTUARY)) return; af.type = sn; af.duration = number_fuzzy (lvl / 8); af.location = APPLY_NONE; af.modifier = 0; af.bitvector = AFF_SANCTUARY; victim->affect_to_char(&af); victim->act ("$n is surrounded by a white aura.", NULL, NULL, TO_ROOM); victim->send_to_char ("You are surrounded by a white aura.\r\n"); return; } void Character::spell_shield (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->has_affect(sn)) return; af.type = sn; af.duration = 8 + lvl; af.location = APPLY_AC; af.modifier = -20; af.bitvector = 0; victim->affect_to_char(&af); victim->act ("$n is surrounded by a force shield.", NULL, NULL, TO_ROOM); victim->send_to_char ("You are surrounded by a force shield.\r\n"); return; } void Character::spell_shocking_grasp (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; static const int dam_each[] = { 0, 0, 0, 0, 0, 0, 0, 20, 25, 29, 33, 36, 39, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57 }; lvl = std::min (lvl, (int) (sizeof (dam_each) / sizeof (dam_each[0]) - 1)); lvl = std::max (0, lvl); int dam = number_range (dam_each[lvl] / 2, dam_each[lvl] * 2); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_sleep (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->is_affected (AFF_SLEEP) || lvl < victim->level || victim->saves_spell (lvl)) return; af.type = sn; af.duration = 4 + lvl; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = AFF_SLEEP; victim->affect_join (&af); if (victim->is_awake ()) { victim->send_to_char ("You feel very sleepy ..... zzzzzz.\r\n"); victim->act ("$n goes to sleep.", NULL, NULL, TO_ROOM); victim->position = POS_SLEEPING; } return; } void Character::spell_stone_skin (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (has_affect(sn)) return; af.type = sn; af.duration = lvl; af.location = APPLY_AC; af.modifier = -40; af.bitvector = 0; victim->affect_to_char(&af); victim->act ("$n's skin turns to stone.", NULL, NULL, TO_ROOM); victim->send_to_char ("Your skin turns to stone.\r\n"); return; } void Character::spell_summon (int sn, int lvl, void *vo) { Character *victim; if ((victim = get_char_world (target_name)) == NULL || victim == this || victim->in_room == NULL || IS_SET (victim->in_room->room_flags, ROOM_SAFE) || IS_SET (victim->in_room->room_flags, ROOM_PRIVATE) || IS_SET (victim->in_room->room_flags, ROOM_SOLITARY) || IS_SET (victim->in_room->room_flags, ROOM_NO_RECALL) || victim->level >= lvl + 3 || victim->fighting != NULL || victim->in_room->area != in_room->area || (victim->is_npc () && victim->saves_spell (lvl))) { send_to_char ("You failed.\r\n"); return; } victim->act ("$n disappears suddenly.", NULL, NULL, TO_ROOM); victim->char_from_room(); victim->char_to_room(in_room); victim->act ("$n arrives suddenly.", NULL, NULL, TO_ROOM); act ("$N has summoned you!", NULL, victim, TO_VICT); victim->do_look ("auto"); return; } void Character::spell_teleport (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; if (victim->in_room == NULL || IS_SET (victim->in_room->room_flags, ROOM_NO_RECALL) || (!is_npc () && victim->fighting != NULL) || (victim != this && (victim->saves_spell (lvl) || victim->saves_spell (lvl)))) { send_to_char ("You failed.\r\n"); return; } Room *pRoomIndex; for (;;) { pRoomIndex = get_room_index (number_range (0, 65535)); if (pRoomIndex != NULL) if (!IS_SET (pRoomIndex->room_flags, ROOM_PRIVATE) && !IS_SET (pRoomIndex->room_flags, ROOM_SOLITARY)) break; } victim->act ("$n slowly fades out of existence.", NULL, NULL, TO_ROOM); victim->char_from_room(); victim->char_to_room(pRoomIndex); victim->act ("$n slowly fades into existence.", NULL, NULL, TO_ROOM); victim->do_look ("auto"); return; } void Character::spell_ventriloquate (int sn, int lvl, void *vo) { std::string speaker; target_name = one_argument (target_name, speaker); char buf1[MAX_STRING_LENGTH]; char buf2[MAX_STRING_LENGTH]; snprintf (buf1, sizeof buf1, "%s says '%s'.\r\n", speaker.c_str(), target_name.c_str()); snprintf (buf2, sizeof buf2, "Someone makes %s say '%s'.\r\n", speaker.c_str(), target_name.c_str()); buf1[0] = toupper (buf1[0]); CharIter vch; for (vch = in_room->people.begin(); vch != in_room->people.end(); vch++) { if (!is_name (speaker, (*vch)->name)) (*vch)->send_to_char ((*vch)->saves_spell (lvl) ? buf2 : buf1); } return; } void Character::spell_weaken (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; Affect af; if (victim->has_affect(sn) || victim->saves_spell (lvl)) return; af.type = sn; af.duration = lvl / 2; af.location = APPLY_STR; af.modifier = -2; af.bitvector = 0; victim->affect_to_char(&af); victim->send_to_char ("You feel weaker.\r\n"); if (this != victim) send_to_char ("Ok.\r\n"); return; } /* * This is for muds that _want_ scrolls of recall. * Ick. */ void Character::spell_word_of_recall (int sn, int lvl, void *vo) { ((Character *) vo)->do_recall (""); return; } /* * NPC spells. */ void Character::spell_acid_breath (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; if (number_percent () < 2 * lvl && !victim->saves_spell (lvl)) { Object *obj_lose; ObjIter o, onext; for (o = victim->carrying.begin(); o != victim->carrying.end(); o = onext) { obj_lose = *o; onext = ++o; int iWear; if (number_percent() <= 75) continue; switch (obj_lose->item_type) { case ITEM_ARMOR: if (obj_lose->value[0] > 0) { victim->act ("$p is pitted and etched!", obj_lose, NULL, TO_CHAR); if ((iWear = obj_lose->wear_loc) != WEAR_NONE) victim->armor -= obj_lose->apply_ac (iWear); obj_lose->value[0] -= 1; obj_lose->cost = 0; if (iWear != WEAR_NONE) victim->armor += obj_lose->apply_ac (iWear); } break; case ITEM_CONTAINER: victim->act ("$p fumes and dissolves!", obj_lose, NULL, TO_CHAR); obj_lose->extract_obj (); break; } } } int hpch = std::max (10, hit); int dam = number_range (hpch / 16 + 1, hpch / 8); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_fire_breath (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; if (number_percent () < 2 * lvl && !victim->saves_spell (lvl)) { Object *obj_lose; ObjIter o, onext; for (o = victim->carrying.begin(); o != victim->carrying.end(); o = onext) { obj_lose = *o; onext = ++o; const char *msg; if (number_percent() <= 75) continue; switch (obj_lose->item_type) { default: continue; case ITEM_CONTAINER: msg = "$p ignites and burns!"; break; case ITEM_POTION: msg = "$p bubbles and boils!"; break; case ITEM_SCROLL: msg = "$p crackles and burns!"; break; case ITEM_STAFF: msg = "$p smokes and chars!"; break; case ITEM_WAND: msg = "$p sparks and sputters!"; break; case ITEM_FOOD: msg = "$p blackens and crisps!"; break; case ITEM_PILL: msg = "$p melts and drips!"; break; } victim->act (msg, obj_lose, NULL, TO_CHAR); obj_lose->extract_obj (); } } int hpch = std::max (10, hit); int dam = number_range (hpch / 16 + 1, hpch / 8); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_frost_breath (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; if (number_percent () < 2 * lvl && !victim->saves_spell (lvl)) { Object *obj_lose; ObjIter o, onext; for (o = victim->carrying.begin(); o != victim->carrying.end(); o = onext) { obj_lose = *o; onext = ++o; const char *msg; if (number_percent() <= 75) continue; switch (obj_lose->item_type) { default: continue; case ITEM_CONTAINER: case ITEM_DRINK_CON: case ITEM_POTION: msg = "$p freezes and shatters!"; break; } victim->act (msg, obj_lose, NULL, TO_CHAR); obj_lose->extract_obj (); } } int hpch = std::max (10, hit); int dam = number_range (hpch / 16 + 1, hpch / 8); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; } void Character::spell_gas_breath (int sn, int lvl, void *vo) { Character *vch; CharIter rch, next; for (rch = in_room->people.begin(); rch != in_room->people.end(); rch = next) { vch = *rch; next = ++rch; if (is_npc () ? !vch->is_npc () : vch->is_npc ()) { int hpch = std::max (10, hit); int dam = number_range (hpch / 16 + 1, hpch / 8); if (vch->saves_spell (lvl)) dam /= 2; damage (this, vch, dam, sn); } } return; } void Character::spell_lightning_breath (int sn, int lvl, void *vo) { Character *victim = (Character *) vo; int hpch = std::max (10, hit); int dam = number_range (hpch / 16 + 1, hpch / 8); if (victim->saves_spell (lvl)) dam /= 2; damage (this, victim, dam, sn); return; }