home *** CD-ROM | disk | FTP | other *** search
- /* SCCS Id: @(#)display.c 3.1 92/10/25 */
- /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */
- /* and Dave Cohrs, 1990. */
- /* NetHack may be freely redistributed. See license for details. */
-
- /*
- * THE NEW DISPLAY CODE
- *
- * The old display code has been broken up into three parts: vision, display,
- * and drawing. Vision decides what locations can and cannot be physically
- * seen by the hero. Display decides _what_ is displayed at a given location.
- * Drawing decides _how_ to draw a monster, fountain, sword, etc.
- *
- * The display system uses information from the vision system to decide
- * what to draw at a given location. The routines for the vision system
- * can be found in vision.c and vision.h. The routines for display can
- * be found in this file (display.c) and display.h. The drawing routines
- * are part of the window port. See doc/window.doc for the drawing
- * interface.
- *
- * The display system deals with an abstraction called a glyph. Anything
- * that could possibly be displayed has a unique glyph identifier.
- *
- * What is seen on the screen is a combination of what the hero remembers
- * and what the hero currently sees. Objects and dungeon features (walls
- * doors, etc) are remembered when out of sight. Monsters and temporary
- * effects are not remembered. Each location on the level has an
- * associated glyph. This is the hero's _memory_ of what he or she has
- * seen there before.
- *
- * Display rules:
- *
- * If the location is in sight, display in order:
- * visible monsters
- * visible objects
- * known traps
- * background
- *
- * If the location is out of sight, display in order:
- * sensed monsters (telepathy)
- * memory
- *
- *
- *
- * Here is a list of the major routines in this file to be used externally:
- *
- * newsym
- *
- * Possibly update the screen location (x,y). This is the workhorse routine.
- * It is always correct --- where correct means following the in-sight/out-
- * of-sight rules. **Most of the code should use this routine.** This
- * routine updates the map and displays monsters.
- *
- *
- * map_background
- * map_object
- * map_trap
- * unmap_object
- *
- * If you absolutely must override the in-sight/out-of-sight rules, there
- * are two possibilities. First, you can mess with vision to force the
- * location in sight then use newsym(), or you can use the map_* routines.
- * The first has not been tried [no need] and the second is used in the
- * detect routines --- detect object, magic mapping, etc. The map_*
- * routines *change* what the hero remembers. All changes made by these
- * routines will be sticky --- they will survive screen redraws. Do *not*
- * use these for things that only temporarily change the screen. These
- * routines are also used directly by newsym(). unmap_object is used to
- * clear a remembered object when/if detection reveals it isn't there.
- *
- *
- * show_glyph
- *
- * This is direct (no processing in between) buffered access to the screen.
- * Temporary screen effects are run through this and its companion,
- * flush_screen(). There is yet a lower level routine, print_glyph(),
- * but this is unbuffered and graphic dependent (i.e. it must be surrounded
- * by graphic set-up and tear-down routines). Do not use print_glyph().
- *
- *
- * see_monsters
- * see_objects
- *
- * These are only used when something affects all of the monsters or
- * objects. For objects, the only thing is hallucination. For monsters,
- * there are hallucination and changing from/to blindness, etc.
- *
- *
- * tmp_at
- *
- * This is a useful interface for displaying temporary items on the screen.
- * Its interface is different than previously, so look at it carefully.
- *
- *
- *
- * Parts of the rm structure that are used:
- *
- * typ - What is really there.
- * glyph - What the hero remembers. This will never be a monster.
- * Monsters "float" above this.
- * lit - True if the position is lit. An optimization for
- * lit/unlit rooms.
- * waslit - True if the position was *remembered* as lit.
- * seen - Set to true when the location is seen or felt as it really
- * is. This is used primarily for walls, which look like stone
- * if seen from the outside of a room. However, this is
- * also used as a guide for blind heros. If the hero has
- * seen or felt a room feature underneath a boulder, when the
- * boulder is moved, the hero should see it again. This is
- * also used as an indicator for unmapping detected objects.
- *
- * doormask - Additional information for the typ field.
- * horizontal - Indicates whether the wall or door is horizontal or
- * vertical.
- */
- #include "hack.h"
-
- static void FDECL(display_monster,(XCHAR_P,XCHAR_P,struct monst *,int,XCHAR_P));
- static int FDECL(swallow_to_glyph, (int, int));
-
- #ifdef INVISIBLE_OBJECTS
- /*
- * vobj_at()
- *
- * Returns a pointer to an object if the hero can see an object at the
- * given location. This takes care of invisible objects. NOTE, this
- * assumes that the hero is not blind and on top of the object pile.
- * It does NOT take into account that the location is out of sight, or,
- * say, one can see blessed, etc.
- */
- struct obj *
- vobj_at(x,y)
- xchar x,y;
- {
- register struct obj *obj = level.objects[x][y];
-
- while (obj) {
- if (!obj->oinvis || See_invisible) return obj;
- obj = obj->nexthere;
- }
- return ((struct obj *) 0);
- }
- #endif /* else vobj_at() is defined in display.h */
-
- /*
- * The routines map_background(), map_object(), and map_trap() could just
- * as easily be:
- *
- * map_glyph(x,y,glyph,show)
- *
- * Which is called with the xx_to_glyph() in the call. Then I can get
- * rid of 3 routines that don't do very much anyway. And then stop
- * having to create fake objects and traps. However, I am reluctant to
- * make this change.
- */
-
- /*
- * map_background()
- *
- * Make the real background part of our map. This routine assumes that
- * the hero can physically see the location. Update the screen if directed.
- */
- void
- map_background(x, y, show)
- register xchar x,y;
- register int show;
- {
- register int glyph = back_to_glyph(x,y);
-
- if (level.flags.hero_memory)
- levl[x][y].glyph = glyph;
- if (show) show_glyph(x,y, glyph);
- }
-
- /*
- * map_trap()
- *
- * Map the trap and print it out if directed. This routine assumes that the
- * hero can physically see the location.
- */
- void
- map_trap(trap, show)
- register struct trap *trap;
- register int show;
- {
- register int x = trap->tx, y = trap->ty;
- register int glyph = trap_to_glyph(trap);
-
- if (level.flags.hero_memory)
- levl[x][y].glyph = glyph;
- if (show) show_glyph(x, y, glyph);
- }
-
- /*
- * map_object()
- *
- * Map the given object. This routine assumes that the hero can physically
- * see the location of the object. Update the screen if directed.
- */
- void
- map_object(obj, show)
- register struct obj *obj;
- register int show;
- {
- register int x = obj->ox, y = obj->oy;
- register int glyph = obj_to_glyph(obj);
-
- if (level.flags.hero_memory)
- levl[x][y].glyph = glyph;
- if (show) show_glyph(x, y, glyph);
- }
-
- /*
- * unmap_object()
- *
- * Remove something from the map when detection reveals that it isn't
- * there any more. Replace it with background or known trap, but not
- * with any other remembered object. No need to update the display;
- * a full update is imminent.
- *
- * This isn't quite correct due to overloading of the seen bit. But
- * it works well enough for now.
- */
- void
- unmap_object(x, y)
- register int x, y;
- {
- register struct trap *trap;
-
- if (!level.flags.hero_memory) return;
-
- if ((trap = t_at(x,y)) != 0 && trap->tseen && !covers_traps(x,y))
- map_trap(trap, 0);
- else if (levl[x][y].seen) {
- struct rm *lev = &levl[x][y];
-
- map_background(x, y, 0);
-
- /* turn remembered dark room squares dark */
- if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) &&
- lev->typ == ROOM)
- lev->glyph = cmap_to_glyph(S_stone);
- } else
- levl[x][y].glyph = cmap_to_glyph(S_stone); /* default val */
- }
-
-
- /*
- * map_location()
- *
- * Make whatever at this location show up. This is only for non-living
- * things. This will not handle feeling invisible objects correctly.
- */
- #define map_location(x,y,show) \
- { \
- register struct obj *obj; \
- register struct trap *trap; \
- \
- if ((obj = vobj_at(x,y)) && !covers_objects(x,y)) \
- map_object(obj,show); \
- else if ((trap = t_at(x,y)) && trap->tseen && !covers_traps(x,y)) \
- map_trap(trap,show); \
- else \
- map_background(x,y,show); \
- }
-
-
- /*
- * display_monster()
- *
- * Note that this is *not* a map_XXXX() function! Monsters sort of float
- * above everything.
- *
- * Yuck. Display body parts by recognizing that the display position is
- * not the same as the monster position. Currently the only body part is
- * a worm tail.
- *
- */
- static void
- display_monster(x, y, mon, in_sight, worm_tail)
- register xchar x, y; /* display position */
- register struct monst *mon; /* monster to display */
- int in_sight; /* TRUE if the monster is physically seen */
- register xchar worm_tail; /* mon is actually a worm tail */
- {
- register boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING);
- register int sensed = mon_mimic &&
- (Protection_from_shape_changers || sensemon(mon));
-
- /*
- * We must do the mimic check first. If the mimic is mimicing something,
- * and the location is in sight, we have to change the hero's memory
- * so that when the position is out of sight, the hero remembers what
- * the mimic was mimicing.
- */
-
- if (mon_mimic && in_sight) {
- switch (mon->m_ap_type) {
- default:
- impossible("display_monster: bad m_ap_type value [ = %d ]",
- (int) mon->m_ap_type);
- case M_AP_NOTHING:
- show_glyph(x, y, mon_to_glyph(mon));
- break;
-
- case M_AP_FURNITURE: {
- /*
- * This is a poor man's version of map_background(). I can't
- * use map_background() because we are overriding what is in
- * the 'typ' field. Maybe have map_background()'s parameters
- * be (x,y,glyph) instead of just (x,y).
- *
- * mappearance is currently set to an S_ index value in
- * makemon.c.
- */
- register int glyph = cmap_to_glyph(mon->mappearance);
- levl[x][y].glyph = glyph;
- if (!sensed) show_glyph(x,y, glyph);
- break;
- }
-
- case M_AP_OBJECT: {
- struct obj obj; /* Make a fake object to send */
- /* to map_object(). */
- obj.ox = x;
- obj.oy = y;
- obj.otyp = mon->mappearance;
- obj.corpsenm = PM_TENGU; /* if mimicing a corpse */
- map_object(&obj,!sensed);
- break;
- }
-
- case M_AP_MONSTER:
- show_glyph(x,y, monnum_to_glyph(what_mon(mon->mappearance)));
- break;
- }
-
- }
-
- /* If the mimic is unsucessfully mimicing something, display the monster */
- if (!mon_mimic || sensed) {
- if (mon->mtame) {
- if (worm_tail)
- show_glyph(x,y, petnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)));
- else
- show_glyph(x,y, pet_to_glyph(mon));
- } else {
- if (worm_tail)
- show_glyph(x,y, monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)));
- else
- show_glyph(x,y, mon_to_glyph(mon));
- }
- }
- }
-
- /*
- * feel_location()
- *
- * Feel the given location. This assumes that the hero is blind and that
- * the given position is either the hero's or one of the eight squares
- * adjacent to the hero (except for a boulder push).
- */
- void
- feel_location(x, y)
- xchar x, y;
- {
- struct rm *lev = &(levl[x][y]);
- struct obj *boulder;
- register struct monst *mon;
-
- /* The hero can't feel non pool locations while under water. */
- if (Underwater && !Is_waterlevel(&u.uz) && ! is_pool(x,y))
- return;
-
- /* If the hero is not in a corridor, then she will feel the wall as a */
- /* wall. It doesn't matter if the hero is levitating or not. */
- if ((IS_WALL(lev->typ) || lev->typ == SDOOR) &&
- levl[u.ux][u.uy].typ != CORR)
- lev->seen = 1;
-
- if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
- /*
- * Levitation Rules. It is assumed that the hero can feel the state
- * of the walls around herself and can tell if she is in a corridor,
- * room, or doorway. Boulders are felt because they are large enough.
- * Anything else is unknown because the hero can't reach the ground.
- * This makes things difficult.
- *
- * Check (and display) in order:
- *
- * + Stone, walls, and closed doors.
- * + Boulders. [see a boulder before a doorway]
- * + Doors.
- * + Room/water positions
- * + Everything else (hallways!)
- */
- if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) &&
- (lev->doormask & (D_LOCKED | D_CLOSED)))) {
- map_background(x, y, 1);
- } else if (boulder = sobj_at(BOULDER,x,y)) {
- map_object(boulder, 1);
- } else if (IS_DOOR(lev->typ)) {
- map_background(x, y, 1);
- } else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) {
- /*
- * An open room or water location. Normally we wouldn't touch
- * this, but we have to get rid of remembered boulder symbols.
- * This will only occur in rare occations when the hero goes
- * blind and doesn't find a boulder where expected (something
- * came along and picked it up). We know that there is not a
- * boulder at this location. Show fountains, pools, etc.
- * underneath if already seen. Otherwise, show the appropriate
- * floor symbol.
- *
- * This isn't quite correct. If the boulder was on top of some
- * other objects they should be seen once the boulder is removed.
- * However, we have no way of knowing that what is there now
- * was there then. So we let the hero have a lapse of memory.
- * We could also just display what is currently on the top of the
- * object stack (if anything).
- */
- if (lev->glyph == objnum_to_glyph(BOULDER)) {
- if (lev->typ != ROOM && lev->seen) {
- map_background(x, y, 1);
- } else {
- lev->glyph = lev->waslit ? cmap_to_glyph(S_room) :
- cmap_to_glyph(S_stone);
- show_glyph(x,y,lev->glyph);
- }
- }
- } else {
- /* We feel it (I think hallways are the only things left). */
- map_background(x, y, 1);
- /* Corridors are never felt as lit (unless remembered that way) */
- /* (lit_corridor only). */
- if (lev->typ == CORR &&
- lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
- show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
- }
- } else {
- map_location(x, y, 1);
-
- if (Punished) {
- /*
- * A ball or chain is only felt if it is first on the object
- * location list. Otherwise, we need to clear the felt bit ---
- * something has been dropped on the ball/chain. If the bit is
- * not cleared, then when the ball/chain is moved it will drop
- * the wrong glyph.
- */
- if (uchain->ox == x && uchain->oy == y) {
- if (level.objects[x][y] == uchain)
- u.bc_felt |= BC_CHAIN;
- else
- u.bc_felt &= ~BC_CHAIN; /* do not feel the chain */
- }
- if (!carried(uball) && uball->ox == x && uball->oy == y) {
- if (level.objects[x][y] == uball)
- u.bc_felt |= BC_BALL;
- else
- u.bc_felt &= ~BC_BALL; /* do not feel the ball */
- }
- }
-
- /* Floor spaces are dark if unlit. Corridors are dark if unlit. */
- if (lev->typ == ROOM &&
- lev->glyph == cmap_to_glyph(S_room) && !lev->waslit)
- show_glyph(x,y, lev->glyph = cmap_to_glyph(S_stone));
- else if (lev->typ == CORR &&
- lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
- show_glyph(x,y, lev->glyph = cmap_to_glyph(S_corr));
- }
- /* draw monster on top if we can sense it */
- if ((x != u.ux || y != u.uy) && (mon = m_at(x,y)) && sensemon(mon))
- display_monster(x,y,mon,1,((x != mon->mx) || (y != mon->my)));
- }
-
- /*
- * newsym()
- *
- * Possibly put a new glyph at the given location.
- */
- void
- newsym(x,y)
- register xchar x,y;
- {
- register struct monst *mon;
- register struct rm *lev = &(levl[x][y]);
- register int see_it;
- register xchar worm_tail;
-
- /* only permit updating the hero when swallowed */
- if (u.uswallow) {
- if (x == u.ux && y == u.uy) display_self();
- return;
- }
- if (Underwater && !Is_waterlevel(&u.uz)) {
- /* don't do anything unless (x,y) is an adjacent underwater position */
- int dx, dy;
- if (!is_pool(x,y)) return;
- dx = x - u.ux; if (dx < 0) dx = -dx;
- dy = y - u.uy; if (dy < 0) dy = -dy;
- if (dx > 1 || dy > 1) return;
- }
-
- /* Can physically see the location. */
- if (cansee(x,y)) {
- lev->waslit = (lev->lit!=0); /* remember lit condition */
-
- if (x == u.ux && y == u.uy) {
- if (canseeself()) {
- map_location(x,y,0); /* map *under* self */
- display_self();
- } else
- /* we can see what is there */
- map_location(x,y,1);
- }
- else if ((mon = m_at(x,y)) &&
- ((see_it = mon_visible(mon)) || sensemon(mon))) {
- map_location(x,y,0); /* map under the monster */
- worm_tail = ((x != mon->mx) || (y != mon->my));
- display_monster(x,y,mon,see_it,worm_tail);
- }
- else
- map_location(x,y,1); /* map the location */
- }
-
- /* Can't see the location. */
- else {
- if (x == u.ux && y == u.uy) {
- feel_location(u.ux, u.uy); /* forces an update */
-
- if (canseeself()) display_self();
- }
- else if ((mon = m_at(x,y)) && sensemon(mon) &&
- !((x != mon->mx) || (y != mon->my))) {
- /* Monsters are printed every time. */
- display_monster(x,y,mon,0,0);
- }
- /*
- * If the location is remembered as being both dark (waslit is false)
- * and lit (glyph is a lit room or lit corridor) then it was either:
- *
- * (1) A dark location that the hero could see through night
- * vision.
- *
- * (2) Darkened while out of the hero's sight. This can happen
- * when cursed scroll of light is read.
- *
- * In either case, we have to manually correct the hero's memory to
- * match waslit. Deciding when to change waslit is non-trivial.
- *
- * Note: If flags.lit_corridor is set, then corridors act like room
- * squares. That is, they light up if in night vision range.
- * If flags.lit_corridor is not set, then corridors will
- * remain dark unless lit by a light spell.
- *
- * These checks and changes must be here and not in back_to_glyph().
- * They are dependent on the position being out of sight.
- */
- else if (!lev->waslit) {
- if (flags.lit_corridor && lev->glyph == cmap_to_glyph(S_litcorr) &&
- lev->typ == CORR)
- show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
- else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM)
- show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone));
- else
- goto show_mem;
- } else {
- show_mem:
- show_glyph(x, y, lev->glyph);
- }
- }
- }
-
-
- /*
- * shieldeff()
- *
- * Put magic shield pyrotechnics at the given location. This *could* be
- * pulled into a platform dependent routine for fancier graphics if desired.
- */
- void
- shieldeff(x,y)
- xchar x,y;
- {
- register int i;
-
- if (cansee(x,y)) { /* Don't see anything if can't see the location */
- for (i = 0; i < SHIELD_COUNT; i++) {
- show_glyph(x, y, cmap_to_glyph(shield_static[i]));
- flush_screen(1); /* make sure the glyph shows up */
- delay_output();
- }
- newsym(x,y); /* restore the old information */
- }
- }
-
-
- /*
- * tmp_at()
- *
- * Temporarily place glyphs on the screen. Do not call delay_output(). It
- * is up to the caller to decide if it wants to wait [presently, everyone
- * but explode() wants to delay].
- *
- * Call:
- * (DISP_BEAM, glyph) open, initialize glyph
- * (DISP_FLASH, glyph) open, initialize glyph
- * (DISP_CHANGE, glyph) change glyph
- * (DISP_END, 0) close & clean up (second argument doesn't
- * matter)
- * (x, y) display the glyph at the location
- *
- * DISP_BEAM - Display the given glyph at each location, but do not erase
- * any until the close call.
- * DISP_FLASH - Display the given glyph at each location, but erase the
- * previous location's glyph.
- */
- void
- tmp_at(x, y)
- int x, y;
- {
- static coord saved[COLNO]; /* prev positions, only for DISP_BEAM */
- static int sidx = 0; /* index of saved previous positions */
- static int sx = -1, sy; /* previous position, only for DISP_FLASH */
- static int status; /* either DISP_BEAM or DISP_FLASH */
- static int glyph; /* glyph to use when printing */
-
- switch (x) {
- case DISP_BEAM:
- case DISP_FLASH:
- status = x;
- glyph = y;
- flush_screen(0); /* flush buffered glyphs */
- break;
-
- case DISP_CHANGE:
- glyph = y;
- break;
-
- case DISP_END:
- if (status == DISP_BEAM) {
- register int i;
-
- /* Erase (reset) from source to end */
- for (i = 0; i < sidx; i++)
- newsym(saved[i].x,saved[i].y);
- sidx = 0;
-
- } else if (sx >= 0) { /* DISP_FLASH (called at least once) */
- newsym(sx,sy); /* reset the location */
- sx = -1; /* reset sx to an illegal pos for next time */
- }
- break;
-
- default: /* do it */
- if (!cansee(x,y)) break;
-
- if (status == DISP_BEAM) {
- saved[sidx ].x = x; /* save pos for later erasing */
- saved[sidx++].y = y;
- }
-
- else { /* DISP_FLASH */
- if (sx >= 0) /* not first call */
- newsym(sx,sy); /* update the old position */
-
- sx = x; /* save previous pos for next call */
- sy = y;
- }
-
- show_glyph(x,y,glyph); /* show it */
- flush_screen(0); /* make sure it shows up */
- break;
- } /* end case */
- }
-
-
- /*
- * swallowed()
- *
- * The hero is swallowed. Show a special graphics sequence for this. This
- * bypasses all of the display routines and messes with buffered screen
- * directly. This method works because both vision and display check for
- * being swallowed.
- */
- void
- swallowed(first)
- int first;
- {
- static xchar lastx, lasty; /* last swallowed position */
- int swallower;
-
- if (first)
- cls();
- else {
- register int x, y;
-
- /* Clear old location */
- for (y = lasty-1; y <= lasty+1; y++)
- if(isok(lastx,y)) {
- for (x = lastx-1; x <= lastx+1; x++)
- show_glyph(x,y,cmap_to_glyph(S_stone));
- }
- }
-
- swallower = monsndx(u.ustuck->data);
- /*
- * Display the hero surrounded by the monster's stomach.
- */
- if(isok(u.ux, u.uy-1)) {
- show_glyph(u.ux-1, u.uy-1, swallow_to_glyph(swallower, S_sw_tl));
- show_glyph(u.ux , u.uy-1, swallow_to_glyph(swallower, S_sw_tc));
- show_glyph(u.ux+1, u.uy-1, swallow_to_glyph(swallower, S_sw_tr));
- }
-
- show_glyph(u.ux-1, u.uy , swallow_to_glyph(swallower, S_sw_ml));
- display_self();
- show_glyph(u.ux+1, u.uy , swallow_to_glyph(swallower, S_sw_mr));
-
- if(isok(u.ux, u.uy+1)) {
- show_glyph(u.ux-1, u.uy+1, swallow_to_glyph(swallower, S_sw_bl));
- show_glyph(u.ux , u.uy+1, swallow_to_glyph(swallower, S_sw_bc));
- show_glyph(u.ux+1, u.uy+1, swallow_to_glyph(swallower, S_sw_br));
- }
-
- /* Update the swallowed position. */
- lastx = u.ux;
- lasty = u.uy;
- }
-
- /*
- * under_water()
- *
- * Similar to swallowed() in operation. Shows hero when underwater
- * except when in water level. Special routines exist for that.
- */
- void
- under_water(mode)
- int mode;
- {
- static xchar lastx, lasty;
- static boolean dela;
- register int x, y;
-
- /* swallowing has a higher precedence than under water */
- if (Is_waterlevel(&u.uz) || u.uswallow) return;
-
- /* full update */
- if (mode == 1 || dela) {
- cls();
- dela = FALSE;
- }
- /* delayed full update */
- else if (mode == 2) {
- dela = TRUE;
- return;
- }
- /* limited update */
- else {
- for (y = lasty-1; y <= lasty+1; y++)
- for (x = lastx-1; x <= lastx+1; x++)
- if (isok(x,y))
- show_glyph(x,y,cmap_to_glyph(S_stone));
- }
- for (x = u.ux-1; x <= u.ux+1; x++)
- for (y = u.uy-1; y <= u.uy+1; y++)
- if (isok(x,y) && is_pool(x,y)) {
- if (Blind && !(x == u.ux && y == u.uy))
- show_glyph(x,y,cmap_to_glyph(S_stone));
- else
- newsym(x,y);
- }
- lastx = u.ux;
- lasty = u.uy;
- }
-
-
- /* ========================================================================= */
-
- /*
- * Loop through all of the monsters and update them. Called when:
- * + going blind & telepathic
- * + regaining sight & telepathic
- * + hallucinating
- * + doing a full screen redraw
- * + see invisible times out or a ring of see invisible is taken off
- * + when a potion of see invisible is quaffed or a ring of see
- * invisible is put on
- * + gaining telepathy when blind [givit() in eat.c, pleased() in pray.c]
- * + losing telepathy while blind [xkilled() in mon.c, attrcurse() in
- * sit.c]
- */
- void
- see_monsters()
- {
- register struct monst *mon;
- for (mon = fmon; mon; mon = mon->nmon) {
- newsym(mon->mx,mon->my);
- if (mon->wormno) see_wsegs(mon);
- }
- }
-
- /*
- * Block/unblock light depending on what a mimic is mimicing and if it's
- * invisible or not. Should be called only when the state of See_invisible
- * changes.
- */
- void
- set_mimic_blocking()
- {
- register struct monst *mon;
- for (mon = fmon; mon; mon = mon->nmon)
- if(mon->minvis &&
- ((mon->m_ap_type == M_AP_FURNITURE &&
- (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor))||
- (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) {
- if(See_invisible)
- block_point(mon->mx, mon->my);
- else
- unblock_point(mon->mx, mon->my);
- }
- }
-
- /*
- * Loop through all of the object *locations* and update them. Called when
- * + hallucinating.
- */
- void
- see_objects()
- {
- register struct obj *obj;
- for(obj = fobj; obj; obj = obj->nobj)
- if (vobj_at(obj->ox,obj->oy) == obj) newsym(obj->ox, obj->oy);
- }
-
- /*
- * Put the cursor on the hero. Flush all accumulated glyphs before doing it.
- */
- void
- curs_on_u()
- {
- flush_screen(1); /* Flush waiting glyphs & put cursor on hero */
- }
-
- int
- doredraw()
- {
- docrt();
- return 0;
- }
-
- void
- docrt()
- {
- register int x,y;
- register struct rm *lev;
-
- if (!u.ux) return; /* display isn't ready yet */
-
- if (u.uswallow) {
- swallowed(1);
- return;
- }
- if (Underwater && !Is_waterlevel(&u.uz)) {
- under_water(1);
- return;
- }
-
- /* shut down vision */
- vision_recalc(2);
-
- /*
- * This routine assumes that cls() does the following:
- * + fills the physical screen with the symbol for rock
- * + clears the glyph buffer
- */
- cls();
-
- /* display memory */
- for (x = 1; x < COLNO; x++) {
- lev = &levl[x][0];
- for (y = 0; y < ROWNO; y++, lev++)
- if (lev->glyph != cmap_to_glyph(S_stone))
- show_glyph(x,y,lev->glyph);
- }
-
- /* see what is to be seen */
- vision_recalc(0);
-
- /* overlay with monsters */
- see_monsters();
-
- flags.botlx = 1; /* force a redraw of the bottom line */
- }
-
-
- /* ========================================================================= */
- /* Glyph Buffering (3rd screen) ============================================ */
-
- typedef struct {
- xchar new; /* perhaps move this bit into the rm strucure. */
- int glyph;
- } gbuf_entry;
-
- static gbuf_entry gbuf[ROWNO][COLNO];
- static char gbuf_start[ROWNO];
- static char gbuf_stop[ROWNO];
-
- /*
- * Store the glyph in the 3rd screen for later flushing.
- */
- void
- show_glyph(x,y,glyph)
- xchar x,y;
- int glyph;
- {
- /*
- * Check for bad positions and glyphs.
- */
- if (x <= 0 || x >= COLNO || y < 0 || y >= ROWNO) {
- const char *text;
- int offset;
-
- /* column 0 is invalid, but it's often used as a flag, so ignore it */
- if (x == 0) return;
-
- /*
- * This assumes an ordering of the offsets. See display.h for
- * the definition.
- */
- if (glyph >= GLYPH_SWALLOW_OFF) { /* swallow border */
- text = "swallow border"; offset = glyph - GLYPH_SWALLOW_OFF;
- }else if (glyph >= GLYPH_ZAP_OFF) { /* zap beam */
- text = "zap beam"; offset = glyph - GLYPH_ZAP_OFF;
- } else if (glyph >= GLYPH_CMAP_OFF) { /* cmap */
- text = "cmap_index"; offset = glyph - GLYPH_CMAP_OFF;
- } else if (glyph >= GLYPH_TRAP_OFF) { /* trap */
- text = "trap"; offset = glyph - GLYPH_TRAP_OFF;
- } else if (glyph >= GLYPH_OBJ_OFF) { /* object */
- text = "object"; offset = glyph - GLYPH_OBJ_OFF;
- } else if (glyph >= GLYPH_BODY_OFF) { /* a corpse */
- text = "corpse"; offset = glyph - GLYPH_BODY_OFF;
- } else { /* a monster */
- text = "monster"; offset = glyph;
- }
-
- impossible("show_glyph: bad pos %d %d with glyph %d [%s %d].",
- x, y, glyph, text, offset);
- return;
- }
-
- if (glyph >= MAX_GLYPH) {
- impossible("show_glyph: bad glyph %d [max %d] at (%d,%d).",
- glyph, MAX_GLYPH, x, y);
- return;
- }
-
- if (gbuf[y][x].glyph != glyph) {
- gbuf[y][x].glyph = glyph;
- gbuf[y][x].new = 1;
- if (gbuf_start[y] > x) gbuf_start[y] = x;
- if (gbuf_stop[y] < x) gbuf_stop[y] = x;
- }
- }
-
-
- /*
- * Reset the changed glyph borders so that none of the 3rd screen has
- * changed.
- */
- #define reset_glyph_bbox() \
- { \
- int i; \
- \
- for (i = 0; i < ROWNO; i++) { \
- gbuf_start[i] = COLNO-1; \
- gbuf_stop[i] = 0; \
- } \
- }
-
-
- static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) };
- /*
- * Turn the 3rd screen into stone.
- */
- void
- clear_glyph_buffer()
- {
- register int x, y;
- register gbuf_entry *gptr;
-
- for (y = 0; y < ROWNO; y++) {
- gptr = &gbuf[y][0];
- for (x = COLNO; x; x--) {
- *gptr++ = nul_gbuf;
- }
- }
- reset_glyph_bbox();
- }
-
- /*
- * Assumes that the indicated positions are filled with S_stone glyphs.
- */
- void
- row_refresh(start,stop,y)
- int start,stop,y;
- {
- register int x;
-
- for (x = start; x <= stop; x++)
- if (gbuf[y][x].glyph != cmap_to_glyph(S_stone))
- print_glyph(WIN_MAP,x,y,gbuf[y][x].glyph);
- }
-
- void
- cls()
- {
- display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
- flags.botlx = 1; /* force update of botl window */
- clear_nhwindow(WIN_MAP); /* clear physical screen */
-
- clear_glyph_buffer(); /* this is sort of an extra effort, but OK */
- }
-
- /*
- * Synch the third screen with the display.
- */
- void
- flush_screen(cursor_on_u)
- int cursor_on_u;
- {
- /* Prevent infinite loops on errors:
- * flush_screen->print_glyph->impossible->pline->flush_screen
- */
- static boolean flushing = 0;
- register int x,y;
-
- if (flushing) return; /* if already flushing then return */
- flushing = 1;
-
- for (y = 0; y < ROWNO; y++) {
- register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]];
- for (; x <= gbuf_stop[y]; gptr++, x++)
- if (gptr->new) {
- print_glyph(WIN_MAP,x,y,gptr->glyph);
- gptr->new = 0;
- }
- }
-
- if (cursor_on_u) curs(WIN_MAP, u.ux,u.uy); /* move cursor to the hero */
- display_nhwindow(WIN_MAP, FALSE);
- reset_glyph_bbox();
- flushing = 0;
- if(flags.botl || flags.botlx) bot();
- }
-
- /* ========================================================================= */
-
- /*
- * back_to_glyph()
- *
- * Use the information in the rm structure at the given position to create
- * a glyph of a background.
- *
- * I had to add a field in the rm structure (horizontal) so that we knew
- * if open doors and secret doors were horizontal or vertical. Previously,
- * the screen symbol had the horizontal/vertical information set at
- * level generation time.
- *
- * I used the 'ladder' field (really doormask) for deciding if stairwells
- * were up or down. I didn't want to check the upstairs and dnstairs
- * variables.
- */
- int
- back_to_glyph(x,y)
- xchar x,y;
- {
- int idx;
- struct rm *ptr = &(levl[x][y]);
-
- switch (ptr->typ) {
- case SCORR:
- case STONE: idx = S_stone; break;
- case ROOM: idx = S_room; break;
- case CORR:
- idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr;
- break;
- case HWALL: idx = ptr->seen ? S_hwall : S_stone; break;
- case VWALL: idx = ptr->seen ? S_vwall : S_stone; break;
- case TLCORNER: idx = ptr->seen ? S_tlcorn : S_stone; break;
- case TRCORNER: idx = ptr->seen ? S_trcorn : S_stone; break;
- case BLCORNER: idx = ptr->seen ? S_blcorn : S_stone; break;
- case BRCORNER: idx = ptr->seen ? S_brcorn : S_stone; break;
- case CROSSWALL: idx = ptr->seen ? S_crwall : S_stone; break;
- case TUWALL: idx = ptr->seen ? S_tuwall : S_stone; break;
- case TDWALL: idx = ptr->seen ? S_tdwall : S_stone; break;
- case TLWALL: idx = ptr->seen ? S_tlwall : S_stone; break;
- case TRWALL: idx = ptr->seen ? S_trwall : S_stone; break;
- case SDOOR:
- if (ptr->seen)
- idx = (ptr->horizontal) ? S_hwall : S_vwall;
- else
- idx = S_stone;
- break;
- case DOOR:
- if (ptr->doormask) {
- if (ptr->doormask & D_BROKEN)
- idx = S_ndoor;
- else if (ptr->doormask & D_ISOPEN)
- idx = (ptr->horizontal) ? S_hodoor : S_vodoor;
- else /* else is closed */
- idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor;
- } else
- idx = S_ndoor;
- break;
- case POOL:
- case MOAT: idx = S_pool; break;
- case STAIRS:
- idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair;
- break;
- case LADDER:
- idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder;
- break;
- case FOUNTAIN: idx = S_fountain; break;
- case SINK: idx = S_sink; break;
- case ALTAR: idx = S_altar; break;
- case THRONE: idx = S_throne; break;
- case LAVAPOOL: idx = S_lava; break;
- case ICE: idx = S_ice; break;
- case AIR: idx = S_air; break;
- case CLOUD: idx = S_cloud; break;
- case WATER: idx = S_water; break;
- case DBWALL:
- idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge;
- break;
- case DRAWBRIDGE_UP:
- switch(ptr->drawbridgemask & DB_UNDER) {
- case DB_MOAT: idx = S_pool; break;
- case DB_LAVA: idx = S_lava; break;
- case DB_ICE: idx = S_ice; break;
- case DB_FLOOR: idx = S_room; break;
- default:
- impossible("Strange db-under: %d",
- ptr->drawbridgemask & DB_UNDER);
- idx = S_room; /* something is better than nothing */
- break;
- }
- break;
- case DRAWBRIDGE_DOWN:
- idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge;
- break;
- default:
- impossible("back_to_glyph: unknown level type [ = %d ]",ptr->typ);
- idx = S_room;
- break;
- }
-
- return cmap_to_glyph(idx);
- }
-
-
- /*
- * swallow_to_glyph()
- *
- * Convert a monster number and a swallow location into the correct glyph.
- * If you don't want a patchwork monster while hallucinating, decide on
- * a random monster in swallowed() and don't use what_mon() here.
- */
- static int
- swallow_to_glyph(mnum, loc)
- int mnum;
- int loc;
- {
- if (loc < S_sw_tl || S_sw_br < loc) {
- impossible("swallow_to_glyph: bad swallow location");
- loc = S_sw_br;
- }
- return ((int) (what_mon(mnum)<<3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF;
- }
-
-
-
- /*
- * zapdir_to_glyph()
- *
- * Change the given zap direction and beam type into a glyph. Each beam
- * type has four glyphs, one for each of the symbols below. The order of
- * the zap symbols [0-3] as defined in rm.h are:
- *
- * | S_vbeam ( 0, 1) or ( 0,-1)
- * - S_hbeam ( 1, 0) or (-1, 0)
- * \ S_lslant ( 1, 1) or (-1,-1)
- * / S_rslant (-1, 1) or ( 1,-1)
- */
- int
- zapdir_to_glyph(dx, dy, beam_type)
- register int dx, dy;
- int beam_type;
- {
- if (beam_type >= NUM_ZAP) {
- impossible("zapdir_to_glyph: illegal beam type");
- beam_type = 0;
- }
- dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0;
-
- return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF;
- }
-
-
- /*
- * Utility routine for dowhatis() used to find out the glyph displayed at
- * the location. This isn't necessarily the same as the glyph in the levl
- * structure, so we must check the "third screen".
- */
- int
- glyph_at(x, y)
- xchar x,y;
- {
- if(x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
- return cmap_to_glyph(S_room); /* XXX */
- return gbuf[y][x].glyph;
- }
-
- /*display.c*/
-