/* NetHack 3.6 rm.h $NHDT-Date: 1580070206 2020/01/26 20:23:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.78 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2017. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef RM_H #define RM_H /* * The dungeon presentation graphics code and data structures were rewritten * and generalized for NetHack's release 2 by Eric S. Raymond (eric@snark) * building on Don G Kneller's MS-DOS implementation. See drawing.c for * the code that permits the user to set the contents of the symbol structure. * * The door representation was changed by Ari * Huttunen(ahuttune@niksula.hut.fi) */ /* * TLCORNER TDWALL TRCORNER * +- -+- -+ * | | | * * TRWALL CROSSWALL TLWALL HWALL * | | | * +- -+- -+ --- * | | | * * BLCORNER TUWALL BRCORNER VWALL * | | | | * +- -+- -+ | */ /* Level location types. [Some debugging code in src/display.c defines array type_names[] which contains an entry for each of these, so needs to be kept in sync if any new types are added or existing ones renumbered.] */ enum levl_typ_types { STONE = 0, VWALL = 1, HWALL = 2, TLCORNER = 3, TRCORNER = 4, BLCORNER = 5, BRCORNER = 6, CROSSWALL = 7, /* For pretty mazes and special levels */ TUWALL = 8, TDWALL = 9, TLWALL = 10, TRWALL = 11, DBWALL = 12, TREE = 13, /* KMH */ SDOOR = 14, SCORR = 15, POOL = 16, MOAT = 17, /* pool that doesn't boil, adjust messages */ WATER = 18, DRAWBRIDGE_UP = 19, LAVAPOOL = 20, IRONBARS = 21, /* KMH */ DOOR = 22, CORR = 23, ROOM = 24, STAIRS = 25, LADDER = 26, FOUNTAIN = 27, THRONE = 28, SINK = 29, GRAVE = 30, ALTAR = 31, ICE = 32, DRAWBRIDGE_DOWN = 33, AIR = 34, CLOUD = 35, MAX_TYPE = 36, INVALID_TYPE = 127 }; /* * Avoid using the level types in inequalities: * these types are subject to change. * Instead, use one of the macros below. */ #define IS_WALL(typ) ((typ) && (typ) <= DBWALL) #define IS_STWALL(typ) ((typ) <= DBWALL) /* STONE <= (typ) <= DBWALL */ #define IS_ROCK(typ) ((typ) < POOL) /* absolutely nonaccessible */ #define IS_DOOR(typ) ((typ) == DOOR) #define IS_DOORJOIN(typ) (IS_ROCK(typ) || (typ) == IRONBARS) #define IS_TREE(typ) \ ((typ) == TREE || (g.level.flags.arboreal && (typ) == STONE)) #define ACCESSIBLE(typ) ((typ) >= DOOR) /* good position */ #define IS_ROOM(typ) ((typ) >= ROOM) /* ROOM, STAIRS, furniture.. */ #define ZAP_POS(typ) ((typ) >= POOL) #define SPACE_POS(typ) ((typ) > DOOR) #define IS_POOL(typ) ((typ) >= POOL && (typ) <= DRAWBRIDGE_UP) #define IS_THRONE(typ) ((typ) == THRONE) #define IS_FOUNTAIN(typ) ((typ) == FOUNTAIN) #define IS_SINK(typ) ((typ) == SINK) #define IS_GRAVE(typ) ((typ) == GRAVE) #define IS_ALTAR(typ) ((typ) == ALTAR) #define IS_DRAWBRIDGE(typ) \ ((typ) == DRAWBRIDGE_UP || (typ) == DRAWBRIDGE_DOWN) #define IS_FURNITURE(typ) ((typ) >= STAIRS && (typ) <= ALTAR) #define IS_AIR(typ) ((typ) == AIR || (typ) == CLOUD) #define IS_SOFT(typ) ((typ) == AIR || (typ) == CLOUD || IS_POOL(typ)) /* * The screen symbols may be the default or defined at game startup time. * See drawing.c for defaults. * Note: {ibm|dec|curses}_graphics[] arrays (also in drawing.c) must be kept in * synch. */ /* begin dungeon characters */ enum screen_symbols { S_stone = 0, S_vwall = 1, S_hwall = 2, S_tlcorn = 3, S_trcorn = 4, S_blcorn = 5, S_brcorn = 6, S_crwall = 7, S_tuwall = 8, S_tdwall = 9, S_tlwall = 10, S_trwall = 11, S_ndoor = 12, S_vodoor = 13, S_hodoor = 14, S_vcdoor = 15, /* closed door, vertical wall */ S_hcdoor = 16, /* closed door, horizontal wall */ S_bars = 17, /* KMH -- iron bars */ S_tree = 18, /* KMH */ S_room = 19, S_darkroom = 20, S_corr = 21, S_litcorr = 22, S_upstair = 23, S_dnstair = 24, S_upladder = 25, S_dnladder = 26, S_altar = 27, S_grave = 28, S_throne = 29, S_sink = 30, S_fountain = 31, S_pool = 32, S_ice = 33, S_lava = 34, S_vodbridge = 35, S_hodbridge = 36, S_vcdbridge = 37, /* closed drawbridge, vertical wall */ S_hcdbridge = 38, /* closed drawbridge, horizontal wall */ S_air = 39, S_cloud = 40, S_water = 41, /* end dungeon characters, begin traps */ S_arrow_trap = 42, S_dart_trap = 43, S_falling_rock_trap = 44, S_squeaky_board = 45, S_bear_trap = 46, S_land_mine = 47, S_rolling_boulder_trap = 48, S_sleeping_gas_trap = 49, S_rust_trap = 50, S_fire_trap = 51, S_pit = 52, S_spiked_pit = 53, S_hole = 54, S_trap_door = 55, S_teleportation_trap = 56, S_level_teleporter = 57, S_magic_portal = 58, S_web = 59, S_statue_trap = 60, S_magic_trap = 61, S_anti_magic_trap = 62, S_polymorph_trap = 63, S_vibrating_square = 64, /* for display rather than any trap effect */ /* end traps, begin special effects */ S_vbeam = 65, /* The 4 zap beam symbols. Do NOT separate. */ S_hbeam = 66, /* To change order or add, see function */ S_lslant = 67, /* zapdir_to_glyph() in display.c. */ S_rslant = 68, S_digbeam = 69, /* dig beam symbol */ S_flashbeam = 70, /* camera flash symbol */ S_boomleft = 71, /* thrown boomerang, open left, e.g ')' */ S_boomright = 72, /* thrown boomerang, open right, e.g. '(' */ S_ss1 = 73, /* 4 magic shield ("resistance sparkle") glyphs */ S_ss2 = 74, S_ss3 = 75, S_ss4 = 76, S_poisoncloud = 77, S_goodpos = 78, /* valid position for targeting via getpos() */ /* The 8 swallow symbols. Do NOT separate. To change order or add, */ /* see the function swallow_to_glyph() in display.c. */ S_sw_tl = 79, /* swallow top left [1] */ S_sw_tc = 80, /* swallow top center [2] Order: */ S_sw_tr = 81, /* swallow top right [3] */ S_sw_ml = 82, /* swallow middle left [4] 1 2 3 */ S_sw_mr = 83, /* swallow middle right [6] 4 5 6 */ S_sw_bl = 84, /* swallow bottom left [7] 7 8 9 */ S_sw_bc = 85, /* swallow bottom center [8] */ S_sw_br = 86, /* swallow bottom right [9] */ S_explode1 = 87, /* explosion top left */ S_explode2 = 88, /* explosion top center */ S_explode3 = 89, /* explosion top right Ex. */ S_explode4 = 90, /* explosion middle left */ S_explode5 = 91, /* explosion middle center /-\ */ S_explode6 = 92, /* explosion middle right |@| */ S_explode7 = 93, /* explosion bottom left \-/ */ S_explode8 = 94, /* explosion bottom center */ S_explode9 = 95, /* explosion bottom right */ /* end effects */ MAXPCHARS = 96 /* maximum number of mapped characters */ }; #define MAXDCHARS (S_water - S_stone + 1) /* mapped dungeon characters */ #define MAXTCHARS (S_vibrating_square - S_arrow_trap + 1) /* trap chars */ #define MAXECHARS (S_explode9 - S_vbeam + 1) /* mapped effects characters */ #define MAXEXPCHARS 9 /* number of explosion characters */ #define DARKROOMSYM (Is_rogue_level(&u.uz) ? S_stone : S_darkroom) #define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap) #define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge) #define is_cmap_door(i) ((i) >= S_vodoor && (i) <= S_hcdoor) #define is_cmap_wall(i) ((i) >= S_stone && (i) <= S_trwall) #define is_cmap_room(i) ((i) >= S_room && (i) <= S_darkroom) #define is_cmap_corr(i) ((i) >= S_corr && (i) <= S_litcorr) #define is_cmap_furniture(i) ((i) >= S_upstair && (i) <= S_fountain) #define is_cmap_water(i) ((i) == S_pool || (i) == S_water) #define is_cmap_lava(i) ((i) == S_lava) struct symdef { uchar sym; const char *explanation; #ifdef TEXTCOLOR uchar color; #endif }; struct symparse { unsigned range; #define SYM_CONTROL 1 /* start/finish markers */ #define SYM_PCHAR 2 /* index into showsyms */ #define SYM_OC 3 /* index into oc_syms */ #define SYM_MON 4 /* index into monsyms */ #define SYM_OTH 5 /* misc */ int idx; const char *name; }; /* misc symbol definitions */ #define SYM_BOULDER 0 #define SYM_INVISIBLE 1 #define SYM_PET_OVERRIDE 2 #define SYM_HERO_OVERRIDE 3 #define MAXOTHER 4 /* linked list of symsets and their characteristics */ struct symsetentry { struct symsetentry *next; /* next in list */ char *name; /* ptr to symset name */ char *desc; /* ptr to description */ int idx; /* an index value */ int handling; /* known handlers value */ Bitfield(nocolor, 1); /* don't use color if set */ Bitfield(primary, 1); /* restricted for use as primary set */ Bitfield(rogue, 1); /* restricted for use as rogue lev set */ Bitfield(explicitly, 1); /* explicit symset set */ /* 4 free bits */ }; /* * Graphics sets for display symbols */ #define DEFAULT_GRAPHICS 0 /* regular characters: '-', '+', &c */ #define PRIMARY 0 /* primary graphics set */ #define ROGUESET 1 /* rogue graphics set */ #define NUM_GRAPHICS 2 /* * special symbol set handling types ( for invoking callbacks, etc.) * Must match the order of the known_handlers strings * in drawing.c */ #define H_UNK 0 #define H_IBM 1 #define H_DEC 2 #define H_CURS 3 #define H_MAC 4 /* obsolete; needed so that the listing of available * symsets by 'O' can skip it for !MAC_GRAPHICS_ENV */ extern const struct symdef defsyms[MAXPCHARS]; /* defaults */ #define WARNCOUNT 6 /* number of different warning levels */ extern const struct symdef def_warnsyms[WARNCOUNT]; #define SYMHANDLING(ht) (g.symset[g.currentgraphics].handling == (ht)) /* * Note: secret doors (SDOOR) want to use both rm.doormask and * rm.wall_info but those both overload rm.flags. SDOOR only * has 2 states (closed or locked). However, it can't specify * D_CLOSED due to that conflicting with WM_MASK (below). When * a secret door is revealed, the door gets set to D_CLOSED iff * it isn't set to D_LOCKED (see cvt_sdoor_to_door() in detect.c). * * D_TRAPPED conflicts with W_NONDIGGABLE but the latter is not * expected to be used on door locations. */ /* * The 5 possible states of doors. */ #define D_NODOOR 0 #define D_BROKEN 1 #define D_ISOPEN 2 #define D_CLOSED 4 #define D_LOCKED 8 #define D_TRAPPED 16 #define D_SECRET 32 /* only used by sp_lev.c, NOT in rm-struct */ /* * Some altars are considered as shrines, so we need a flag. */ #define AM_SHRINE 8 /* * Thrones should only be looted once. */ #define T_LOOTED 1 /* * Trees have more than one kick result. */ #define TREE_LOOTED 1 #define TREE_SWARM 2 /* * Fountains have limits, and special warnings. */ #define F_LOOTED 1 #define F_WARNED 2 #define FOUNTAIN_IS_WARNED(x, y) (levl[x][y].looted & F_WARNED) #define FOUNTAIN_IS_LOOTED(x, y) (levl[x][y].looted & F_LOOTED) #define SET_FOUNTAIN_WARNED(x, y) levl[x][y].looted |= F_WARNED; #define SET_FOUNTAIN_LOOTED(x, y) levl[x][y].looted |= F_LOOTED; #define CLEAR_FOUNTAIN_WARNED(x, y) levl[x][y].looted &= ~F_WARNED; #define CLEAR_FOUNTAIN_LOOTED(x, y) levl[x][y].looted &= ~F_LOOTED; /* * doors are even worse :-) The special warning has a side effect * of instantly trapping the door, and if it was defined as trapped, * the guards consider that you have already been warned! */ #define D_WARNED 16 /* * Sinks have 3 different types of loot that shouldn't be abused */ #define S_LPUDDING 1 #define S_LDWASHER 2 #define S_LRING 4 /* * The four directions for a DrawBridge. */ #define DB_NORTH 0 #define DB_SOUTH 1 #define DB_EAST 2 #define DB_WEST 3 #define DB_DIR 3 /* mask for direction */ /* * What's under a drawbridge. */ #define DB_MOAT 0 #define DB_LAVA 4 #define DB_ICE 8 #define DB_FLOOR 16 #define DB_UNDER 28 /* mask for underneath */ /* * Wall information. Nondiggable also applies to iron bars. */ #define WM_MASK 0x07 /* wall mode (bottom three bits) */ #define W_NONDIGGABLE 0x08 #define W_NONPASSWALL 0x10 /* * Ladders (in Vlad's tower) may be up or down. */ #define LA_UP 1 #define LA_DOWN 2 /* * Room areas may be iced pools */ #define ICED_POOL 8 #define ICED_MOAT 16 /* * The structure describing a coordinate position. * Before adding fields, remember that this will significantly affect * the size of temporary files and save files. * * Also remember that the run-length encoding for some ports in save.c * must be updated to consider the field. */ struct rm { int glyph; /* what the hero thinks is there */ schar typ; /* what is really there */ uchar seenv; /* seen vector */ Bitfield(flags, 5); /* extra information for typ */ Bitfield(horizontal, 1); /* wall/door/etc is horiz. (more typ info) */ Bitfield(lit, 1); /* speed hack for lit rooms */ Bitfield(waslit, 1); /* remember if a location was lit */ Bitfield(roomno, 6); /* room # for special rooms */ Bitfield(edge, 1); /* marks boundaries for special rooms*/ Bitfield(candig, 1); /* Exception to Can_dig_down; was a trapdoor */ }; #define SET_TYPLIT(x, y, ttyp, llit) \ { \ if ((x) >= 0 && (y) >= 0 && (x) < COLNO && (y) < ROWNO) { \ if ((ttyp) < MAX_TYPE) \ levl[(x)][(y)].typ = (ttyp); \ if ((ttyp) == LAVAPOOL) \ levl[(x)][(y)].lit = 1; \ else if ((schar)(llit) != -2) { \ if ((schar)(llit) == -1) \ levl[(x)][(y)].lit = rn2(2); \ else \ levl[(x)][(y)].lit = (llit); \ } \ } \ } /* * Add wall angle viewing by defining "modes" for each wall type. Each * mode describes which parts of a wall are finished (seen as as wall) * and which are unfinished (seen as rock). * * We use the bottom 3 bits of the flags field for the mode. This comes * in conflict with secret doors, but we avoid problems because until * a secret door becomes discovered, we know what sdoor's bottom three * bits are. * * The following should cover all of the cases. * * type mode Examples: R=rock, F=finished * ----- ---- ---------------------------- * WALL: 0 none hwall, mode 1 * 1 left/top (1/2 rock) RRR * 2 right/bottom (1/2 rock) --- * FFF * * CORNER: 0 none trcorn, mode 2 * 1 outer (3/4 rock) FFF * 2 inner (1/4 rock) F+- * F|R * * TWALL: 0 none tlwall, mode 3 * 1 long edge (1/2 rock) F|F * 2 bottom left (on a tdwall) -+F * 3 bottom right (on a tdwall) R|F * * CRWALL: 0 none crwall, mode 5 * 1 top left (1/4 rock) R|F * 2 top right (1/4 rock) -+- * 3 bottom left (1/4 rock) F|R * 4 bottom right (1/4 rock) * 5 top left & bottom right (1/2 rock) * 6 bottom left & top right (1/2 rock) */ #define WM_W_LEFT 1 /* vertical or horizontal wall */ #define WM_W_RIGHT 2 #define WM_W_TOP WM_W_LEFT #define WM_W_BOTTOM WM_W_RIGHT #define WM_C_OUTER 1 /* corner wall */ #define WM_C_INNER 2 #define WM_T_LONG 1 /* T wall */ #define WM_T_BL 2 #define WM_T_BR 3 #define WM_X_TL 1 /* cross wall */ #define WM_X_TR 2 #define WM_X_BL 3 #define WM_X_BR 4 #define WM_X_TLBR 5 #define WM_X_BLTR 6 /* * Seen vector values. The seen vector is an array of 8 bits, one for each * octant around a given center x: * * 0 1 2 * 7 x 3 * 6 5 4 * * In the case of walls, a single wall square can be viewed from 8 possible * directions. If we know the type of wall and the directions from which * it has been seen, then we can determine what it looks like to the hero. */ #define SV0 0x01 #define SV1 0x02 #define SV2 0x04 #define SV3 0x08 #define SV4 0x10 #define SV5 0x20 #define SV6 0x40 #define SV7 0x80 #define SVALL 0xFF /* if these get changed or expanded, make sure wizard-mode wishing becomes aware of the new usage */ #define doormask flags /* door, sdoor (note conflict with wall_info) */ #define altarmask flags /* alignment and maybe temple */ #define wall_info flags /* wall, sdoor (note conflict with doormask) */ #define ladder flags /* up or down */ #define drawbridgemask flags /* what's underneath when the span is open */ #define looted flags /* used for throne, tree, fountain, sink, door */ #define icedpool flags /* used for ice (in case it melts) */ /* horizonal applies to walls, doors (including sdoor); also to iron bars even though they don't have separate symbols for horizontal and vertical */ #define blessedftn horizontal /* a fountain that grants attribs */ #define disturbed horizontal /* a grave that has been disturbed */ struct damage { struct damage *next; long when, cost; coord place; schar typ; }; /* for bones levels: identify the dead character, who might have died on an existing bones level; if so, most recent victim will be first in list */ struct cemetery { struct cemetery *next; /* next struct is previous dead character... */ /* "g.plname" + "-ROLe" + "-RACe" + "-GENder" + "-ALIgnment" + \0 */ char who[PL_NSIZ + 4 * (1 + 3) + 1]; /* death reason, same as in score/log file */ char how[100 + 1]; /* [DTHSZ+1] */ /* date+time in string of digits rather than binary */ char when[4 + 2 + 2 + 2 + 2 + 2 + 1]; /* "YYYYMMDDhhmmss\0" */ /* final resting place spot */ schar frpx, frpy; boolean bonesknown; }; struct levelflags { uchar nfountains; /* number of fountains on level */ uchar nsinks; /* number of sinks on the level */ /* Several flags that give hints about what's on the level */ Bitfield(has_shop, 1); Bitfield(has_vault, 1); Bitfield(has_zoo, 1); Bitfield(has_court, 1); Bitfield(has_morgue, 1); Bitfield(has_beehive, 1); Bitfield(has_barracks, 1); Bitfield(has_temple, 1); Bitfield(has_swamp, 1); Bitfield(noteleport, 1); Bitfield(hardfloor, 1); Bitfield(nommap, 1); Bitfield(hero_memory, 1); /* hero has memory */ Bitfield(shortsighted, 1); /* monsters are shortsighted */ Bitfield(graveyard, 1); /* has_morgue, but remains set */ Bitfield(sokoban_rules, 1); /* fill pits and holes w/ boulders */ Bitfield(is_maze_lev, 1); Bitfield(is_cavernous_lev, 1); Bitfield(arboreal, 1); /* Trees replace rock */ Bitfield(wizard_bones, 1); /* set if level came from a bones file which was created in wizard mode (or normal mode descendant of such) */ Bitfield(corrmaze, 1); /* Whether corridors are used for the maze rather than ROOM */ }; typedef struct { struct rm locations[COLNO][ROWNO]; #ifndef MICROPORT_BUG struct obj *objects[COLNO][ROWNO]; struct monst *monsters[COLNO][ROWNO]; #else struct obj *objects[1][ROWNO]; char *yuk1[COLNO - 1][ROWNO]; struct monst *monsters[1][ROWNO]; char *yuk2[COLNO - 1][ROWNO]; #endif struct obj *objlist; struct obj *buriedobjlist; struct monst *monlist; struct damage *damagelist; struct cemetery *bonesinfo; struct levelflags flags; } dlevel_t; /* * Macros for compatibility with old code. Someday these will go away. */ #define levl g.level.locations #define fobj g.level.objlist #define fmon g.level.monlist /* * Covert a trap number into the defsym graphics array. * Convert a defsym number into a trap number. * Assumes that arrow trap will always be the first trap. */ #define trap_to_defsym(t) (S_arrow_trap + (t) -1) #define defsym_to_trap(d) ((d) -S_arrow_trap + 1) #define OBJ_AT(x, y) (g.level.objects[x][y] != (struct obj *) 0) /* * Macros for encapsulation of level.monsters references. */ #if 0 #define MON_AT(x, y) \ (g.level.monsters[x][y] != (struct monst *) 0 \ && !(g.level.monsters[x][y])->mburied) #define MON_BURIED_AT(x, y) \ (g.level.monsters[x][y] != (struct monst *) 0 \ && (g.level.monsters[x][y])->mburied) #else /* without 'mburied' */ #define MON_AT(x, y) (g.level.monsters[x][y] != (struct monst *) 0) #endif #ifdef EXTRA_SANITY_CHECKS #define place_worm_seg(m, x, y) \ do { \ if (g.level.monsters[x][y] && g.level.monsters[x][y] != m) \ impossible("place_worm_seg over mon"); \ g.level.monsters[x][y] = m; \ } while(0) #define remove_monster(x, y) \ do { \ if (!g.level.monsters[x][y]) \ impossible("no monster to remove"); \ g.level.monsters[x][y] = (struct monst *) 0; \ } while(0) #else #define place_worm_seg(m, x, y) g.level.monsters[x][y] = m #define remove_monster(x, y) g.level.monsters[x][y] = (struct monst *) 0 #endif #define m_at(x, y) (MON_AT(x, y) ? g.level.monsters[x][y] : (struct monst *) 0) #define m_buried_at(x, y) \ (MON_BURIED_AT(x, y) ? g.level.monsters[x][y] : (struct monst *) 0) /* restricted movement, potential luck penalties */ #define Sokoban g.level.flags.sokoban_rules #endif /* RM_H */