Difference between revisions of "Source:NetHack 3.4.3/src/spell.c"

From NetHackWiki
Jump to navigation Jump to search
m (At start, link to source code.)
(cursed_book: Comment that already-blind players would not be able to read spellbooks.)
Line 108: Line 108:
 
</pre>
 
</pre>
  
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 [[turn]]s! The <code>Blinded +</code> part is needed to add on the preexisting number of turns left if you are already blind.
+
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 [[turn]]s! Because of the <code>Blinded +</code> part, if you are already blind, then you will remain blind for 100 to 250 more turns. (Ignore that there seems to be no way to read a spellbook if you are already blind.)
  
 
<pre>
 
<pre>

Revision as of 07:13, 18 May 2006

In the vanilla 3.4.3 source code, 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. */

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

#include "hack.h"

static NEARDATA schar delay;		/* moves left for this spell */
static NEARDATA struct obj *book;	/* last/current book being xscribed */

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

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

#define KEEN 20000
#define MAX_SPELL_STUDY 3
#define incrnknow(spell)        spl_book[spell].sp_know = KEEN

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

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, KEEN 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.]
#define uarmhbon 4 /* Metal helmets interfere with the mind */
#define uarmgbon 6 /* Casting channels through the hands */
#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 explodes is a constant C string. Farther down in the code are printf-style constructs like "The book %s!", explodes 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".

spell_let_to_idx

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 bp, 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 cursed_book 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! Because of the Blinded + part, if you are already blind, then you will remain blind for 100 to 250 more turns. (Ignore that there seems to be no way to read a spellbook 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.

  • uarmg 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, uarmg->oeroded and uarmg->oeroded2; this code uses the latter.)
  • In the call to losestr, 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 losehp, 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 rndcurse does. Find the code, or maybe play wizard mode and order several cursed spellbooks of identify.

confused_book

deadbook

learn

getspell

dospellmenu

percent_success

throwspell

cast_protection

spell_backfire

spelltypemnemonic

isqrt

This page is a stub. Should you wish to do so, you can contribute by expanding this page.

A user has suggested improving this page or section as follows:

"Does anyone want to document the other functions?"