#ifndef WH_STRUCTS_H_edd60534_ #define WH_STRUCTS_H_edd60534_ /* * Data structure definitions, including relevant constants. */ #include #include #include "param.h" /* * Levels are `named' by numbers. These are the numbers for the * special levels: the elemental planes, the underworld, and hell. */ #define L_EARTH (-1) #define L_AIR (-2) #define L_FIRE (-3) #define L_WATER (-4) #define L_UNDERWORLD (-5) #define L_HELL (-6) // The (algebraeically) lowest elemental level number. #define L__FIRSTELEM (-4) // The number of elemental levels. #define L__NELEM 4 // Negative of the most-negative special level number. #define LEVEL_OFFSET 6 // Total number of levels. #define N_LEVELS (DUNGEON_LEVELS+LEVEL_OFFSET) /* * Various places want to create arrays indexed by elemental level * number (L_EARTH, etc). The trick used to do so is safe only when * the elemental levels are the smallest (closest to zero) of the * negative special level numbers. (Without that, it depends on * working with a pointer value that C does not promise exists.) * These places have a #if testing this condition, with a comment * saying "see structs.h". */ /* * Time. Time is nominally measured in "ticks", whose size is * unspecified. Since we want to be able to represent less than a * tick (eg, for hasted monsters), we also keep tick fractions. We do * this using fixed-point arithmetic; a TIME is just a 64-bit integer, * of which the low 32 bits are the fractional part and the high 32 * the integer part. TIMESCALE is the factor by which a tick count * must be multiplied to turn it into a TIME; TIMESHIFT is * lg(TIMESCALE); or, to put it another way, TIMESCALE is * 1<" in comments here means "towards", which is not always * "directly connected to". */ typedef enum { /* subtypes of LOC_GATE */ LOC_GATE_DUNGEON = 1, // Main dungeon LOC_GATE_UWORLD_DUNGEON, // Underworld -> dungeon LOC_GATE_UWORLD_HELL, // Underworld -> Hell LOC_GATE_HELL, // Hell LOC_GATE_ELEM_DUNGEON, // Elemental -> dungeon LOC_GATE_ELEM_UWORLD, // Elemental -> Underworld } GATETYPE; typedef struct invobj INVOBJ; typedef struct level LEVEL; typedef struct loc LOC; typedef struct monops MONOPS; typedef struct monst MONST; typedef struct montype MONTYPE; typedef struct mtinfo MTINFO; typedef struct obj OBJ; typedef struct objops OBJOPS; typedef struct objtype OBJTYPE; typedef struct shop SHOP; typedef struct trail TRAIL; typedef struct trap TRAP; typedef struct invent INVENT; typedef struct xy XY; typedef struct jmp JMP; typedef struct effect EFFECT; typedef struct effectops EFFECTOPS; typedef struct tdrv TDRV; typedef struct bonusroll BONUSROLL; typedef struct damage DAMAGE; /* * These are used as part of SIGINT handling. See signals.c. */ struct jmp { jmp_buf b; } ; /* * Used in various places for coordinate pairs, either absolute or * relative. */ struct xy { short int x; short int y; } ; /* * An inventory list. This consists of the chain of objects (inv), a * type field indicating what kind of place the inventory is (type - * see INVTYPE above), and a type-specific field describing exactly * where the inventory is (u.m and u.l); */ struct invent { INVOBJ *inv; INVTYPE type; union { MONST *m; LOC *l; } u; } ; /* * A location in a dungeon level. This consists of coordinates (x and * y), a location type (type - see LOCTYPE above), and type-specific * data (orientation for WALL, orientation and open/closed state for * DOOR, subtype for CAVE and GATE), some flag bits, tracking data, * contents (a potential inventory of objects and a potential * monster), a link to the "other" location (for, eg, gates), and a * backpointer to the level this cell is part of. */ struct loc { unsigned char x; unsigned char y; LOCTYPE type; union { unsigned char walldoor; #define LOC_WALL_H 1 #define LOC_WALL_V 2 #define LOC_UWALL 0 #define LOC_HWALL (LOC_WALL_H) #define LOC_VWALL (LOC_WALL_V) #define LOC_TWALL (LOC_WALL_H|LOC_WALL_V) #define LOC_DOOR_CLOSED 0 #define LOC_DOOR_OPEN 4 #define LOC_CHDOOR (LOC_DOOR_CLOSED|LOC_HWALL) #define LOC_CVDOOR (LOC_DOOR_CLOSED|LOC_VWALL) #define LOC_OHDOOR (LOC_DOOR_OPEN|LOC_HWALL) #define LOC_OVDOOR (LOC_DOOR_OPEN|LOC_VWALL) CAVETYPE cavetype; GATETYPE gatetype; } ; unsigned int flags; #define LF_SHOP 0x00000001 #define LF_VAULT 0x00000002 #define LF_NOCROWN 0x00000004 #define LF_FLAG 0x00000008 #define LF_FLAGB 0x00000010 #define LF_VISIBLE 0x00000020 #define LF_WATER 0x00000040 #define LF__PERMANENT (LF_SHOP|LF_VAULT|LF_NOCROWN|LF_WATER) #define TRACK_DUMB 0 #define TRACK_SMART 1 #define NTRACKTYPES 2 LOC *tracks[NTRACKTYPES]; TIME tracktime[NTRACKTYPES]; unsigned int exitdist; INVENT objs; MONST *monst; LOC *to; LEVEL *on; } ; /* * A shop. Shops are kept in a linked list per level; besides the list * link, a shop knows what level it's on, its shopkeeper's name, a * type (some shops can specialize in, eg, scrolls or wands), a * position, size, and entrance door location. */ struct shop { SHOP *link; LEVEL *on; const char *shkname; int type; #define SHOP_BASETYPE 1 #define SHOP_TYPE_GENERAL 1 #define SHOP_NTYPES 1 XY pos; XY size; XY door; } ; /* * A trail left by a monster. Just a linked list of LOCs. These also * occasionally get abused for other linked lists of LOCs, but that * really is an abuse of the type. */ struct trail { TRAIL *link; LOC *loc; } ; /* * A trap. Traps are kept in a per-level linked list; besides the list * link, a trap has just a type and a location. */ struct trap { TRAP *link; TRAPTYPE type; LOC *loc; } ; /* * A dungeon level. A level knows its level number, its index in the * array of levels, a short name, a long name, some flags, an offset * so that the dungeon does not have to have all its levels' bounding * boxes line up vertically, an indication of how good visibility is, * counts of various things on the level, the list heads for shops and * trap, pointers to the levels above and below it (if any), the gates * in and out (if any), and the array of LOCs making it up. */ struct level { int levelno; int index; const char *shortname; const char *longname; int flags; #define LVF_WRAPAROUND 0x00000001 #define LVF_DRIFT 0x00000002 #define LVF_SEEN 0x00000004 XY off; int visibility; int ncorr; int nstup; int ncave; int nmonst; int nunflagged; SHOP *shops; TRAP *traps; LEVEL *up; LEVEL *down; LOC *gate_ib; LOC *gate_ob; LOC cells[LEV_X][LEV_Y]; } ; /* * A monster type. There's one of these per monster type. That is, * there is one for you (the player), one for rats, etc. See also * MTINFO, below. */ struct montype { const char *name; char letter; MTINFO *info; } ; /* * TDRV = TakeDamage Return Value. This is the return value from a * monster type's takedamage method. takedamage wants to return two * things: (1) the amount of damage actually taken (which may not be * the amount passed in because of DR or overkill) and (2) a boolean * indicating whether the monster died as a result. */ struct tdrv { int taken; unsigned int flags; #define TDRV_DIED 0x00000001 } ; /* * Damage. This is a struct rather than a simple int because some * damage can be healed in only certain ways, requiring tracking * multiple kinds of damage. */ struct damage { int ordinary; int magiconly; int timeonly; } ; #define DMG_ORDINARY(n) ((DAMAGE){.ordinary=(n), .magiconly=0, .timeonly=0}) #define DMG_MAGICONLY(n) ((DAMAGE){.ordinary=0, .magiconly=(n), .timeonly=0}) #define DMG_TIMEONLY(n) ((DAMAGE){.ordinary=0, .magiconly=0, .timeonly=(n)}) #define DMG_GENERAL(ord,mag,tim) ((DAMAGE){.ordinary=(ord), .magiconly=(mag), .timeonly=(tim)}) /* * Monster type info. This summarizes almost everything about a * monster type. The only things it doesn't cover are those stored in * MONTYPE, above. * * The reason MONTYPE and MTINFO are split, rather than being a single * struct, is that MONTYPEs are generated mechanically from monlist * and just include a pointer to the MTINFO. * * Here, we have a call (new) to set up a new instance of the monster * given the allocated and cleared MONST (it returns a pointer so that * it can, for example, destroy the monster), and a function to * perform operations on the monster (monctl). */ struct mtinfo { MONST *(*new)(MONST *, LEVEL *); void (*monctl)(MONST *, int, ...); #define MCTL_AGGR 1 TIME basespeed; int baseheal; int exp; int mtype; } ; #define MTINFO_INIT(name) {\ &new_##name, \ &monctl_##name, \ basespeed_##name, \ baseheal_##name, \ exp_##name, \ } /* * The operations vector for a monster. There is usually one of these * per monster type, but some monster types may have multiple ops * vectors and switch among them based on internal conditions. * * The operations: * * tick - it's the monster's turn to move; let it take its move. * * bemoved - the monster has been moved; let it adjust its internal * data structures, if appropriate. * * name - return the monster's name, suitable for contexts where simple * words begin with a lowercase letter (eg, "You hit %s"). * * Name - return the monster's name, suitable for contexts where simple * words begin with an uppercase letter (eg, "%s hits you"). * * attack - return a number giving the strength of the monster's * attack. This is the to-hit roll, to put it loosely. The higher * the return value, the likelier the attack is to hit. * * defend - return a number giving the strength of the monster's * defense. This will normally roll dice based on armour. The higher * the return value, the stronger the defense. * * givedamage - return the amount of damage done by a hit by this * monster. This is the damage roll. The second arg is the amount by * which the to-hit roll exceeded the defense roll. * * takedamage - The monster has been hit; take the damage and do * anything appropriate in consequence. This usually will point to * std_takedamage, but monsters with DR, for example, may do something * special here. * * kill - The monster has been reduced to 0hp or less; do anything * appropriate in consequence. This usually points to std_kill, which * just destroys the monster and drops its inventory, but monsters for * which something special needs to happen can override this. (For * example, the player-avatar monster does this, because death for * that monster means Game Over.) * * destroy - The monster is gone; clean up any associated data * structures. This usually points to std_destroyi, which just * free()s the argument, but if the monster has private data, this is * the hook for freeing it up. */ struct monops { void (*tick)(MONST *); void (*bemoved)(MONST *); const char *(*name)(MONST *); const char *(*Name)(MONST *); int (*attack)(MONST *); int (*defend)(MONST *); DAMAGE (*givedamage)(MONST *, int); TDRV (*takedamage)(MONST *, DAMAGE); void (*kill)(MONST *); void (*destroy)(MONST *); } ; /* * An effect ops vector. * * When a new effect is added or removed, the effect-modifiable fields * of the affected monster are reinitialized and all effects' apply * functions are called. Things such as destroying temporary effects * after a timer expires, or revoking ring effects when rings are * removed, must be handled by effect-private code. For example, the * private data for a potion's effect could point to a potion-private * structure which includes a fuse for the timeout. * * The death function is called on monster death to clean up any * leftover state for the effect. The effect will have already been * removed from the monster's effects chain when this happens. * * There is no init method. The code that creats the effect is * expected to handle any setup necessary. * * There is no assumption that the private data pointer is non-nil. */ struct effectops { void (*apply)(MONST *, void *); void (*death)(MONST *, void *); } ; #define EFFECTOPS_INIT(name) {\ &apply_##name, \ &death_##name, \ } /* * A (potentially temporary) status effect on a monster. * * Every monster has a list of these; they are used for things like * potions which have duration and rings. An effect has a MONST * backpointer, a link in the linked list of all effects on that * monster, private data, and an ops vector. */ struct effect { EFFECT *link; MONST *m; void *private; EFFECTOPS *ops; } ; /* * A bonus roll. These need some overhead data, too: they are kept in * lists, from which they may be removed out-of-order, hence forward * and backward links and list-root pointer. But they may need to be * destroyed by code other than their creators, eg on monster death, * hence the teardown method and private data pointer. */ struct bonusroll { BONUSROLL *flink; BONUSROLL *blink; BONUSROLL **list; const char *roll; void (*teardown)(BONUSROLL *); void *priv; } ; /* * A monster. This consists of: * * type: MONTYPE. * symbol: on-screen symbol. * hp: current hit points. * maxhp: maximum hit points. * heal: heal rate, in hit points per tick. * magiconly: amount of damage that can be healed only by magic. * timeonly: amount of damage that can be healed only by time. * flags: various flags. * speed: speed, in TIME between actions. * age: age in ticks (number of times its tick method has been called). * created: creation TIME. * fuseid: ID of the fuse used to generate its ticks. * you: the (x,y) at which it saw you (valid iff SAWYOU set in flags). * priv: type-private data. * link: next link in the chain of all monsters. * ops: ops vector. * invent: inventory. * lastloc: previous location. * loc: current lcoation. * effects: list of status effects. * rings: rings worn (up to MAXRINGS of them). * armour: armour worn. * weapon: weapon wielded. * bonus_def: defense bonuses. * bonus_hit: to-hit bonuses. * bonus_dmg: damage bonuses. * * Note that INVISIBLE exists as both a base flag and an effect flag. * This is to account for both permanent invisibility (intrinsically * invisible monsters, wand of make invisible) and temporary * invisibility (ring/potion of invisibility). */ struct monst { MONTYPE *type; char symbol; int hp; int maxhp; int magiconly; int timeonly; int heal; unsigned int baseflags; #define MBF_DEAD 0x00000001 #define MBF_ASLEEP 0x00000002 #define MBF_INVISIBLE 0x00000004 #define MBF_TELEPATHIC 0x00000008 #define MBF_SAWYOU 0x00000010 #define MBF_TRACKING 0x00000020 #define MBF_PLANE_E 0x00000040 #define MBF_PLANE_A 0x00000080 #define MBF_PLANE_F 0x00000100 #define MBF_PLANE_W 0x00000200 #define MBF_CROWN 0x00000400 unsigned int effflags; #define MEF_INVISIBLE 0x00000001 #define MEF_SEE_INVISIBLE 0x00000002 #define MEF_VAMP_REGEN 0x00000004 #define MEF_PHASING 0x00000008 #define MEF_BREATHE_WATER 0x00000010 #define MEF_RESIST_FIRE 0x00000020 #define MEF_PERCEPTION 0x00000040 #define MEF_TELEPORT_CTL 0x00000080 #define MEF_MEMORY 0x00000100 TIME speed; int age; TIME created; int fuseid; XY you; void *priv; MONST *link; MONOPS *ops; INVENT invent; LOC *lastloc; LOC *loc; EFFECT *effects; OBJ *rings[MAXRINGS]; OBJ *armour; OBJ *weapon; BONUSROLL *bonus_def; BONUSROLL *bonus_hit; BONUSROLL *bonus_dmg; // When adding struct members, init them in newmon()! } ; /* * An object in an inventory. This consists of a link to the next * INVOBJ in the inventory (link), a backpointer to the INVENT it * belongs to (inv), its index within the inventory (xwi), the number * of objects displayed (dispn, eg, 25 in "25 arrows"), and a vector * (v) and count (n) of the objects proper making up this inventory * object. * * Note that xwi 0 is reserved for gold; other objects get 1 up. * * The reason there can be multiple objects in a single inventory * object is that unidentified objects may be different in important * ways but indistinguishable to the player, so they have to be kept * separate but displayed as if they were identical. (For example, if * the player is carrying 10 unidentified +0,+0 arrows and picks up 3 * unidentified +1,+2 arrows, they will display as "13 arrows" until * and unless something happens to distinguish them, like using a * scroll of identify on them.) * * Note that objects of different types never occur together in a * single INVOBJ. */ struct invobj { INVOBJ *link; INVENT *inv; int xwi; int dispn; int n; OBJ **v; } ; /* * An object proper. This is just a type, a count, and type-specific * private data. */ struct obj { int type; int number; INVOBJ *io; void *private; } ; /* * The ops vector for an object type. The methods here are * * new - set up a new object of this type. The object is passed in and * returned. The first argument is the object type (so that the same * new function can be used for multiple types). * * old - free up any private data the object has. This is called just * before free()ing the OBJ. * * format - print, to the FILE *, the text for an INVOBJ of this type. * This generates a string suitable for displaying in, eg, an * inventory listing. * * fmt_cond - handles type-specific conditionals in description * strings. See format.c for more. * * fmt_spec - handles type-specific format specifiers in description * strings. See format.c for more. * * collapsible - decides whether two OBJs of this type should be merged * in an inventory slot. For example, objects with plusses will * usually test whether either object is identified, and, if both are, * whether the plusses are identical. * * identical - decides whether two OBJs of this type should be * considered completely identical. * * split - turn a plural OBJ of this type into two OBJs, with a given * number of them in the new OBJ. The new OBJ is returned. * * identified - returns whether an INVOBJ of this type is identified. * For object classes with both type-level identification and * object-level identification (eg, wands, with type-level "wand of * FOO" and object-level "with N charges"), this call tests the * type-level identification. For other classes, it may be * object-specific (eg, weapons, for which it tests an object-specific * flag). * * identify - identifies an INVOBJ of this type, returning a * (potentially multi-entry) INVOBJ list it turns into. * * moved - called when an object is moved from one inventory into * another. This can be used to, for example, alter things upon * acquiring or losing an object for which mere possession is * significant. * * cursable - true if "cursed" is a meaningful concept for objects of * this type. * * setcursed - called to set an OBJ cursed or not. Must not be called * unless cursable is true. */ struct objops { OBJ *(*new)(int, OBJ *); void (*old)(OBJ *); void (*format)(FILE *, INVOBJ *); int (*fmt_cond)(char, INVOBJ *); void (*fmt_spec)(FILE *, char, INVOBJ *); int (*collapsible)(OBJ *, OBJ *); int (*identical)(OBJ *, OBJ *); OBJ *(*split)(OBJ *, int); int (*identified)(INVOBJ *); INVOBJ *(*identify)(INVOBJ *); void (*moved)(INVOBJ *, INVENT *, INVENT *); int cursable; void (*setcursed)(OBJ *, int); } ; #define OBJOPS_INIT(name) {\ &new_##name, \ &old_##name, \ &format_##name, \ &fmt_cond_##name, \ &fmt_spec_##name, \ &collapsible_##name, \ &identical_##name, \ &split_##name, \ &identified_##name, \ &identify_##name, \ &moved_##name, \ cursable_##name, \ &setcursed_##name, \ } /* * An object type. These are the next level of granularity after * object class. Thus, for example, there is the object class * "potion" (OC_POTION), but there is the OBJTYPE "potion of healing". * * There are five strings, nomnially names (their usage is mostly up to * the format string, though see shuffle_name23()'s calls and * definition), a format string used for generating inventory item * descriptions, the object's class, the symbol used for display, the * ops vector, a flags field, a player-specified identifier, and an * object-type-private pointer. */ struct objtype { const char *name; const char *name2; const char *name3; const char *name4; const char *format; int class; char sym; OBJOPS *ops; unsigned int flags; #define OTF_KNOWN 0x00000001 char *called; void *priv; } ; #endif