Source:Spell.c

The file spell.c contains code to handle spells and spellbooks.

TODO: check if the annotated values derived from "rnd" calls are correct.

Top of file
/*	SCCS Id: @(#)spell.c	3.4	2003/01/17	*/ /*	Copyright (c) M. Stephenson 1988			 */ /* NetHack may be freely redistributed. See license for details. */

static NEARDATA schar delay;		/* moves left for this spell */ static NEARDATA struct obj *book;	/* last/current book being xscribed */
 * 1) include "hack.h"

TODO: check what is "xscribed" in this context.

/* spellmenu arguments; 0 thru n-1 used as spl_book[] index when swapping */
 * 1) define SPELLMENU_CAST (-2)
 * 2) define SPELLMENU_VIEW (-1)


 * 1) define KEEN 20000
 * 2) define MAX_SPELL_STUDY 3
 * 3) define incrnknow(spell)       spl_book[spell].sp_know = KEEN

((char)((spell < 26) ? ('a' + spell) : ('A' + spell - 26)))
 * 1) define spellev(spell)		spl_book[spell].sp_lev
 * 2) define spellname(spell)	OBJ_NAME(objects[spellid(spell)])
 * 3) define spellet(spell)	\

This sets up a bunch of macros. Most of these are simply programming shortcuts for this file. When you successfully read a spellbook, your knowledge is set to KEEN. Here, KEENn is 20000. This means that your spell knowledge will last for 20000 turns.

STATIC_DCL int FDECL(spell_let_to_idx, (CHAR_P)); STATIC_DCL boolean FDECL(cursed_book, (struct obj *bp)); STATIC_DCL boolean FDECL(confused_book, (struct obj *)); STATIC_DCL void FDECL(deadbook, (struct obj *)); STATIC_PTR int NDECL(learn); STATIC_DCL boolean FDECL(getspell, (int *)); STATIC_DCL boolean FDECL(dospellmenu, (const char *,int,int *)); STATIC_DCL int FDECL(percent_success, (int)); STATIC_DCL int NDECL(throwspell); STATIC_DCL void NDECL(cast_protection); STATIC_DCL void FDECL(spell_backfire, (int)); STATIC_DCL const char *FDECL(spelltypemnemonic, (int)); STATIC_DCL int FDECL(isqrt, (int));

Now are the function declarations.


 * [After the function declarations is a long spoiler comment about the ability of different roles to cast spells. It reveals a spell that each role can cast well.]


 * 1) define uarmhbon 4 /* Metal helmets interfere with the mind */
 * 2) define uarmgbon 6 /* Casting channels through the hands */
 * 3) define uarmfbon 2 /* All metal interferes to some degree */

These macros will appear in the code that controls how the wearing of metal armor impacts the ability to succeed in casting a spell.

/* since the spellbook itself doesn't blow up, don't say just "explodes" */ static const char explodes[] = "radiates explosive energy";

The variable  is a constant C string. Farther down in the code are printf-style constructs like  to message the player that the book is exploding. However, as this comment reveals, the spellbooks do not actually explode, they only "radiate explosive energy".

cursed_book
The cursed_book function randomly decides what bad will happen when you try to read a cursed spellbook. In general, never read a cursed spellbook, or always uncurse it before reading.

The function receives an object pointer, presumably a cursed spellbook. It decides what harm the spellbook will cause, implements the harm, and decides whether the spellbook destroyed itself in the process. The function that called  must do the actual process of destroying the spellbook, if necessary.

/* TRUE: book should be destroyed by caller */ STATIC_OVL boolean cursed_book(bp) struct obj *bp; {	int lev = objects[bp->otyp].oc_level;

switch(rn2(lev)) { case 0: You_feel("a wrenching sensation."); tele;		/* teleport him */ break;

A common effect of reading a cursed spellbook is the "wrenching sensation", which causes the reader to teleport. When you need to escape, and you do not have a scroll of teleport, wand of teleport or other method to teleport, reading a low-level cursed spellbook might save you.

case 1: You_feel("threatened."); aggravate; break;

This is one of several ways to aggravate the monsters around you. This has some effects, for example monsters which were peaceful will now attack you.

case 2: make_blinded(Blinded + rn1(100,250),TRUE); break;

No yellow light around? Then note that sometimes, a peek into a cursed spellbook will harm you so much as to blind you for 100 to 250 turns! The  part is needed to add on the preexisting number of turns left if you are already blind.

case 3: take_gold; break;

This is annoying. The code is in another function somewhere, but when it runs, your purse empties completely. Remember this: reading a cursed spellbook of level 3 or greater could cost you all of your gold.

case 4: pline("These runes were just too much to comprehend."); make_confused(HConfusion + rn1(7,16),FALSE); break;

Confusion for only 7 to 16 turns does not seem so bad, when compared to the blindness under cased 2.

case 5: pline_The("book was coated with contact poison!"); if (uarmg) { if (uarmg->oerodeproof || !is_corrodeable(uarmg)) { Your("gloves seem unaffected."); } else if (uarmg->oeroded2 < MAX_ERODE) { if (uarmg->greased) { grease_protect(uarmg, "gloves", &youmonst); } else { Your("gloves corrode%s!",				 uarmg->oeroded2+1 == MAX_ERODE ?				 " completely" : uarmg->oeroded2 ?				 " further" : ""); uarmg->oeroded2++; }		   } else Your("gloves %s completely corroded.",			    Blind ? "feel" : "look"); break; }		/* temp disable in_use; death should not destroy the book */ bp->in_use = FALSE; losestr(Poison_resistance ? rn1(2,1) : rn1(4,3)); losehp(rnd(Poison_resistance ? 6 : 10),		      "contact-poisoned spellbook", KILLED_BY_AN); bp->in_use = TRUE; break;

Sometimes, when reading a cursed spellbook, it will randomly seem to be poisoned. Further, in addition to the usual loss of strength and health, this poison has additional harmful effects. If you have poison resistance, eat as many poisonous corpses as you want, but beware of contact-poisoned spellbooks; poison resistance will reduce but not prevent harm.
 * refers to your gloves. Poison, it seems, does not only reduce strength and harm health, but it in this case it apparently also corrodes your gloves. (Note: in obj.h each object has two types of erosion,  and  ; this code uses the latter.)
 * In the call to, you have the potential to lose up to 4 points of strength, or up to 2 points if you have poison resistance.
 * As with any call to, this call might cause death. In this case, the cause is "contact-poisoned spellbook"; this appears to be the only way in NetHack to have a contact-poisoned spellbook kill your player. You lose 10 hp (which is quite bad for low-level players), or 6 hp if you have poison resistance.

case 6: if(Antimagic) { shieldeff(u.ux, u.uy); pline_The("book %s, but you are unharmed!", explodes); } else { pline("As you read the book, it %s in your %s!",			 explodes, body_part(FACE)); losehp(2*rnd(10)+5, "exploding rune", KILLED_BY_AN); }		return TRUE;

It is a magical explosion! The book "explodes", but remember that explodes is actually defined at the top of this source file, so the book "radiates explosive energy".

The good news is that magic resistance is effective. The same that guards you against magic missiles and magic traps is also good for magic spellbooks. If you lack that resistance, then you can lose up to 105 hp. (Ouch!)

default: rndcurse; break; }	return FALSE; }

TODO: check what  does. Find the code, or maybe play wizard mode and order several cursed spellbooks of identify.