Mercurial > hg > early-roguelike
diff urogue/scrolls.c @ 256:c495a4f288c6
Import UltraRogue from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 31 Jan 2017 19:56:04 -0500 |
parents | |
children | e52a8a7ad4c5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/urogue/scrolls.c Tue Jan 31 19:56:04 2017 -0500 @@ -0,0 +1,1491 @@ +/* + scrolls.c - Functions for dealing with scrolls + + UltraRogue: The Ultimate Adventure in the Dungeons of Doom + Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "rogue.h" + +/* + read_scroll - read a scroll (or effect a scroll-like spell) + reader: who does it + which: which S_SCROLL (-1 means ask from pack) + flags: ISBLESSED, ISCURSED +*/ + +void +read_scroll(struct thing *reader, int which, int flags) +{ + struct object *obj; + struct linked_list *item, *nitem; + int i, j, charm_power; + char ch, nch; + int blessed = flags & ISBLESSED; + int cursed = flags & ISCURSED; + int is_scroll = (which < 0 ? TRUE : FALSE); + char buf[2 * LINELEN]; + + if (reader != &player) + { + monread(reader, which, flags); + return; + } + + if (is_scroll) /* A regular scroll */ + { + if ((item = get_item("read", SCROLL)) == NULL) + return; + + obj = OBJPTR(item); + + if (obj->o_type != SCROLL) + { + msg("It says 'Made in Yugoslavia'!"); + return; + } + + if (on(player, ISBLIND)) + { + msg("You can't see to read anything."); + return; + } + + /* Calculate its effect */ + + cursed = obj->o_flags & ISCURSED; + blessed = obj->o_flags & ISBLESSED; + flags = obj->o_flags; + which = obj->o_which; + + /* remove it from the pack */ + + rem_pack(obj); + discard(item); + updpack(); + } + + switch (which) + { + case S_CONFUSE: /* Touch causes monster confusion. */ + if (cursed) + quaff(reader, P_CLEAR, ISCURSED); + else + { + msg("Your hands begin to glow red."); + turn_on(player, CANHUH); + /* if blessed... */ + } + break; + + case S_CURING: /* A cure disease spell */ + if (on(player, HASINFEST) || on(player, HASDISEASE)) + { + if (!cursed && on(player, HASDISEASE)) + { + extinguish_fuse(FUSE_CURE_DISEASE); + cure_disease(NULL); + } + + if (on(player, HASINFEST)) + { + msg("You begin to feel yourself improving again."); + turn_off(player, HASINFEST); + infest_dam = 0; + } + + if (is_scroll) + know_items[TYP_SCROLL][S_CURING] = TRUE; + } + else + nothing_message(flags); + break; + + case S_LIGHT: + if (blue_light(flags) && is_scroll) + know_items[TYP_SCROLL][S_LIGHT] = TRUE; + break; + + case S_HOLD: + if (cursed) + { + /* + * This scroll aggravates all the monsters on the + * current level and sets them running towards the + * hero + */ + aggravate(); + hearmsg("You hear a high pitched humming noise."); + } + else if (blessed) /* Hold all monsters on level */ + { + if (mlist == NULL) + nothing_message(flags); + else + { + struct linked_list *mon; + struct thing *th; + + for (mon = mlist; mon != NULL; mon = next(mon)) + { + th = THINGPTR(mon); + turn_off(*th, ISRUN); + turn_on(*th, ISHELD); + } + msg("A sudden peace comes over the dungeon."); + } + } + else + { + /* + * Hold monster scroll. Stop all monsters within two + * spaces from chasing after the hero. + */ + int x, y; + struct linked_list *mon; + int gotone = FALSE; + + for (x = hero.x - 2; x <= hero.x + 2; x++) + { + for (y = hero.y - 2; y <= hero.y + 2; y++) + { + if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x))) + { + if ((mon = find_mons(y, x)) != NULL) + { + struct thing *th; + + gotone = TRUE; + th = THINGPTR(mon); + turn_off(*th, ISRUN); + turn_on(*th, ISHELD); + } + } + } + } + + if (gotone) + msg("A sudden peace surrounds you."); + else + nothing_message(flags); + } + break; + + case S_SLEEP: + + /* if cursed, you fall asleep */ + + if (cursed) + { + if (is_wearing(R_ALERT)) + msg("You feel drowsy for a moment."); + else + { + msg("You fall asleep."); + no_command += 4 + rnd(SLEEPTIME); + } + } + else + { + /* + * sleep monster scroll. puts all monsters within 2 + * spaces asleep + */ + int x, y; + struct linked_list *mon; + int gotone = FALSE; + + for (x = hero.x - 2; x <= hero.x + 2; x++) + { + for (y = hero.y - 2; y <= hero.y + 2; y++) + { + if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x))) + { + if ((mon = find_mons(y, x)) != NULL) + { + struct thing *th; + th = THINGPTR(mon); + + if (on(*th, ISUNDEAD)) + continue; + + gotone = TRUE; + th->t_no_move += SLEEPTIME; + } + } + } + } + + if (gotone) + msg("The monster(s) around you seem to have fallen asleep."); + else + nothing_message(flags); + } + break; + + case S_CREATE: + { + /* + * Create a monster. First look in a circle around + * him, next try his room otherwise give up + */ + + struct thing *tp; + struct linked_list *ip; + + if (blessed) + summon_monster((short) 0, NOFAMILIAR, MESSAGE); + else if (cursed) + { + i = rnd(4) + 3; + for (j = 0; j < i; j++) + { + if ((ip = creat_mons(&player, (short) 0, MESSAGE)) != NULL) + { + tp = THINGPTR(ip); + turn_off(*tp, ISFRIENDLY); + } + } + } + else if ((ip = creat_mons(&player, (short) 0, MESSAGE)) != NULL) + { + tp = THINGPTR(ip); + turn_off(*tp, ISFRIENDLY); + } + } + break; + + case S_IDENTIFY: + if (cursed) + msg("You identify this scroll as an identify scroll"); + else if (blessed) /* identify everything in the pack */ + { + msg("You feel more Knowledgeable!"); + idenpack(); + } + else + { + /* Identify, let the rogue figure something out */ + + if (is_scroll && know_items[TYP_SCROLL][S_IDENTIFY] != TRUE) + { + msg("This scroll is an identify scroll."); + know_items[TYP_SCROLL][S_IDENTIFY] = TRUE; + } + whatis(NULL); + } + break; + + case S_MAP: + + /* Scroll of magic mapping. */ + + if (cursed) + { + msg("Your mind goes blank for a moment."); + wclear(cw); + light(&hero); + status(TRUE); + break; + } + + if (is_scroll && know_items[TYP_SCROLL][S_MAP] != TRUE) + { + msg("Oh! This scroll has a map on it!!"); + know_items[TYP_SCROLL][S_MAP] = TRUE; + } + + if (blessed) + turn_on(player, BLESSMAP); + + overwrite(stdscr, hw); + + /* Take all the things we want to keep hidden out of the window */ + + for (i = 0; i < LINES; i++) + for (j = 0; j < COLS; j++) + { + switch (nch = ch = CCHAR(mvwinch(hw, i, j))) + { + case SECRETDOOR: + nch = DOOR; + mvaddch(i, j, nch); + break; + + case '-': + case '|': + case DOOR: + case PASSAGE: + case ' ': + case STAIRS: + if (mvwinch(mw, i, j) != ' ') + { + struct thing *it; + struct linked_list *lit; + + lit = find_mons(i, j); + + if (lit) { + it = THINGPTR(lit); + + if (it && it->t_oldch == ' ') + it->t_oldch = nch; + } + } + break; + + default: + if (!blessed || !isatrap(ch)) + nch = ' '; + else + { + struct trap *tp; + struct room *rp; + + tp = trap_at(i, j); + rp = roomin(hero); + + if (tp->tr_type == FIRETRAP && rp != NULL) + { + rp->r_flags &= ~ISDARK; + light(&hero); + } + + tp->tr_flags |= ISFOUND; + } + } + if (nch != ch) + waddch(hw, nch); + } + + /* Copy in what he has discovered */ + overlay(cw, hw); + + /* And set up for display */ + overwrite(hw, cw); + + break; + + case S_GFIND: + /* Scroll of gold detection */ + + if (cursed) + { + int n = roll(3, 6); + int k; + struct room *rp; + coord pos; + + msg("You begin to feel greedy and you sense gold."); + wclear(hw); + + for (k = 1; k < n; k++) + { + rp = &rooms[rnd_room()]; + rnd_pos(rp, &pos); + mvwaddch(hw, pos.y, pos.x, GOLD); + } + overlay(hw, cw); + + break; + } + + if (blessed) + turn_on(player, BLESSGOLD); + + if (gsense() && is_scroll) + know_items[TYP_SCROLL][S_GFIND] = TRUE; + + break; + + case S_SELFTELEP: + + /* Scroll of teleportation: Make him disappear and reappear */ + + if (cursed) + { + level += 5 + rnd(5); + new_level(NORMLEV,0); + mpos = 0; + msg("You are banished to the lower regions."); + } + else if (blessed) + { + level -= rnd(3) + 1; + + if (level < 1) + level = 1; + + mpos = 0; + new_level(NORMLEV,0); /* change levels */ + status(TRUE); + msg("You are whisked away to another region."); + } + else + { + teleport(); + + if (is_scroll) + know_items[TYP_SCROLL][S_SELFTELEP] = TRUE; + } + + if (off(player, ISCLEAR)) + { + if (on(player, ISHUH)) + lengthen_fuse(FUSE_UNCONFUSE, rnd(4) + 4); + else + { + light_fuse(FUSE_UNCONFUSE, 0, rnd(4) + 4, AFTER); + turn_on(player, ISHUH); + } + } + else + msg("You feel dizzy for a moment, but it quickly passes."); + + break; + + case S_SCARE: + + /* + * A blessed scroll of scare monster automatically transports + * itself to the hero's feet + * + */ + + if (blessed) + { + ch = CCHAR( mvwinch(stdscr, hero.y, hero.x) ); + + if (ch != FLOOR && ch != PASSAGE) + { + msg("Your feet tickle for a moment"); + return; + } + + item = spec_item(SCROLL, S_SCARE, 0, 0); + + obj = OBJPTR(item); + obj->o_flags = ISCURSED; + obj->o_pos = hero; + add_obj(item, hero.y, hero.x); + msg("A wave of terror sweeps throughout the room"); + } + else + { + /* + * A monster will refuse to step on a scare monster + * scroll if it is dropped. Thus reading it is a + * mistake and produces laughter at the poor rogue's + * boo boo. + */ + + msg("You hear maniacal laughter in the distance."); + + if (cursed) /* If cursed, monsters get mad */ + aggravate(); + } + break; + + case S_REMOVECURSE: + if (cursed) /* curse a player's possession */ + { + for (nitem = pack; nitem != NULL; nitem = next(nitem)) + { + obj = OBJPTR(nitem); + + if (rnd(5) == 0) + if (obj->o_flags & ISBLESSED) + obj->o_flags &= ~ISBLESSED; + else + obj->o_flags |= ISCURSED; + } + msg("The smell of fire and brimstone comes from your pack."); + } + else if (blessed) + { + for (nitem = pack; nitem != NULL; nitem = next(nitem)) + (OBJPTR(nitem))->o_flags &= ~ISCURSED; + + msg("Your pack glistens brightly."); + } + else + { + if ((nitem = get_item("remove the curse on", 0)) != NULL) + { + obj = OBJPTR(nitem); + msg("Removed the curse from %s.", inv_name(obj, LOWERCASE)); + obj->o_flags &= ~ISCURSED; + + if (is_scroll) + know_items[TYP_SCROLL][S_REMOVECURSE] = TRUE; + } + } + break; + + case S_PETRIFY: + switch(CCHAR(mvinch(hero.y, hero.x))) + { + case TRAPDOOR: + case DARTTRAP: + case TELTRAP: + case ARROWTRAP: + case SLEEPTRAP: + case BEARTRAP: + case FIRETRAP: + { + int n; + + /* Find the right trap */ + for (n = 0; n < ntraps && !ce(traps[n].tr_pos, hero); n++) + ; + + ntraps--; + + if (!ce(traps[n].tr_pos, hero)) + msg("What a strange trap!"); + else + { + while (n < ntraps) + { + traps[n] = traps[n + 1]; + n++; + } + } + + msg("The dungeon begins to rumble and shake!"); + addch(WALL); + + if (on(player, CANINWALL)) + { + extinguish_fuse(FUSE_UNPHASE); + turn_off(player, CANINWALL); + msg("Your dizzy feeling leaves you."); + } + + turn_on(player, ISINWALL); + } + break; + + case DOOR: + case SECRETDOOR: + { + struct room *rp = roomin(hero); + short n; + + /* Find the right door */ + + for (n=0; n<rp->r_nexits && !ce(rp->r_exit[n], hero); n++) + /* do nothing */ ; + + rp->r_nexits--; + + if (!ce(rp->r_exit[n], hero)) + msg("What a strange door!"); + else + { + while (n < rp->r_nexits) + { + rp->r_exit[n] = rp->r_exit[n + 1]; + n++; + } + } + /* No break - fall through */ + } + case FLOOR: + case PASSAGE: + msg("The dungeon begins to rumble and shake!"); + addch(WALL); + + if (on(player, CANINWALL)) + { + extinguish_fuse(FUSE_UNPHASE); + turn_off(player, CANINWALL); + msg("Your dizzy feeling leaves you."); + } + + turn_on(player, ISINWALL); + break; + + default: + nothing_message(flags); + break; + } + break; + + case S_GENOCIDE: + msg("You have been granted the boon of genocide!--More--"); + + wait_for(' '); + msg(""); + + genocide(flags); + + if (is_scroll) + know_items[TYP_SCROLL][S_GENOCIDE] = TRUE; + + break; + + case S_PROTECT: + if (is_scroll && know_items[TYP_SCROLL][S_PROTECT] == FALSE) + { + msg("You can protect something from rusting or theft."); + know_items[TYP_SCROLL][S_PROTECT] = TRUE; + } + + if ((item = get_item("protect", 0)) != NULL) + { + struct object *lb = OBJPTR(item); + + if (cursed) + { + lb->o_flags &= ~ISPROT; + mpos = 0; + msg("Unprotected %s.", inv_name(lb, LOWERCASE)); + } + else + { + lb->o_flags |= ISPROT; + mpos = 0; + msg("Protected %s.", inv_name(lb, LOWERCASE)); + } + } + break; + + case S_MAKEITEMEM: + if (!is_scroll || rnd(luck)) + feel_message(); + else + { + char itemtype; + + if (is_scroll) + know_items[TYP_SCROLL][S_MAKEITEMEM] = TRUE; + + msg("You have been endowed with the power of creation."); + + if (blessed) + itemtype = '\0'; + else + switch (rnd(6)) + { + case 0: itemtype = RING; break; + case 1: itemtype = POTION; break; + case 2: itemtype = SCROLL; break; + case 3: itemtype = ARMOR; break; + case 4: itemtype = WEAPON; break; + case 5: itemtype = STICK; break; + } + + flags |= SCR_MAGIC; + buy_it(itemtype, flags); + } + break; + + case S_ENCHANT: + { + struct linked_list *ll; + struct object *lb; + int howmuch, flg=0; + + if (is_scroll && know_items[TYP_SCROLL][S_ENCHANT] == FALSE) + { + msg("You are granted the power of enchantment."); + msg("You may enchant anything(weapon,ring,armor,scroll,potion)"); + know_items[TYP_SCROLL][S_ENCHANT] = TRUE; + } + + if ((ll = get_item("enchant", 0)) != NULL) + { + lb = OBJPTR(ll); + lb->o_flags &= ~ISCURSED; + + if (blessed) + howmuch = 2; + else if (cursed) + howmuch = -1; + else + { + howmuch = 1; + flg |= ISBLESSED; + } + + switch (lb->o_type) + { + case RING: + lb->o_ac += howmuch; + + if (lb->o_ac > 5 && rnd(5) == 0) + { + msg("Your ring explodes in a cloud of smoke."); + lb->o_flags &= ~ISCURSED; + dropcheck(lb); + + switch (lb->o_which) + { + case R_ADDSTR: + chg_str(-2, TRUE, FALSE); + break; + case R_ADDHIT: + chg_dext(-2, TRUE, FALSE); + break; + case R_ADDINTEL: + pstats.s_intel -= 2; + max_stats.s_intel -= 2; + break; + case R_ADDWISDOM: + pstats.s_wisdom -= 2; + max_stats.s_wisdom -= 2; + break; + } + + del_pack(ll); + lb = NULL; + } + else if (is_r_on(lb)) + switch (lb->o_which) + { + case R_ADDSTR: + pstats.s_str += howmuch; + break; + case R_ADDHIT: + pstats.s_dext += howmuch; + break; + case R_ADDINTEL: + pstats.s_intel += howmuch; + break; + case R_ADDWISDOM: + pstats.s_wisdom += howmuch; + break; + case R_CARRYING: + updpack(); + break; + } + + break; + + case ARMOR: + lb->o_ac -= howmuch; + + if (armors[lb->o_which].a_class - lb->o_ac > 5 && rnd(5) == 0) + { + msg("Your %s explodes in a cloud of dust.", + inv_name(lb, LOWERCASE)); + + lb->o_flags &= ~ISCURSED; + + if (lb == cur_armor) + pstats.s_hpt /= 2; + + dropcheck(lb); + del_pack(ll); + lb = NULL; + } + break; + + case STICK: + if (wizard || howmuch != 1 && rnd(5) == 0) + lb->o_flags |= flg; + + lb->o_charges += howmuch + 10; + + if (lb->o_charges < 0) + lb->o_charges = 0; + + if (lb->o_charges > 50 && rnd(5) == 0) + { + msg("Your %s explodes into splinters.", + inv_name(lb, LOWERCASE)); + + lb->o_flags &= ~ISCURSED; + dropcheck(lb); + del_pack(ll); + lb = NULL; + } + break; + + case WEAPON: + if (rnd(100) < 50) + lb->o_hplus += howmuch; + else + lb->o_dplus += howmuch; + + if (lb->o_hplus + lb->o_dplus > 10 && rnd(5) == 0) + { + msg("Your %s explodes in a cloud of shrapnel", + inv_name(lb, LOWERCASE)); + + lb->o_flags &= ~ISCURSED; + + if (lb == cur_weapon) + chg_dext(-2, FALSE, TRUE); + + dropcheck(lb); + del_pack(ll); + lb = NULL; + + } + break; + + case POTION: + case SCROLL: + default: + lb->o_flags |= flg; + break; + } + + mpos = 0; + + if (lb != NULL) + msg("Enchanted %s.", inv_name(lb, LOWERCASE)); + } + } + break; + + case S_NOTHING: + nothing_message(flags); + break; + + case S_SILVER: + { + struct object *lb; + + if (is_scroll && know_items[TYP_SCROLL][S_SILVER] == FALSE) + { + msg("You are granted the power of magic hitting."); + know_items[TYP_SCROLL][S_SILVER] = TRUE; + } + + if ((item = get_item("annoint", WEAPON)) != NULL) + { + lb = OBJPTR(item); + + if (blessed && !(lb->o_flags & ISSILVER)) + { + lb->o_hplus += rnd(3) + 1; + lb->o_flags |= ISSILVER; + lb->o_flags |= ISMETAL; + msg("Your weapon has turned to silver!"); + } + else if (cursed && (lb->o_flags & ISSILVER)) + { + lb->o_hplus -= (rnd(3) + 1); + lb->o_flags &= ~ISSILVER; + msg("Your silver weapon has turned to steel."); + } + else if (lb->o_flags & ISSILVER) + { + msg("Your silver weapon glitters briefly."); + lb->o_hplus += rnd(2); + } + else + { + lb->o_hplus += rnd(3); + lb->o_flags |= ISSILVER; + lb->o_flags |= ISMETAL; + msg("Your weapon has turned to silver."); + } + } + } + break; + case S_OWNERSHIP: + { + struct linked_list *ll; + struct object *lb; + + if (is_scroll && know_items[TYP_SCROLL][S_OWNERSHIP] == FALSE) + { + msg("You are granted the power of ownership."); + know_items[TYP_SCROLL][S_OWNERSHIP] = TRUE; + } + + if ((ll = get_item("claim", 0)) != NULL) + { + lb = OBJPTR(ll); + + if (cursed && lb->o_flags & (ISOWNED | CANRETURN)) + { + lb->o_flags &= ~(ISOWNED | CANRETURN); + msg("The gods seem to have forgotten you."); + } + else if (cursed && !(lb->o_flags & ISLOST)) + { + lb->o_flags |= ISLOST; + msg("The gods look the other way."); + } + else if (blessed && lb->o_flags & ISLOST) + { + lb->o_flags |= CANRETURN; + msg("The gods seem to have remembered you."); + } + else if (blessed && !(lb->o_flags & ISOWNED)) + { + lb->o_flags |= (ISOWNED | CANRETURN); + msg("The gods smile upon you."); + } + else if (blessed | cursed) + { + nothing_message(flags); + } + else + { + lb->o_flags |= CANRETURN; + msg("The gods look upon you."); + } + } + } + break; + + case S_FOODDET: + + /* Scroll of food detection */ + + if (cursed) + { + int n = roll(3, 6); + int k; + struct room *rp; + coord pos; + + msg("You begin to feel hungry and you smell food."); + wclear(hw); + + for (k = 1; k < n; k++) + { + rp = &rooms[rnd_room()]; + rnd_pos(rp, &pos); + mvwaddch(hw, pos.y, pos.x, FOOD); + } + + overlay(hw, cw); + + if (is_scroll) + know_items[TYP_SCROLL][S_FOODDET] = TRUE; + + break; + } + + if (blessed) + turn_on(player, BLESSFOOD); + + if (off(player, ISUNSMELL) && lvl_obj != NULL) + { + struct linked_list *itm; + struct object *cur; + struct thing *th; + int fcount = 0; + int same_room = FALSE; + struct room *rp = roomin(hero); + + wclear(hw); + + for (itm = lvl_obj; itm != NULL; itm = next(itm)) + { + cur = OBJPTR(itm); + + if (cur->o_type == FOOD) + { + fcount += cur->o_count; + mvwaddch(hw, cur->o_pos.y, cur->o_pos.x, FOOD); + + if (roomin(cur->o_pos) == rp) + same_room = TRUE; + } + } + + for (itm = mlist; itm != NULL; itm = next(itm)) + { + struct linked_list *pitem; + + th = THINGPTR(itm); + + for (pitem = th->t_pack; pitem != NULL; pitem = next(pitem)) + { + cur = OBJPTR(pitem); + + if (cur->o_type == FOOD) + { + fcount += cur->o_count; + mvwaddch(hw, th->t_pos.y, th->t_pos.x, FOOD); + + if (roomin(th->t_pos) == rp) + same_room = TRUE; + } + } + } + + if (fcount) + { + if (is_scroll) + know_items[TYP_SCROLL][S_FOODDET] = TRUE; + + if (same_room) + msg("FOOOOD!!"); + else + msg("You begin to feel hungry and you smell food."); + + overlay(hw, cw); + break; + } + } + + if (off(player, ISUNSMELL)) + msg("You can't smell anything."); + else + nothing_message(flags); + + break; + + case S_ELECTRIFY: + if (on(player, ISELECTRIC)) + { + msg("Your violet glow brightens for an instant."); + lengthen_fuse(FUSE_UNELECTRIFY, 4 + rnd(8)); + } + else + { + msg("Your body begins to glow violet and shoot sparks."); + turn_on(player, ISELECTRIC); + light_fuse(FUSE_UNELECTRIFY,0,(blessed?3:1)*WANDERTIME, AFTER); + light(&hero); + } + + if (is_scroll) + know_items[TYP_SCROLL][S_ELECTRIFY] = TRUE; + + break; + + case S_CHARM: + + /* + * Beauty, brains and experience make a person charming. + * Unique monsters can never be charmed. + */ + + charm_power = pstats.s_charisma / 2 + pstats.s_lvl / 3 + max(0, pstats.s_intel - 15); + + if (cursed) + { + msg("You hear harsh, dissonant twanging throughout the dungeon."); + aggravate(); + } + else if (blessed) /* Charm entire level */ + { + struct linked_list *mon; + + msg("You hear ringingly meliflous music all around you."); + + for (mon = mlist; mon != NULL; mon = next(mon)) + { + struct thing *th = THINGPTR(mon); + + if (th->t_stats.s_intel < charm_power && off(*th, ISUNIQUE)) + { + turn_on(*th, ISCHARMED); + chase_it(&th->t_pos, &player); + } + } + } + else /* Charm all monsters within two spaces of the hero */ + { + int x, y; + struct linked_list *mon; + + msg("You hear soft, lyrical music all around you."); + + for (x = hero.x - 2; x <= hero.x + 2; x++) + for (y = hero.y - 2; y <= hero.y + 2; y++) + if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x))) + { + if ((mon = find_mons(y, x)) != NULL) + { + struct thing *th; + + th = THINGPTR(mon); + + if (th->t_stats.s_intel < charm_power && off(*th, ISUNIQUE)) + { + turn_on(*th, ISCHARMED); + chase_it(&th->t_pos, &player); + } + } + } + } + break; + + case S_SUMMON: + { + struct linked_list *llp; + struct thing *tp; + int mon_type; + + if (on(player, HASSUMMONED)) + { + nothing_message(flags); + break; + } + + if (cursed) + { + creat_mons(&player, (short) 0, MESSAGE); + break; + } + + if (blessed) /* Summon a possibly very high monster */ + { + int nsides = max(2, max(pstats.s_lvl, 12) - luck); + + mon_type = roll(nsides, rnd(pstats.s_charisma + 15) + 8); + mon_type = min(mon_type, nummonst); + } + else + mon_type = 0; + + llp = summon_monster((short) mon_type, NOFAMILIAR, NOMESSAGE); + + if (llp) + { + tp = THINGPTR(llp); + turn_on(*tp, WASSUMMONED); + turn_on(player, HASSUMMONED); + msg("You have summoned a %s.", monsters[tp->t_index].m_name); + light_fuse(FUSE_UNSUMMON, llp, WANDERTIME + rnd(pstats.s_lvl), AFTER); + } + } + break; + + case S_REFLECT: + if (on(player, CANREFLECT)) + { + msg("The sparkling around you brightens momentarily."); + lengthen_fuse(FUSE_UNGAZE, 5 + rnd(10)); + } + else + { + msg("Shiny particles sparkle all around you."); + turn_on(player, CANREFLECT); + light_fuse(FUSE_UNGAZE, 0, (blessed ? 3 : 1) * WANDERTIME, AFTER); + } + break; + + case S_SUMFAMILIAR: + { + int type = 0; + + if (on(player, HASFAMILIAR)) + { + msg("But you already have a familiar - somewhere..."); + return; + } + + if (wizard) + type = get_monster_number("be your familiar"); + else if (blessed) /* Summon a possibly very high monster */ + { + int nsides = max(2, max(pstats.s_lvl, 12) - luck); + + type = roll(nsides, rnd(pstats.s_charisma + 15) + 8); + type = min(type, nummonst); + } + else if (cursed) /* Summon a bat, maggot, eye, etc */ + { + type = rnd(20) + 1; + + if (summon_monster(type, FAMILIAR, MESSAGE)) + turn_on(player, HASFAMILIAR); + } + } + break; + + case S_FEAR: + + /* if cursed, you get frightened */ + + if (cursed) + { + if (off(player, SUPERHERO) && (player.t_ctype != C_PALADIN) && !save(VS_DEATH)) + msg("A momentary wave of panic sweeps over you."); + else + { + msg("Panicstricken, you fall into a coma."); + no_command += roll(2, SLEEPTIME); + } + } + else + { + /* + * terrify monster scroll. frightens all monsters + * within 2 spaces + */ + int x, y; + struct linked_list *mon; + int gotone = FALSE; + + for (x = hero.x - 2; x <= hero.x + 2; x++) + { + for (y = hero.y - 2; y <= hero.y + 2; y++) + { + if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x))) + { + if ((mon = find_mons(y, x)) != NULL) + { + struct thing *th; + + th = THINGPTR(mon); + + if (on(*th, ISUNDEAD) || on(*th, ISUNIQUE)) + continue; + + gotone = TRUE; + turn_on(*th, ISFLEE); + th->t_chasee = &player; + th->t_ischasing = FALSE; + th->t_horde = NULL; + } + } + } + } + + if (gotone) + seemsg("The monster(s) around you recoil in horror."); + else + nothing_message(flags); + } + break; + + case S_MSHIELD: /* deal with blessed/cursed later */ + if (on(player, HASMSHIELD)) + { + seemsg("The fog around you thickens."); + lengthen_fuse(FUSE_UNMSHIELD, (blessed ? 3 : 1) * HEROTIME); + } + else + { + seemsg("A fog forms around you."); + turn_on(player, HASMSHIELD); + light_fuse(FUSE_UNMSHIELD, 0, (blessed ? 3 : 1) * HEROTIME, AFTER); + } + + if (is_scroll) + know_items[TYP_SCROLL][S_MSHIELD] = TRUE; + + break; + + default: + msg("What a puzzling scroll!"); + return; + } + + look(TRUE); /* put the result of the scroll on the screen */ + status(FALSE); + + if (is_scroll) + { + if (know_items[TYP_SCROLL][which] && guess_items[TYP_SCROLL][which]) + { + ur_free(guess_items[TYP_SCROLL][which]); + guess_items[TYP_SCROLL][which] = NULL; + } + else if (askme && !know_items[TYP_SCROLL][which] && guess_items[TYP_SCROLL][which] == NULL) + { + msg("What do you want to call it? "); + + if (get_string(buf, cw) == NORM) + { + guess_items[TYP_SCROLL][which] = new_alloc(strlen(buf) + 1); + strcpy(guess_items[TYP_SCROLL][which], buf); + } + } + } +} + +/* + creat_mons() + creates the specified monster -- any if 0 +*/ + +struct linked_list * +creat_mons(struct thing *person, int monster, int message) +{ + coord mp; + + /* Search for an open place */ + + debug("Creator @(%d, %d) ", person->t_pos.y, person->t_pos.x); + + if ((place_mons(person->t_pos.y, person->t_pos.x, &mp)) != FALSE) + { + struct linked_list *nitem; + + nitem = new_item(sizeof(struct thing)); + new_monster(nitem, monster == 0 ? randmonster(NOWANDER, NOGRAB) + : monster, &mp, MAXSTATS); + chase_it(&mp, &player); + + /* If the monster is on a trap, trap it */ + + if (isatrap(mvinch(mp.y, mp.x))) + { + debug("Monster trapped during creat_mons."); + be_trapped(THINGPTR(nitem), mp); + } + + light(&hero); + return(nitem); + } + + if (message) + hearmsg("You hear a faint cry of anguish in the distance."); + + return(NULL); +} + +/* + place_mons() + finds a place to put the monster +*/ + +int +place_mons(int y, int x, coord *pos) +{ + int distance, xx, yy, appears; + + for (distance = 1; distance <= 10; distance++) + { + appears = 0; + + for (yy = y - distance; yy <= y + distance; yy++) + for (xx = x - distance; xx <= x + distance; xx++) + { + /* Don't put a monster in top of the creator or player */ + + if (xx < 0 || yy < 0) + continue; + + if (yy == y && xx == x) + continue; + + if (yy == hero.y && xx == hero.x) + continue; + + /* Or anything else nasty */ + + if (step_ok(yy, xx, NOMONST, FALSE)) + { + if (rnd(max(1, (10 * distance - ++appears))) == 0) + { + pos->y = yy; + pos->x = xx; + debug("Make monster dist %d appear %d @(%d, %d) ", + distance, appears, pos->y, pos->x); + return(TRUE); + } + } + } + } + return(FALSE); +} + +/* + is_t_on() + This subroutine determines if an object that is a ring is being + worn by the hero by Bruce Dautrich 4/3/84 + */ + +int +is_r_on(struct object *obj) +{ + if (obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] || + obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4] || + obj == cur_ring[LEFT_5] || + obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] || + obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4] || + obj == cur_ring[RIGHT_5]) + { + return(TRUE); + } + + return(FALSE); +} + +/* + monread() + monster gets the effect +*/ + +void +monread(struct thing *reader, int which, int flags) +{ + struct stats *curp = &(reader->t_stats); + struct stats *maxp = &(reader->maxstats); + int blessed = flags & ISBLESSED; + int cursed = flags & ISCURSED; + + switch (which) + { + case S_SELFTELEP: + /* If monster was suffocating, stop it */ + if (on(*reader, DIDSUFFOCATE)) + { + turn_off(*reader, DIDSUFFOCATE); + extinguish_fuse(FUSE_SUFFOCATE); + } + + /* If monster held us, stop it */ + + if (on(*reader, DIDHOLD) && (hold_count == 0)) + turn_off(player, ISHELD); + + turn_off(*reader, DIDHOLD); + + if (cursed) + reader->t_no_move++; + else + { + int rm; + + if (blessed) /* Give him his hit points */ + curp->s_hpt = maxp->s_hpt; + + /* Erase the monster from the old position */ + + if (isalpha(mvwinch(cw, reader->t_pos.y, reader->t_pos.x))) + mvwaddch(cw, reader->t_pos.y, reader->t_pos.x, reader->t_oldch); + + mvwaddch(mw, reader->t_pos.y, reader->t_pos.x, ' '); + + /* Get a new position */ + + do + { + rm = rnd_room(); + rnd_pos(&rooms[rm], &reader->t_pos); + } + while (winat(reader->t_pos.y, reader->t_pos.x) != FLOOR); + + /* Put it there */ + + mvwaddch(mw, reader->t_pos.y, reader->t_pos.x, reader->t_type); + reader->t_oldch = CCHAR( mvwinch(cw, reader->t_pos.y, reader->t_pos.x) ); + } + break; + + default: + debug("'%s' is a strange scroll for a monster to read!", + r_magic[which].mi_name); + break; + } +}