This is spell.c in view mode; [Download] [Up]
/* SCCS Id: @(#)spell.c 3.0 88/09/18 * * Copyright (c) M. Stephenson 1988 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef SPELLS static schar delay; /* moves left for this spell */ static struct obj *book; /* last/current book being xscribed */ #ifdef HARD #define spelluses(spell) spl_book[spell-1].sp_uses #define decrnuses(spell) spl_book[spell-1].sp_uses-- #endif /* HARD */ #define spellev(spell) spl_book[spell-1].sp_lev #define spellname(spell) objects[spl_book[spell-1].sp_id].oc_name #define spellid(spell) spl_book[spell-1].sp_id static void cursed_book(lev) register int lev; { switch(rn2(lev)) { case 0: You("feel a wrenching sensation."); tele(); /* teleport him */ break; case 1: You("feel threatened."); aggravate(); break; case 2: make_blinded(Blinded + rn1(100,250),TRUE); break; case 3: take_gold(); break; case 4: pline("These runes were just too much to comprehend."); make_confused(HConfusion + rn1(7,16),FALSE); break; case 5: pline("The book was coated with contact poison!"); if (uarmg) { if (uarmg->rustfree) Your("gloves seem unaffected."); else if (uarmg->spe > -2) { Your("gloves corrode!"); uarmg->spe--; } else Your("gloves %s quite corroded.",Blind ? "feel":"look"); break; } if(Poison_resistance) { losestr(rn1(1,2)); losehp(rnd(6), "contact-poisoned spellbook", KILLED_BY_AN); } else { losestr(rn1(4,3)); losehp(rnd(10), "contact-poisoned spellbook", KILLED_BY_AN); } break; case 6: if(Antimagic) { shieldeff(u.ux, u.uy); pline("The book explodes, but you are unharmed!"); } else { pline("As you read the book, it explodes in your %s!", body_part(FACE)); losehp (2*rnd(10)+5, "exploding rune", KILLED_BY_AN); } break; default: rndcurse(); break; } return; } #ifndef OVERLAY static #endif int learn() { register int i; register unsigned booktype; if (delay) { /* not if (delay++), so at end delay == 0 */ delay++; return(1); /* still busy */ } booktype = book->otyp; for (i = 0; i < MAXSPELL; i++) { if (spl_book[i].sp_id == booktype) { #ifdef HARD Your("knowledge of that spell is keener."); spl_book[i].sp_uses += rn1(3,8-spl_book[i].sp_lev); #else pline("Oh, you already know that one!"); #endif break; } else if (spl_book[i].sp_id == NO_SPELL) { spl_book[i].sp_id = booktype; spl_book[i].sp_lev = objects[booktype].spl_lev; spl_book[i].sp_flags = objects[booktype].bits; #ifdef HARD /* spells have 2 .. 10-level uses. */ /* ie 2 or 3 uses w/ most potent */ spl_book[i].sp_uses = rn1(3,8-spl_book[i].sp_lev); #endif You("add the spell to your repertoire."); makeknown(booktype); break; } } if (i == MAXSPELL) impossible("Too many spells memorized!"); if (book->cursed) { /* maybe a demon cursed it */ cursed_book(objects[booktype].spl_lev); } useup(book); book = 0; return(0); } int study_book(spellbook) register struct obj *spellbook; { register int booktype = spellbook->otyp; if (delay && spellbook == book) You("continue your efforts to memorize the spell."); else { switch(booktype) { /* level 1 spells */ case SPE_HEALING: case SPE_DETECT_MONSTERS: case SPE_FORCE_BOLT: case SPE_LIGHT: case SPE_SLEEP: case SPE_KNOCK: /* level 2 spells */ case SPE_MAGIC_MISSILE: case SPE_CONFUSE_MONSTER: case SPE_SLOW_MONSTER: case SPE_CURE_BLINDNESS: case SPE_CREATE_MONSTER: case SPE_DETECT_FOOD: case SPE_WIZARD_LOCK: delay = -objects[booktype].oc_delay; break; /* level 3 spells */ case SPE_HASTE_SELF: case SPE_CAUSE_FEAR: case SPE_CURE_SICKNESS: case SPE_DETECT_UNSEEN: case SPE_EXTRA_HEALING: case SPE_CHARM_MONSTER: case SPE_CLAIRVOYANCE: /* level 4 spells */ case SPE_LEVITATION: case SPE_RESTORE_ABILITY: case SPE_INVISIBILITY: case SPE_FIREBALL: case SPE_DETECT_TREASURE: delay = -(objects[booktype].spl_lev - 1) * objects[booktype].oc_delay; break; /* level 5 spells */ case SPE_REMOVE_CURSE: case SPE_MAGIC_MAPPING: case SPE_CONE_OF_COLD: case SPE_IDENTIFY: case SPE_DIG: /* level 6 spells */ case SPE_TURN_UNDEAD: case SPE_POLYMORPH: case SPE_CREATE_FAMILIAR: case SPE_TELEPORT_AWAY: delay = -objects[booktype].spl_lev * objects[booktype].oc_delay; break; /* level 7 spells */ case SPE_CANCELLATION: case SPE_FINGER_OF_DEATH: case SPE_GENOCIDE: delay = -8 * objects[booktype].oc_delay; break; /* impossible */ default: impossible("Unknown spellbook, %d;", booktype); return(0); } if(!spellbook->blessed && (spellbook->cursed || rn2(20) > (ACURR(A_INT) + 4 + (int)(u.ulevel/2) - 2*objects[booktype].spl_lev))) { cursed_book(objects[booktype].spl_lev); nomul(delay); /* study time */ delay = 0; useup(spellbook); return(1); } You("begin to memorize the runes."); } book = spellbook; set_occupation(learn, "studying", 0); return(1); } static int getspell() { register int maxs, ilet, i; char lets[BUFSZ], buf[BUFSZ]; if (spl_book[0].sp_id == NO_SPELL) { You("don't know any spells right now."); return(0); } else { for(maxs = 1; (maxs < MAXSPELL) && (spl_book[maxs].sp_id != NO_SPELL); maxs++); if (maxs >= MAXSPELL) { impossible("Too many spells memorized."); return(0); } for(i = 0; (i < maxs) && (i < 26); buf[++i] = 0) buf[i] = 'a' + i; for(i = 26; (i < maxs) && (i < 52); buf[++i] = 0) buf[i] = 'A' + i - 26; if (maxs == 1) Strcpy(lets, "a"); else if (maxs < 27) Sprintf(lets, "a-%c", 'a' + maxs - 1); else if (maxs == 27) Sprintf(lets, "a-z A"); else Sprintf(lets, "a-z A-%c", 'A' + maxs - 27); for(;;) { pline("Cast which spell? [%s ?] ", lets); if ((ilet = readchar()) == '?') { (void) dovspell(); continue; } else if ((ilet == '\033')||(ilet == '\n')||(ilet == ' ')) return(0); else for(i = 0; buf[i] != 0; i++) if(ilet == buf[i]) return(++i); You("don't know that spell."); } } } int docast() { register int spell; spell = getspell(); if (!spell) return(0); return(spelleffects(spell,FALSE)); } int spelleffects(spell,atme) register int spell; boolean atme; { register int energy, damage; #ifdef HARD boolean confused = (Confusion != 0); #endif struct obj *pseudo; #ifdef HARD /* note that trying to cast it decrements the # of uses, */ /* even if the mage does not have enough food/energy to use */ /* the spell */ switch (spelluses(spell)) { case 0: pline ("That spell is too hard to recall at the moment."); return(0); case 1: pline ("You can barely remember the runes of this spell."); break; case 2: pline ("This spell is starting to be over-used."); break; default: break; } decrnuses(spell); #endif energy = spellev(spell); if (u.uhave_amulet) { You("feel the amulet draining your energy away."); energy *= rnd(6); } if(energy > u.uen) { You("don't have enough energy to cast that spell."); return(0); } else if ((u.uhunger <= 100 && spell != SPE_DETECT_FOOD) || (ACURR(A_STR) < 6)) { You("lack the strength for that spell."); return(0); } else { if (spell != SPE_DETECT_FOOD) morehungry(energy * 10); u.uen -= energy; } flags.botl = 1; #ifdef HARD if (confused || ((int)(ACURR(A_INT) + Luck) - 3 * spellev(spell)) < 0) { if (Hallucination) pline("Far out... a light show!"); else pline("The air around you crackles as you goof up."); return(0); } #endif /* pseudo is a temporary "false" object containing the spell stats. */ pseudo = mksobj(spellid(spell),FALSE); pseudo->blessed = pseudo->cursed = 0; pseudo->quan = 20; /* do not let useup get it */ switch(pseudo->otyp) { /* These spells are all duplicates of wand effects */ case SPE_FORCE_BOLT: case SPE_SLEEP: case SPE_MAGIC_MISSILE: case SPE_KNOCK: case SPE_SLOW_MONSTER: case SPE_WIZARD_LOCK: case SPE_FIREBALL: case SPE_CONE_OF_COLD: case SPE_DIG: case SPE_TURN_UNDEAD: case SPE_POLYMORPH: case SPE_TELEPORT_AWAY: case SPE_CANCELLATION: case SPE_FINGER_OF_DEATH: case SPE_LIGHT: case SPE_DETECT_UNSEEN: if (!(objects[pseudo->otyp].bits & NODIR)) { if (atme) u.dx = u.dy = u.dz = 0; else (void) getdir(1); if(!u.dx && !u.dy && !u.dz) { if((damage = zapyourself(pseudo))) losehp(damage, self_pronoun("zapped %sself with a spell", "him"), NO_KILLER_PREFIX); } else weffects(pseudo); } else weffects(pseudo); break; /* These are all duplicates of scroll effects */ case SPE_CONFUSE_MONSTER: case SPE_DETECT_FOOD: case SPE_CAUSE_FEAR: case SPE_CHARM_MONSTER: case SPE_REMOVE_CURSE: case SPE_MAGIC_MAPPING: case SPE_CREATE_MONSTER: case SPE_IDENTIFY: case SPE_GENOCIDE: (void) seffects(pseudo); break; case SPE_HASTE_SELF: case SPE_DETECT_TREASURE: case SPE_DETECT_MONSTERS: case SPE_LEVITATION: case SPE_RESTORE_ABILITY: case SPE_INVISIBILITY: (void) peffects(pseudo); break; case SPE_HEALING: You("feel a bit better."); healup(rnd(8), 0, 0, 0); break; case SPE_CURE_BLINDNESS: healup(0, 0, 0, 1); break; case SPE_CURE_SICKNESS: if (Sick) You("are no longer ill."); healup(0, 0, 1, 0); break; case SPE_EXTRA_HEALING: You("feel a fair bit better."); healup(d(2,8), 1, 0, 0); break; case SPE_CREATE_FAMILIAR: make_familiar((struct obj *)0); break; case SPE_CLAIRVOYANCE: do_vicinity_map(); break; default: impossible("Unknown spell %d attempted.", spell); obfree(pseudo, (struct obj *)0); return(0); } obfree(pseudo, (struct obj *)0); /* now, get rid of it */ return(1); } void losespells() { register boolean confused = (Confusion != 0); register int n, nzap, i; book = 0; for(n = 0;(spl_book[n].sp_id != NO_SPELL) && (n < MAXSPELL); n++); if (!n) return; if (n < MAXSPELL) { nzap = rnd(n); if (nzap < n) nzap += confused; for (i = 0; i < nzap; i++) spl_book[n-i-1].sp_id = NO_SPELL; } else impossible("Too many spells memorized!"); return; } static char spellet(spl) int spl; { return (spl < 27) ? ('a' + spl - 1) : ('A' + spl - 27); } int dovspell() { register int maxs, i; char buf[BUFSZ], any[BUFSZ]; if (spl_book[0].sp_id == NO_SPELL) { You("don't know any spells right now."); return 0; } for(maxs = 1; (maxs < MAXSPELL) && (spl_book[maxs].sp_id != NO_SPELL); maxs++); if (maxs >= MAXSPELL) { impossible("Too many spells memorized."); return 0; } morc = 0; /* just to be sure */ cornline(0, "Currently known spells:"); for(i = 1; i <= maxs; i++) { #ifdef HARD Sprintf(buf, "%c %c %s (%d)", spellet(i), (spelluses(i)) ? '-' : '*', spellname(i), spellev(i)); #else Sprintf(buf, "%c %s (%d)", spellet(i), spellname(i), spellev(i)); #endif cornline(1, buf); any[i-1] = spellet(i); } any[i-1] = 0; cornline(2, any); return 0; } #endif /* SPELLS /**/
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.