home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!news.tek.com!master!saab!billr
- From: billr@saab.CNA.TEK.COM (Bill Randle)
- Newsgroups: comp.sources.games
- Subject: v16i093: nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part85/108
- Message-ID: <4456@master.CNA.TEK.COM>
- Date: 5 Feb 93 19:21:52 GMT
- Sender: news@master.CNA.TEK.COM
- Lines: 1787
- Approved: billr@saab.CNA.TEK.COM
- Xref: uunet comp.sources.games:1644
-
- Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
- Posting-number: Volume 16, Issue 93
- Archive-name: nethack31/Part85
- Supersedes: nethack3p9: Volume 10, Issue 46-102
- Environment: Amiga, Atari, Mac, MS-DOS, OS2, Unix, VMS, X11
-
-
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 85 (of 108)."
- # Contents: include/vision.h src/end.c sys/msdos/maintovl.doc
- # win/X11/winmesg.c
- # Wrapped by billr@saab on Wed Jan 27 16:09:21 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'include/vision.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'include/vision.h'\"
- else
- echo shar: Extracting \"'include/vision.h'\" \(1597 characters\)
- sed "s/^X//" >'include/vision.h' <<'END_OF_FILE'
- X/* SCCS Id: @(#)vision.h 3.1 92/11/14 */
- X/* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */
- X/* NetHack may be freely redistributed. See license for details. */
- X
- X#ifndef VISION_H
- X#define VISION_H
- X
- X#if 0 /* (moved to decl.h) */
- Xextern boolean vision_full_recalc; /* TRUE if need vision recalc */
- Xextern char **viz_array; /* could see/in sight row pointers */
- Xextern char *viz_rmin; /* min could see indices */
- Xextern char *viz_rmax; /* max could see indices */
- X#endif
- X#define COULD_SEE 0x1
- X#define IN_SIGHT 0x2
- X
- X/*
- X * cansee() - Returns true if the hero can see the location.
- X *
- X * couldsee() - Returns true if the hero has a clear line of sight to
- X * the location.
- X */
- X#define cansee(x,y) (viz_array[y][x] & IN_SIGHT)
- X#define couldsee(x,y) (viz_array[y][x] & COULD_SEE)
- X
- X/*
- X * The following assume the monster is not blind.
- X *
- X * m_cansee() - Returns true if the monster can see the given location.
- X *
- X * m_canseeu() - Returns true if the monster could see the hero. Assumes
- X * that if the hero has a clear line of sight to the monster's
- X * location and the hero is visible, then monster can see the
- X * hero.
- X */
- X#define m_cansee(mtmp,x2,y2) clear_path((mtmp)->mx,(mtmp)->my,(x2),(y2))
- X
- X#define m_canseeu(m) ((!Invis || perceives((m)->data)) && !Underwater ? \
- X couldsee((m)->mx,(m)->my) : 0)
- X
- X/*
- X * Circle information
- X */
- X#define MAX_RADIUS 15 /* this is in points from the source */
- X
- X/* Use this macro to get a list of distances of the edges (see vision.c). */
- X#define circle_ptr(z) (&circle_data[circle_start[z]])
- X
- X#endif /* VISION_H */
- END_OF_FILE
- if test 1597 -ne `wc -c <'include/vision.h'`; then
- echo shar: \"'include/vision.h'\" unpacked with wrong size!
- fi
- # end of 'include/vision.h'
- fi
- if test -f 'src/end.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/end.c'\"
- else
- echo shar: Extracting \"'src/end.c'\" \(17434 characters\)
- sed "s/^X//" >'src/end.c' <<'END_OF_FILE'
- X/* SCCS Id: @(#)end.c 3.1 93/01/15 */
- X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
- X/* NetHack may be freely redistributed. See license for details. */
- X
- X#define NEED_VARARGS /* comment line for pre-compiled headers */
- X
- X#include "hack.h"
- X#include "eshk.h"
- X#ifndef NO_SIGNAL
- X#include <signal.h>
- X#endif
- X
- XSTATIC_PTR int NDECL(done_intr);
- Xstatic void FDECL(disclose,(int,BOOLEAN_P));
- Xstatic struct obj *FDECL(get_valuables, (struct obj *));
- Xstatic void FDECL(savelife, (int));
- X
- X/*
- X * The order of these needs to match the macros in hack.h.
- X */
- Xstatic const char NEARDATA *deaths[] = { /* the array of death */
- X "died", "choked", "poisoned", "starvation", "drowning",
- X "burning", "crushed", "turned to stone", "genocided",
- X "panic", "trickery",
- X "quit", "escaped", "ascended"
- X};
- X
- Xstatic const char NEARDATA *ends[] = { /* "when you..." */
- X "died", "choked", "were poisoned", "starved", "drowned",
- X "burned", "were crushed", "turned to stone", "were genocided",
- X "panicked", "were tricked",
- X "quit", "escaped", "ascended"
- X};
- X
- Xint
- Xdone1()
- X{
- X#ifndef NO_SIGNAL
- X (void) signal(SIGINT,SIG_IGN);
- X#endif
- X if(flags.ignintr) {
- X#ifndef NO_SIGNAL
- X (void) signal(SIGINT, (SIG_RET_TYPE) done1);
- X#endif
- X clear_nhwindow(WIN_MESSAGE);
- X curs_on_u();
- X wait_synch();
- X if(multi > 0) nomul(0);
- X return 0;
- X }
- X return done2();
- X}
- X
- Xint
- Xdone2()
- X{
- X if(yn("Really quit?") == 'n') {
- X#ifndef NO_SIGNAL
- X (void) signal(SIGINT, (SIG_RET_TYPE) done1);
- X#endif
- X clear_nhwindow(WIN_MESSAGE);
- X curs_on_u();
- X wait_synch();
- X if(multi > 0) nomul(0);
- X if(multi == 0) {
- X u.uinvulnerable = FALSE; /* avoid ctrl-C bug -dlc */
- X u.usleep = 0;
- X }
- X return 0;
- X }
- X#if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
- X if(wizard) {
- X# ifdef VMS
- X const char *tmp = "Enter debugger?";
- X# else
- X# ifdef LATTICE
- X const char *tmp = "Create SnapShot?";
- X# else
- X const char *tmp = "Dump core?";
- X# endif
- X# endif
- X if(yn(tmp) == 'y') {
- X (void) signal(SIGINT, (SIG_RET_TYPE) done1);
- X exit_nhwindows(NULL);
- X#ifdef AMIGA
- X Abort(0);
- X#else
- X# ifdef SYSV
- X (void)
- X# endif
- X abort();
- X#endif
- X }
- X }
- X#endif
- X#ifndef LINT
- X done(QUIT);
- X#endif
- X return 0;
- X}
- X
- XSTATIC_PTR
- Xint
- Xdone_intr(){
- X done_stopprint++;
- X#ifndef NO_SIGNAL
- X (void) signal(SIGINT, SIG_IGN);
- X# if defined(UNIX) || defined(VMS)
- X (void) signal(SIGQUIT, SIG_IGN);
- X# endif
- X#endif /* NO_SIGNAL /* */
- X return 0;
- X}
- X
- X#if defined(UNIX) || defined(VMS)
- Xstatic
- Xint
- Xdone_hangup(){
- X done_hup++;
- X (void)signal(SIGHUP, SIG_IGN);
- X (void)done_intr();
- X return 0;
- X}
- X#endif
- X
- Xvoid
- Xdone_in_by(mtmp)
- Xregister struct monst *mtmp;
- X{
- X char buf[BUFSZ];
- X
- X You("die...");
- X buf[0] = '\0';
- X if (type_is_pname(mtmp->data) || (mtmp->data->geno & G_UNIQ)) {
- X if (!(type_is_pname(mtmp->data) && (mtmp->data->geno & G_UNIQ)))
- X Strcat(buf, "the ");
- X killer_format = KILLED_BY;
- X }
- X if (mtmp->minvis)
- X Strcat(buf, "invisible ");
- X if (Hallucination)
- X Strcat(buf, "hallucinogen-distorted ");
- X
- X if(mtmp->data == &mons[PM_GHOST]) {
- X register char *gn = (char *) mtmp->mextra;
- X if (!Hallucination && !mtmp->minvis && *gn) {
- X Strcat(buf, "the ");
- X killer_format = KILLED_BY;
- X }
- X Sprintf(eos(buf), (*gn ? "ghost of %s" : "ghost%s"), gn);
- X } else if(mtmp->isshk) {
- X Sprintf(eos(buf), "%s %s, the shopkeeper",
- X (mtmp->female ? "Ms." : "Mr."), shkname(mtmp));
- X killer_format = KILLED_BY;
- X } else if (mtmp->ispriest || mtmp->isminion) {
- X killer = priestname(mtmp);
- X if (!strncmp(killer, "the ", 4)) Strcat(buf, killer+4);
- X else Strcat(buf, killer);
- X } else Strcat(buf, mtmp->data->mname);
- X if (mtmp->mnamelth) Sprintf(eos(buf), " called %s", NAME(mtmp));
- X killer = buf;
- X if (mtmp->data->mlet == S_WRAITH)
- X u.ugrave_arise = PM_WRAITH;
- X else if (mtmp->data->mlet == S_MUMMY)
- X u.ugrave_arise = (pl_character[0]=='E') ?
- X PM_ELF_MUMMY : PM_HUMAN_MUMMY;
- X else if (mtmp->data->mlet == S_VAMPIRE)
- X u.ugrave_arise = PM_VAMPIRE;
- X if (u.ugrave_arise > -1 && (mons[u.ugrave_arise].geno & G_GENOD))
- X u.ugrave_arise = -1;
- X if (mtmp->data->mlet == S_COCKATRICE)
- X done(STONING);
- X else
- X done(DIED);
- X return;
- X}
- X
- X/*VARARGS1*/
- Xboolean panicking;
- Xextern boolean hu; /* from save.c */
- X
- Xvoid
- Xpanic VA_DECL(const char *, str)
- X VA_START(str);
- X VA_INIT(str, char *);
- X
- X if(panicking++)
- X#ifdef AMIGA
- X Abort(0);
- X#else
- X# ifdef SYSV
- X (void)
- X# endif
- X abort(); /* avoid loops - this should never happen*/
- X#endif
- X
- X if (flags.window_inited) exit_nhwindows(NULL);
- X flags.window_inited = 0; /* they're gone; force raw_print()ing */
- X
- X raw_print(" Suddenly, the dungeon collapses.");
- X#if defined(WIZARD) && !defined(MICRO)
- X if(!wizard) {
- X raw_printf("Report error to %s and it may be possible to rebuild.",
- X# ifdef WIZARD_NAME /*(KR1ED)*/
- X WIZARD_NAME);
- X# else
- X WIZARD);
- X# endif
- X }
- X set_error_savefile();
- X hu = FALSE;
- X (void) dosave0();
- X#endif
- X {
- X char buf[BUFSZ];
- X Vsprintf(buf,str,VA_ARGS);
- X raw_print(buf);
- X }
- X#if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
- X if (wizard)
- X# ifdef AMIGA
- X Abort(0);
- X# else
- X# ifdef SYSV
- X (void)
- X# endif
- X abort(); /* generate core dump */
- X# endif
- X#endif
- X VA_END();
- X done(PANICKED);
- X}
- X
- Xstatic void
- Xdisclose(how,taken)
- Xint how;
- Xboolean taken;
- X{
- X char c;
- X char qbuf[QBUFSZ];
- X
- X if(invent) {
- X if(taken)
- X Sprintf(qbuf,"Do you want to see what you had when you %s?",
- X (how == QUIT) ? "quit" : "died");
- X else
- X Strcpy(qbuf,"Do you want your possessions identified?");
- X if ((c = yn_function(qbuf, ynqchars, 'y')) == 'y') {
- X /* New dump format by maartenj@cs.vu.nl */
- X struct obj *obj;
- X
- X for(obj = invent; obj && !done_stopprint; obj = obj->nobj) {
- X makeknown(obj->otyp);
- X obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
- X }
- X (void) display_inventory(NULL, FALSE);
- X container_contents(invent, TRUE, TRUE);
- X }
- X if (c == 'q') done_stopprint++;
- X if (taken) {
- X /* paybill has already given the inventory locations
- X * in the shop and put it on the main object list
- X */
- X struct obj *obj;
- X
- X for(obj = invent; obj; obj = obj->nobj) {
- X obj->owornmask = 0;
- X if(rn2(5)) curse(obj);
- X }
- X invent = (struct obj *) 0;
- X }
- X }
- X
- X if (!done_stopprint) {
- X c = yn_function("Do you want to see your intrinsics?",ynqchars,'y');
- X if (c == 'y') enlightenment(TRUE); /* final */
- X if (c == 'q') done_stopprint++;
- X }
- X
- X}
- X
- X/* try to get the player back in a viable state after being killed */
- Xstatic void
- Xsavelife(how)
- Xint how;
- X{
- X u.uswldtim = 0;
- X u.uhp = u.uhpmax;
- X if (u.uhunger < 500) {
- X u.uhunger = 500;
- X newuhs(FALSE);
- X }
- X if (how == CHOKING) init_uhunger();
- X nomovemsg = "You survived that attempt on your life.";
- X flags.move = 0;
- X if(multi > 0) multi = 0; else multi = -1;
- X if(u.utrap && u.utraptype == TT_LAVA) u.utrap = 0;
- X flags.botl = 1;
- X u.ugrave_arise = -1;
- X curs_on_u();
- X}
- X
- X/*
- X * Get valuables from the given list. NOTE: The list is destroyed as it is
- X * processed, so don't expect to use it again!
- X */
- Xstatic struct obj *
- Xget_valuables(list)
- X struct obj *list;
- X{
- X struct obj *obj, *next_obj, *c_vals, *temp;
- X struct obj *valuables = (struct obj *)0;
- X
- X for (obj = list; obj; obj = next_obj) {
- X if (Is_container(obj) && obj->cobj) {
- X c_vals = get_valuables(obj->cobj);
- X
- X if (c_vals) {
- X /* find the end of the list */
- X for (temp = c_vals; temp->nobj; temp = temp->nobj) ;
- X
- X temp->nobj = valuables;
- X valuables = c_vals;
- X }
- X }
- X
- X next_obj = obj->nobj;
- X
- X if ((obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE)
- X || obj->oclass == AMULET_CLASS) {
- X obj->nobj = valuables;
- X valuables = obj;
- X }
- X }
- X return valuables;
- X}
- X
- X/* Be careful not to call panic from here! */
- Xvoid
- Xdone(how)
- Xint how;
- X{
- X struct permonst *upmon;
- X boolean taken;
- X char kilbuf[BUFSZ], pbuf[BUFSZ];
- X winid endwin = WIN_ERR;
- X boolean have_windows = flags.window_inited;
- X
- X /* kilbuf: used to copy killer in case it comes from something like
- X * xname(), which would otherwise get overwritten when we call
- X * xname() when listing possessions
- X * pbuf: holds Sprintf'd output for raw_print and putstr
- X */
- X if (how == ASCENDED)
- X killer_format = NO_KILLER_PREFIX;
- X /* Avoid killed by "a" burning or "a" starvation */
- X if (!killer && (how == STARVING || how == BURNING))
- X killer_format = KILLED_BY;
- X Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer));
- X killer = kilbuf;
- X#ifdef WIZARD
- X if (wizard && how == TRICKED) {
- X You("are a very tricky wizard, it seems.");
- X return;
- X }
- X#endif
- X if (Lifesaved && how <= GENOCIDED) {
- X pline("But wait...");
- X makeknown(AMULET_OF_LIFE_SAVING);
- X Your("medallion %s!",
- X !Blind ? "begins to glow" : "feels warm");
- X if (how == CHOKING) You("vomit ...");
- X You("feel much better!");
- X pline("The medallion crumbles to dust!");
- X useup(uamul);
- X
- X (void) adjattrib(A_CON, -1, TRUE);
- X if(u.uhpmax <= 0) u.uhpmax = 10; /* arbitrary */
- X savelife(how);
- X if (how == GENOCIDED)
- X pline("Unfortunately you are still genocided...");
- X else {
- X killer = 0;
- X return;
- X }
- X }
- X#if defined(WIZARD) || defined(EXPLORE_MODE)
- X if ((wizard || discover) && how <= GENOCIDED) {
- X if(yn("Die?") == 'y') goto die;
- X pline("OK, so you don't %s.",
- X (how == CHOKING) ? "choke" : "die");
- X if(u.uhpmax <= 0) u.uhpmax = u.ulevel * 8; /* arbitrary */
- X savelife(how);
- X killer = 0;
- X return;
- X }
- X#endif /* WIZARD || EXPLORE_MODE */
- X /* Sometimes you die on the first move. Life's not fair.
- X * On those rare occasions you get hosed immediately, go out
- X * smiling... :-) -3.
- X */
- X if (moves <= 1 && how < QUIT)
- X /* You die... --More-- */
- X pline("Do not pass go. Do not collect 200 zorkmids.");
- X
- Xdie:
- X if (have_windows) wait_synch(); /* flush screen output */
- X#ifndef NO_SIGNAL
- X (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
- X# if defined(UNIX) || defined(VMS)
- X (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
- X (void) signal(SIGHUP, (SIG_RET_TYPE) done_hangup);
- X# endif
- X#endif /* NO_SIGNAL /* */
- X#ifdef POLYSELF
- X if (u.mtimedone)
- X upmon = uasmon;
- X else
- X#endif
- X upmon = player_mon();
- X
- X if (u.ugrave_arise < 0) { /* >= 0 means create no corpse */
- X if (how == STONING)
- X u.ugrave_arise = -2;
- X
- X/*
- X * If you're burned to a crisp, why leave a corpse?
- X */
- X else if (how != BURNING && how != PANICKED)
- X (void) mk_named_object(CORPSE, upmon, u.ux, u.uy, plname,
- X (int)strlen(plname));
- X }
- X
- X if (how == QUIT) {
- X killer_format = NO_KILLER_PREFIX;
- X if (u.uhp < 1) {
- X how = DIED;
- X/* note that killer is pointing at kilbuf */
- X Strcpy(kilbuf, "quit while already on Charon's boat");
- X }
- X }
- X if (how == ESCAPED || how == PANICKED)
- X killer_format = NO_KILLER_PREFIX;
- X
- X /* paybill() must be called unconditionally, or strange things will
- X * happen to bones levels */
- X taken = paybill(how != QUIT);
- X paygd();
- X clearlocks();
- X#ifdef AMIGA
- X clear_icon();
- X#endif
- X if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE);
- X
- X if (flags.end_disclose && how != PANICKED) disclose(how,taken);
- X
- X if (how < GENOCIDED) {
- X#ifdef WIZARD
- X if (!wizard || yn("Save bones?") == 'y')
- X#endif
- X savebones();
- X }
- X
- X /* clean up unneeded windows */
- X if (have_windows) {
- X destroy_nhwindow(WIN_MAP);
- X destroy_nhwindow(WIN_STATUS);
- X destroy_nhwindow(WIN_MESSAGE);
- X
- X if(!done_stopprint || flags.tombstone)
- X endwin = create_nhwindow(NHW_TEXT);
- X
- X if(how < GENOCIDED && flags.tombstone) outrip(how, endwin);
- X } else
- X done_stopprint = 1; /* just avoid any more output */
- X
- X/* changing kilbuf really changes killer. we do it this way because
- X killer is declared a (const char *)
- X*/
- X if (u.uhave.amulet) Strcat(kilbuf, " (with the Amulet)");
- X if (!done_stopprint) {
- X Sprintf(pbuf, "%s %s the %s...",
- X (pl_character[0]=='S') ? "Sayonara" : "Goodbye", plname,
- X how != ASCENDED ? (const char *) pl_character :
- X (const char *) (flags.female ? "Demigoddess" : "Demigod"));
- X putstr(endwin, 0, pbuf);
- X putstr(endwin, 0, "");
- X }
- X { long tmp;
- X int deepest = deepest_lev_reached(FALSE);
- X
- X u.ugold += hidden_gold(); /* accumulate gold from containers */
- X tmp = u.ugold - u.ugold0;
- X if (tmp < 0L)
- X tmp = 0L;
- X if (how < PANICKED)
- X tmp -= tmp / 10L;
- X u.urexp += tmp;
- X u.urexp += 50L * (long)(deepest - 1);
- X if (deepest > 20)
- X u.urexp += 1000L * (long)((deepest > 30) ? 10 : deepest - 20);
- X if (how == ASCENDED) u.urexp *= 2L;
- X }
- X if (how == ESCAPED || how == ASCENDED) {
- X register struct monst *mtmp;
- X register struct obj *otmp;
- X struct obj *jewels;
- X long i;
- X register long worthlessct = 0;
- X
- X /*
- X * Put items that count into the jewels chain. Rewriting
- X * the invent chain and all the container chains (within
- X * invent) here is safe. They will never be used again.
- X */
- X jewels = get_valuables(invent);
- X
- X /* add points for jewels */
- X for(otmp = jewels; otmp; otmp = otmp->nobj) {
- X if(otmp->oclass == GEM_CLASS)
- X u.urexp += otmp->quan *
- X objects[otmp->otyp].oc_cost;
- X else /* amulet */
- X u.urexp += objects[otmp->otyp].oc_cost;
- X }
- X
- X keepdogs();
- X viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
- X mtmp = mydogs;
- X if(!done_stopprint) Strcpy(pbuf, "You");
- X if(mtmp) {
- X while(mtmp) {
- X if(!done_stopprint) {
- X Strcat(pbuf, " and ");
- X Strcat(pbuf, mon_nam(mtmp));
- X }
- X if(mtmp->mtame)
- X u.urexp += mtmp->mhp;
- X mtmp = mtmp->nmon;
- X }
- X if(!done_stopprint)
- X putstr(endwin, 0, pbuf);
- X pbuf[0] = 0;
- X } else {
- X if(!done_stopprint)
- X Strcat(pbuf, " ");
- X }
- X if(!done_stopprint) {
- X Sprintf(eos(pbuf),
- X "%s with %ld point%s,",
- X how==ASCENDED ? "went to your reward"
- X : "escaped from the dungeon",
- X u.urexp, plur(u.urexp));
- X putstr(endwin, 0, pbuf);
- X }
- X
- X /* print jewels chain here */
- X for(otmp = jewels; otmp; otmp = otmp->nobj) {
- X makeknown(otmp->otyp);
- X if(otmp->oclass == GEM_CLASS &&
- X otmp->otyp < LUCKSTONE) {
- X i = otmp->quan *
- X objects[otmp->otyp].oc_cost;
- X if(i == 0) {
- X worthlessct += otmp->quan;
- X continue;
- X }
- X } else { /* amulet */
- X otmp->known = 1;
- X i = objects[otmp->otyp].oc_cost;
- X }
- X if(!done_stopprint) {
- X Sprintf(pbuf, " %s (worth %ld zorkmids),",
- X doname(otmp), i);
- X putstr(endwin, 0, pbuf);
- X }
- X }
- X if(worthlessct && !done_stopprint) {
- X Sprintf(pbuf,
- X " %ld worthless piece%s of colored glass,",
- X worthlessct, plur(worthlessct));
- X putstr(endwin, 0, pbuf);
- X }
- X } else if (!done_stopprint) {
- X Strcpy(pbuf, "You ");
- X Strcat(pbuf, ends[how]);
- X if (how != ASCENDED) {
- X Strcat(pbuf, " in ");
- X if (Is_astralevel(&u.uz))
- X Strcat(pbuf, "The Astral Plane");
- X else Strcat(pbuf, dungeons[u.uz.dnum].dname);
- X Strcat(pbuf, " ");
- X if (!In_endgame(&u.uz)
- X#ifdef MULDGN
- X && !Is_knox(&u.uz)
- X#endif
- X )
- X Sprintf(eos(pbuf), "on dungeon level %d ", (
- X#ifdef MULDGN
- X In_quest(&u.uz) ?
- X dunlev(&u.uz) :
- X#endif
- X depth(&u.uz)));
- X }
- X Sprintf(eos(pbuf),
- X "with %ld point%s,", u.urexp, plur(u.urexp));
- X putstr(endwin, 0, pbuf);
- X }
- X if (!done_stopprint) {
- X Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.",
- X u.ugold, plur(u.ugold), moves, plur(moves));
- X putstr(endwin, 0, pbuf);
- X }
- X if (!done_stopprint) {
- X Sprintf(pbuf,
- X "You were level %u with a maximum of %d hit point%s when you %s.",
- X u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
- X putstr(endwin, 0, pbuf);
- X putstr(endwin, 0, "");
- X }
- X#if (defined(WIZARD) || defined(EXPLORE_MODE))
- X# ifndef LOGFILE
- X if (wizard || discover) {
- X if (!done_stopprint) {
- X putstr(endwin, 0, "");
- X Sprintf(pbuf, "Since you were in %s mode, the score list \
- Xwill not be checked.", wizard ? "wizard" : "discover");
- X putstr(endwin, 0, pbuf);
- X putstr(endwin, 0, "");
- X display_nhwindow(endwin, TRUE);
- X }
- X if (have_windows)
- X exit_nhwindows(NULL);
- X } else
- X# endif
- X#endif
- X {
- X if (!done_stopprint)
- X display_nhwindow(endwin, TRUE);
- X if (have_windows)
- X exit_nhwindows(NULL);
- X/* "So when I die, the first thing I will see in Heaven is a score list?" */
- X topten(how);
- X }
- X if(done_stopprint) { raw_print(""); raw_print(""); }
- X terminate(0);
- X}
- X
- X
- X#ifdef NOSAVEONHANGUP
- Xint
- Xhangup()
- X{
- X (void) signal(SIGINT, SIG_IGN);
- X clearlocks();
- X# ifndef VMS
- X terminate(1);
- X# endif
- X}
- X#endif
- X
- X
- Xvoid
- Xcontainer_contents(list, identified, all_containers)
- X struct obj *list;
- X boolean identified, all_containers;
- X{
- X register struct obj *box, *obj;
- X char buf[BUFSZ];
- X
- X for (box = list; box; box = box->nobj) {
- X if (Is_container(box) && box->otyp != BAG_OF_TRICKS) {
- X if (box->cobj) {
- X winid tmpwin = create_nhwindow(NHW_MENU);
- X Sprintf(buf, "Contents of the %s:", xname(box));
- X putstr(tmpwin, 0, buf); putstr(tmpwin, 0, "");
- X for (obj = box->cobj; obj; obj = obj->nobj) {
- X if (identified) {
- X makeknown(obj->otyp);
- X obj->known = obj->bknown = obj->dknown = 1;
- X }
- X putstr(tmpwin, 0, doname(obj));
- X }
- X display_nhwindow(tmpwin, TRUE);
- X destroy_nhwindow(tmpwin);
- X if (all_containers)
- X container_contents(box->cobj, identified, TRUE);
- X } else {
- X pline("%s is empty.", The(xname(box)));
- X display_nhwindow(WIN_MESSAGE, FALSE);
- X }
- X }
- X if (!all_containers)
- X break;
- X }
- X}
- X
- Xvoid
- Xterminate(status)
- Xint status;
- X{
- X#ifdef MAC
- X if (!hu) {
- X int idx;
- X for (idx = theWindows[BASE_WINDOW].windowTextLen; --idx >= 0; )
- X /* If there is something to show... */
- X if (((unsigned char *)*theWindows[BASE_WINDOW].windowText)[idx] > ' ') {
- X display_nhwindow(BASE_WINDOW, TRUE);
- X break;
- X }
- X }
- X#endif
- X exit(status);
- X}
- X
- X/*end.c*/
- END_OF_FILE
- if test 17434 -ne `wc -c <'src/end.c'`; then
- echo shar: \"'src/end.c'\" unpacked with wrong size!
- fi
- # end of 'src/end.c'
- fi
- if test -f 'sys/msdos/maintovl.doc' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sys/msdos/maintovl.doc'\"
- else
- echo shar: Extracting \"'sys/msdos/maintovl.doc'\" \(17990 characters\)
- sed "s/^X//" >'sys/msdos/maintovl.doc' <<'END_OF_FILE'
- X SCCS Id: @(#)maintovl.doc 3.1 92/11/23
- X Copyright (c) NetHack PC Development Team 1990, 1991, 1992, 1993.
- X NetHack may be freely redistributed. See license for details.
- X ===========================
- X Maintaining PC NetHack
- X ===========================
- X Last revision: 1992november23
- X
- XThe installation of the system of overlay management that currently
- Xbrings full-featured NetHack to the IBM PC and compatibles has
- Xintroduced a number of arcanities into the source code of the
- Xprogramme, and unfortunately running afoul of these intricacies can
- Xresult (as we ourselves have discovered) in the most bizarre and
- Xstrangely inexplicable dysfunctional manifestations, aka sick bugs.
- X
- XThis document is required reading for anyone making substantive
- Xchanges to NetHack for the PC or embarking upon a revision of its
- Xoverlay structure.
- X
- X
- X1. The overlay manager
- X----------------------
- XNetHack is by now a fairly large programme (in excess of 800
- Xkilobytes), and in order to compile it for the PC (which typically
- Xhas little more than 500k of available memory) it was necessary to
- Xrely on the technique of _overlaying_, whereby not all the
- Xprogramme is resident in memory at the same time, segments of the
- Xprogramme being loaded and discarded as they are needed. Unlike
- Xtraditional candidates for the overlaying strategy, however, NetHack
- Xdoes not exhibit strongly phased behaviour; although much of the code
- Xis not being used at any one moment, there is comparatively little
- Xcode that can confidently be said not to be related to or potentially
- Xnecessary for the immediate progress of the game.
- X Furthermore we wished to develop an overlaying strategy that
- Xdid _not_ involve intimate knowledge of the operation of the
- Xprogramme (since NetHack is an international team effort, and few
- Xpeople have a good feeling for the totality of the code structure),
- Xand which would not require substantive changes to the source code,
- Ximpacting on its maintainability and portability.
- X It turned out to be impossible to satisfy these goals with
- Xtools that are widely available at the time of writing, and so we
- Xundertook to write our own overlay manager (compatible with
- XMicrosoft's, but more in concert with NetHack's particular needs).
- XThe result is called ovlmgr.asm and is documented in the file
- Xovlmgr.doc. You would probably be well advised to read at least the
- Xless technical parts of that file now.
- X
- X
- X2. The trampoli mechanism
- X-------------------------
- XOne of the difficulties with using overlays for C (particularly
- XMicrosoft C) is that while common C programming practise places heavy
- Xreliance on function pointers, Microsoft's overlay linker is unable
- Xto resolve calls through pointers to functions that are in remote
- Xoverlays. Nor, unfortunately, does it choose to report such failures;
- Xrather, it generates calls into (what often turns out to be in the
- Xcase of our nonstandard overlay manager) the deepest of space. This
- Xcan result in truly strange behaviour on the part of your programme -
- Xincluding bugs that come and go in as close to a random pattern as
- Xyou are ever likely to see.
- X Other than the creative use of pattern-matching utilities
- Xsuch as grep to locate the offending calls, there is unfortunately no
- Xadvice we can offer in tracking down these bugs. Once they have been
- Xisolated, however, they can be remedied straightforwardly.
- X
- XIn order for the linker not to screw up on a pointered function call
- Xit is (to simplify an actually rather complicated situation)
- Xnecessary that the function called be located in the ROOT "overlay",
- Xand thus not be subject to swapping. Rather than linking the full
- Xtext of every pointered function into the root, however, it suffices
- Xto place a "trampoline" function there which performs a direct call
- Xto the "real" function that does the work, in whatever overlay it
- Xmight naturally reside in. Due to a not-quite-accident of the
- Xbehaviour of the C preprocessor (it was originally intended to make
- Xpossible functions whose address can be taken but which expand inline
- Xas macros where possible, a not unrelated function), it turns out to
- Xbe possible to arrange for this without major change to the C source
- Xcode - and without serious impact on the performance of "regular"
- Xcalls to the same functions.
- X
- XThe C preprocessor's expansion of a macro with parameters is triggered
- Xby an encounter with the macro name immediately followed by an open
- Xparenthesis. If the name is found, but it is not followed by a
- Xparenthesis, the macro is not matched and no expansion takes place.
- XAt the same time it may be noted that (unless someone has been oddly
- Xstrange and enclosed a function name in quite unneeded parentheses!),
- Xa function name is typically followed by an open parenthesis if, and
- Xonly if, it is being declared, defined or invoked; if its address is
- Xbeing taken it will necessarily be followed by some other token.
- XFurthermore it will be observed that (except in the unfortunate case
- Xof the ill-conceived new-style ANSI declaration of a function that
- Xtakes no parameters) the number of parameters to a call of the
- Xfunction (assuming that this number is fixed; if not, I grant, we have
- Xa problem) is the same in all these contexts. This implies that if all
- Xthe modules of a programme are uniformly processed in the context of a
- Xmacro definition such as
- X
- X #define zook(a,b) plenk(a,b)
- X
- Xand assuming that all functions named zook() take exactly two
- Xarguments, then the resulting programme will be completely identical
- Xto the original (without this definition) except that the link
- Xmap will report the existence of the function plenk() in place of
- Xzook() -- UNLESS there was a place in the programme where the address
- Xof zook was taken. In that case, the linker would report an
- Xunresolved external reference for zook.
- X That unresolved reference is, of course, precisely what we
- Xneed; if in another source file (one that did not see the macro
- Xdefinition) we placed the function definition
- X
- X some_t zook(this_t a, that_t b)
- X { extern some_t plenk(this_t, that_t);
- X return plenk(a, b);
- X }
- X
- Xthis would both satisfy the unresolved reference and restore the
- Xoriginal semantics of the programme (even including pointer
- Xcomparison!) -- while providing us with precisely the kind of
- X"trampoline" module that we need to circumvent the problem with the
- Xlinker.
- X This is the basis of the approach we have taken in PC
- XNetHack; rather than using the somewhat idiosyncratic identifier
- X"plenk", however, we have systematically employed (in the files
- Xtrampoli.h and trampoli.c) identifiers generated by appending
- Xunderscores to the ends of the names of the functions we have needed
- Xto so indirect(1).
- X
- XThere are a few small complications. The first is ensuring that both
- Xthe versions of the trampoli'd function (foo() and foo_()) are
- Xsimilarly typed by the appropriate extern declarations (which
- Xthemselves must be written); this can be accomplished by placing all
- Xof these declarations in a header file that is processed _twice_,
- Xonce before and once after the inclusion of the file containing the
- Xtrampoli macro definitions, thereby ensuring that both variants of
- Xthe name have been seen in connection with the appropriate types. The
- Xsecond is that some care must be exercised not to employ other macros
- Xthat interfere with the normal recognition of function syntax: it is
- Xthe presence of the open parenthesis after the name of the function
- Xthat triggers name substitution, and not the fact that the function
- Xis called; and so (particularly in the case of declarations) it is
- Xnecessary that if a macro is used to supply the _arguments_ of a
- Xtrampoli'd function, it must also supply the name (this necessity in
- Xfact triggered a change in the style of the macros that provide
- Xdialect-independent function declaration in NetHack; the new style
- Xwould have you write FDECL(functionName, (argTypes...)).
- X Finally, there is the case of functions declared to take no
- Xarguments whatsoever; in Standard C this is notated:
- X
- X some_t aFunction(void);
- X
- Xfor no theoretically well-motivated reason I can discern. Such a
- Xdeclaration will _not_ match a macro definition such as
- X
- X #define aFunction() aFunction_()
- X
- X-- in fact the compiler will detect an error when processing that
- Xdeclaration in the scope of this macro. The only solution is to
- Xeschew the use of this strange syntax and unfrabjously forgo the
- Xconcomitant security of well- and thoroughly- checked typage. To
- Xwhich end we have provided an ecchy macro, NDECL(functionName), which
- Xuses the new syntax _unless_ the compiler is not Standard or OVERLAY
- Xis enabled.
- X
- XThere is one further consideration: that this technique only applies,
- Xof course, to functions that are published to the linker. For this
- Xreason, wherever such trampoli'd functions were originally declared
- Xstatic, that declaration has been changed to "STATIC_PTR", a macro
- Xthat expands to "static" unless the OVERLAY flag has been selected in
- Xthe configuration file, enabling the trampoli mechanism. Thus such
- Xfunctions lose their privacy in this one case.
- X
- X
- X3. OVLx
- X-------
- XThe strategies described above work fine, but they only stretch so
- Xfar. In particular, they do not admit of an overlay structure in
- Xwhich functions are linked into different overlays even though they
- Xoriginate in the same source file.
- X Classically, this is not considered a real limitation,
- Xbecause one has the freedom to regroup the functions into different
- Xsource files as needed; however, in the case of NetHack this was not
- Xa realistic option, since what structure this unwieldy programme has
- Xis precisely in the current grouping of functions together.
- XNonetheless, the ability to perform some functional grouping is an
- Xabsolute requirement for acceptable performance, since many NetHack
- Xsource modules (were.c, for example) contain one or two tiny
- Xfunctions that are called with great frequency (several millions of
- Xtimes per game is not unheard of) and whose return value determines
- Xwhether the remaining large, slow functions of the file will be
- Xrequired at all in the near future. Obviously these small checking
- Xfunctions should be linked into the same overlays with their callers,
- Xwhile the remainder of the source module should not.
- X
- XIn order to make this possible we ran a dynamic profile on the game
- Xto determine exactly which functions in which modules required such
- Xdistinguished treatment, and we have flagged each function for
- Xconditional compilation (with #if ... #endif) in groups according
- Xapproximately to their frequency of invocation and functionality.
- XThese groups have been arbitrarily named in each source file (in
- Xdecreasing order of frequency), OVL0, OVL1, OVL2, OVL3 and OVLB (B
- Xfor "base functions", those that deserve no special treatment at
- Xall). It is thus possible to compile only a small number of the
- Xfunctions in a file by defining but one or two of these symbols on
- Xthe compiler's command line (with the switch /DOVL2, for example);
- Xthe compiler will ignore the remainder as if they did not exist.
- X(There is an "escape clause" in hack.h that ensures that if none of
- Xthese flags is defined on the command line, then all of them will be
- Xduring compilation; this makes the non-use of this mechanism
- Xstraightforward!)
- X By repeated invocation of the compiler on the _same_ source
- Xfile it is possible to accumulate disjoint object modules that
- Xbetween them contain the images of all the functions in the original
- Xsource, but partitioned as is most convenient. Care must, of course,
- Xbe taken over conflicts of name in both the object file put out (all
- Xslices will by default be called SRCFILE.OBJ, and this default must
- Xbe overridden with distinct file names for each output slice) and in
- Xthe names of the text segments the compiler is to generate; you can
- Xsee this at work in Makefile.ovl. (You may wonder, as we did at
- Xfirst, why the text segment name would have to be made distinct in
- Xeach object file slice (the default segment name is a function of the
- Xsource file name and the compilation model only). The reason for this
- Xis, quite daftly to my mind, that the linker considers the identity
- Xof segment names and combine classes better reason to combine
- Xsegments than the programmer's explicit instructions in the requested
- Xoverlay pattern is reason to keep them apart. Programmer, ask not
- Xwhy...).
- X
- XOnce again, that works fine except for the small matter of
- Xdeclarations (where have we heard this before?). For objects that
- Xonce were static must now be made visible to the linker that they may
- Xbe resolved across the reaches of inter-overlay space. To this end we
- Xhave provided three macros, all of which expand simply to "static" if
- Xno OVLx flags are defined on the compilation command line. They are:
- X
- XSTATIC_DCL which introduces a declaration (as distinct from a
- X definition) of an object that would be static were it
- X not for the requirements of the OVLx mechanism. Its
- X expansion is "static", normally, but it becomes
- X "extern" in the event that this source file has been
- X split into slices with the OVLx mechanism.
- X
- XSTATIC_OVL is used when _defining_ a function (giving its text,
- X that is) that is logically static but may be called
- X across slices; it expands to "static" unless OVLx is
- X active; in the latter case it expands to null,
- X leaving the function with "previous linkage" as the
- X standard says. Note that this behaviour is quite
- X similar to, but very different from, that of
- X STATIC_PTR (described above), which has the same two
- X expansions but which is triggered not by OVLx but by
- X the OVERLAY flag which enables the trampoli mechanism.
- X STATIC_OVL also differs from the STATIC_DCL
- X and STATIC_VAR in that it is employed _within_ OVLx
- X slices, while the others are used to generate
- X declarations and are deployed in areas common to all
- X slices.
- X
- XSTATIC_VAR is used to introduce uninitialised would-be-static
- X variables. Its expansion is complex, since it must
- X read as "static" in the usual case, but as "extern"
- X if OVLx is in use -- in all overlays but one, where
- X it must expand to the null sequence -- giving it
- X "previous linkage" and "tentative definition" (to
- X ensure that the variable gets defined at all).
- X This one took a while to get right, and
- X believe me, using the macro is a lot easier than
- X trying to keep the #ifdefs straight yourself!
- X
- XAn initialised variable that is file-level static unless OVLx is in
- Xuse must now be written with a STATIC_DCL declaration, and a
- Xdefinition (and static initialiser) enclosed within the bracketing
- Xtag of one of the OVLx slices (any will do; we use OVLB).
- X Type definitions, macro definitions and extern declarations
- Xshould, of course remain outside any OVLx slice.
- X
- XFinally, of course, objects whose visibility need not be extended may
- Xsafely continue to be declared static. And in this case, at least,
- Xthe compiler will provide diagnostics that inform you when an object
- Xhas slipped through the cracks and requires the application of Magic
- XMacro Salve.
- X
- XIt is perhaps less than obvious that when a function is _both_ called
- Xacross an OVLx split and referenced through a pointer, it should be
- Xtreated as a pointered function (that is, it should get trampoli
- Xentries and should be defined STATIC_PTR). The reason for this is that
- Xthe STATIC_xxx macros associated with OVLx _only_ change the
- Xdeclaration patterns of the objects, while trampoli results in the
- Xgeneration of necessary code.
- X It is correct to do this, because the declarations produced by
- XSTATIC_PTR are triggered by OVERLAY's being defined, and the selection
- Xof OVERLAY is an absolute precondition for the activation of OVLx.
- X
- X
- X4. Hacking
- X----------
- XBefore undertaking any serious modifications to the overlay structure
- Xor support mechanisms, you should know that a _lot_ of work has gone
- Xinto the current scheme. If performance seems poor, remember: the
- Xoverlay manager itself can be invoked up to ten thousand times in a
- Xsecond, and although the space available for loading overlays (once
- Xthe data and stack spaces have been accounted for) is less than half
- Xthe total size of the overlays that are swapped through it, a disk
- Xaccess occurs well under 0.1% of the time(2). Furthermore, this
- Xperformance (such as it is) has been achieved without substantive
- Xchange or restructuring of the NetHack source code, which must remain
- Xportable to many platforms other than the PC.
- X
- XIf these observations do not daunt you, you are a Bit Warrior indeed
- X(or aspiration anyway), and we await your comments with bait.
- X
- X------------------------------------------------------------------------
- X
- XNOTES:
- X------
- X
- X(1) In fact, we have applied this technique throughout NetHack, even
- X in cases where it is not strictly necessary (since the pointered
- X calls are not across overlay splits, for example - though note
- X that there are more splits than might be initially apparent, due
- X to the effects of the OVLx hackage as described in section 3).
- X There is, however, one exception; and beware: it is an exception
- X with fangs. The file termcap.c contains a few pointered functions
- X that we decided _not_ to trampoli for performance reasons (screen
- X output is one of the problem areas on the PC port at the moment,
- X in terms of performance). It is therefore vital to the health of
- X PC NetHack as it currently stands that the OVLx slice termcap.0 be
- X linked into the ROOT "overlay".
- X
- X(2) These figures are for a 4.77 MHz PC-XT running in low memory with
- X an older version of both the overlay manager and the NetHack
- X overlay arrangement. On a more capable computer and with the
- X current software, the figures are probably more like a 100kHz peak
- X service rate and a hit rate (since we fixed the bug in the LRU
- X clock logic!) in excess of 99.99% -- hopefully not both at the
- X same time.
- X
- X------------------------------------------------------------------------
- XStephen P Spackman stephen@estragon.uchicago.edu
- X------------------------------------------------------------------------
- X * Hack On! *
- END_OF_FILE
- if test 17990 -ne `wc -c <'sys/msdos/maintovl.doc'`; then
- echo shar: \"'sys/msdos/maintovl.doc'\" unpacked with wrong size!
- fi
- # end of 'sys/msdos/maintovl.doc'
- fi
- if test -f 'win/X11/winmesg.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'win/X11/winmesg.c'\"
- else
- echo shar: Extracting \"'win/X11/winmesg.c'\" \(16667 characters\)
- sed "s/^X//" >'win/X11/winmesg.c' <<'END_OF_FILE'
- X/* SCCS Id: @(#)winmesg.c 3.1 92/05/19 */
- X/* Copyright (c) Dean Luick, 1992 */
- X/* NetHack may be freely redistributed. See license for details. */
- X
- X/*
- X * Message window routines.
- X *
- X * Global functions:
- X * set_message_height()
- X * create_message_window()
- X * destroy_message_window()
- X * display_message_window()
- X * append_message()
- X */
- X#include <X11/Intrinsic.h>
- X#include <X11/StringDefs.h>
- X#include <X11/Shell.h>
- X#include <X11/Xaw/Cardinals.h>
- X#include <X11/Xaw/Viewport.h>
- X#include "Window.h" /* Window widget declarations */
- X
- X#include "hack.h"
- X#include "winX.h"
- X
- Xstatic const char message_translations[] =
- X "#override\n\
- X <Key>: no-op()";
- X
- Xstatic struct line_element *get_previous();
- Xstatic void set_circle_buf();
- Xstatic char *split();
- Xstatic void add_line();
- Xstatic void redraw_message_window();
- Xstatic void mesg_check_size_change();
- Xstatic void mesg_exposed();
- Xstatic void get_gc();
- Xstatic void mesg_resized();
- X
- X/* Adjust the number of rows on the given message window. */
- Xvoid
- Xset_message_height(wp, rows)
- X struct xwindow *wp;
- X Dimension rows;
- X{
- X Arg args[1];
- X
- X wp->pixel_height = wp->mesg_information->char_height * rows;
- X
- X XtSetArg(args[0], XtNheight, wp->pixel_height);
- X XtSetValues(wp->w, args, ONE);
- X}
- X
- X/* Move the message window's vertical scrollbar's slider to the bottom. */
- Xvoid
- Xset_message_slider(wp)
- X struct xwindow *wp;
- X{
- X Widget scrollbar;
- X float top;
- X
- X scrollbar = XtNameToWidget(XtParent(wp->w), "vertical");
- X
- X if (scrollbar) {
- X top = 1.0;
- X XtCallCallbacks(scrollbar, XtNjumpProc, &top);
- X }
- X}
- X
- X
- Xvoid
- Xcreate_message_window(wp, create_popup, parent)
- X struct xwindow *wp; /* window pointer */
- X boolean create_popup;
- X Widget parent;
- X{
- X Arg args[8];
- X Cardinal num_args;
- X Widget viewport;
- X struct mesg_info_t *mesg_info;
- X
- X wp->type = NHW_MESSAGE;
- X
- X wp->mesg_information = mesg_info =
- X (struct mesg_info_t *) alloc(sizeof(struct mesg_info_t));
- X
- X mesg_info->fs = 0;
- X mesg_info->num_lines = 0;
- X mesg_info->head = mesg_info->last_pause =
- X mesg_info->last_pause_head = (struct line_element *) 0;
- X mesg_info->dirty = False;
- X mesg_info->viewport_width = mesg_info->viewport_height = 0;
- X
- X /*
- X * We should have an .Xdefaults option that specifies the number of lines
- X * to be displayed. Until then, we'll use DEFAULT_LINES_DISPLAYED.
- X * E.g.:
- X *
- X * if (a lines value from .Xdefaults exists)
- X * lines_displayed = lines value from .Xdefaults;
- X * else
- X * lines_displayed = DEFAULT_LINES_DISPLAYED;
- X */
- X if (flags.msg_history < DEFAULT_LINES_DISPLAYED)
- X flags.msg_history = DEFAULT_LINES_DISPLAYED;
- X if (flags.msg_history > MAX_HISTORY) /* a sanity check */
- X flags.msg_history = MAX_HISTORY;
- X
- X set_circle_buf(mesg_info, (int) flags.msg_history);
- X
- X /* Create a popup that becomes the parent. */
- X if (create_popup) {
- X num_args = 0;
- X XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
- X
- X wp->popup = parent = XtCreatePopupShell("message_popup",
- X topLevelShellWidgetClass,
- X toplevel, args, num_args);
- X }
- X
- X /*
- X * Create the viewport. We only want the vertical scroll bar ever to be
- X * visible. If we allow the horizontal scrollbar to be visible it will
- X * always be visible, due to the stupid way the Athena viewport operates.
- X */
- X num_args = 0;
- X XtSetArg(args[num_args], XtNallowVert, True); num_args++;
- X viewport = XtCreateManagedWidget(
- X "mesg_viewport", /* name */
- X viewportWidgetClass, /* widget class from Window.h */
- X parent, /* parent widget */
- X args, /* set some values */
- X num_args); /* number of values to set */
- X
- X /*
- X * Create a message window. We will change the width and height once
- X * we know what font we are using.
- X */
- X num_args = 0;
- X XtSetArg(args[num_args], XtNtranslations,
- X XtParseTranslationTable(message_translations)); num_args++;
- X wp->w = XtCreateManagedWidget(
- X "message", /* name */
- X windowWidgetClass, /* widget class from Window.h */
- X viewport, /* parent widget */
- X args, /* set some values */
- X num_args); /* number of values to set */
- X
- X XtAddCallback(wp->w, XtNexposeCallback, mesg_exposed, (XtPointer) 0);
- X
- X /*
- X * Now adjust the height and width of the message window so that it
- X * is DEFAULT_LINES_DISPLAYED high and DEFAULT_MESSAGE_WIDTH wide.
- X */
- X
- X /* Get the font information. */
- X num_args = 0;
- X XtSetArg(args[num_args], XtNfont, &mesg_info->fs); num_args++;
- X XtGetValues(wp->w, args, num_args);
- X
- X /* Save character information for fast use later. */
- X mesg_info->char_width = mesg_info->fs->max_bounds.width;
- X mesg_info->char_height = mesg_info->fs->max_bounds.ascent +
- X mesg_info->fs->max_bounds.descent;
- X mesg_info->char_ascent = mesg_info->fs->max_bounds.ascent;
- X mesg_info->char_lbearing = -mesg_info->fs->min_bounds.lbearing;
- X
- X get_gc(wp->w, mesg_info);
- X
- X wp->pixel_height = DEFAULT_LINES_DISPLAYED * mesg_info->char_height;
- X
- X /* If a variable spaced font, only use 2/3 of the default size */
- X if (mesg_info->fs->min_bounds.width != mesg_info->fs->max_bounds.width) {
- X wp->pixel_width = ((2*DEFAULT_MESSAGE_WIDTH)/3) *
- X mesg_info->fs->max_bounds.width;
- X } else
- X wp->pixel_width = (DEFAULT_MESSAGE_WIDTH *
- X mesg_info->fs->max_bounds.width);
- X
- X /* Set the new width and height. */
- X num_args = 0;
- X XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++;
- X XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
- X XtSetValues(wp->w, args, num_args);
- X
- X XtAddEventHandler(wp->w, KeyPressMask, False,
- X (XtEventHandler) msgkey, (XtPointer) 0);
- X XtAddCallback(wp->w, XtNresizeCallback, mesg_resized, (XtPointer) 0);
- X
- X /*
- X * If we have created our own popup, then realize it so that the
- X * viewport is also realized. Then resize the mesg window.
- X */
- X if (create_popup) {
- X XtRealizeWidget(wp->popup);
- X set_message_height(wp, (int) flags.msg_history);
- X }
- X}
- X
- X
- Xvoid
- Xdestroy_message_window(wp)
- X struct xwindow *wp;
- X{
- X if (wp->popup) {
- X nh_XtPopdown(wp->popup);
- X XtDestroyWidget(wp->popup);
- X set_circle_buf(wp->mesg_information, 0); /* free buffer list */
- X free((char *)wp->mesg_information);
- X }
- X wp->type = NHW_NONE;
- X}
- X
- X
- X/* Redraw message window if new lines have been added. */
- Xvoid
- Xdisplay_message_window(wp)
- X struct xwindow *wp;
- X{
- X if (wp->mesg_information->dirty) redraw_message_window(wp);
- X}
- X
- X
- X/*
- X * Append a line of text to the message window. Split the line if the
- X * rendering of the text is too long for the window.
- X */
- Xvoid
- Xappend_message(wp, str)
- X struct xwindow *wp;
- X const char *str;
- X{
- X char *mark, *remainder, buf[BUFSZ];
- X
- X if (!str) return;
- X
- X Strcpy(buf, str); /* we might mark it up */
- X
- X remainder = buf;
- X do {
- X mark = remainder;
- X remainder = split(mark, wp->mesg_information->fs, wp->pixel_width);
- X add_line(wp->mesg_information, mark);
- X } while (remainder);
- X}
- X
- X/* private functions ======================================================= */
- X
- X/*
- X * Return the element in the circular linked list just before the given
- X * element.
- X */
- Xstatic struct line_element *
- Xget_previous(mark)
- X struct line_element *mark;
- X{
- X struct line_element *curr;
- X
- X if (!mark) return (struct line_element *) 0;
- X
- X for (curr = mark; curr->next != mark; curr = curr->next)
- X ;
- X return curr;
- X}
- X
- X
- X/*
- X * Set the information buffer size to count lines. We do this by creating
- X * a circular linked list of elements, each of which represents a line of
- X * text. New buffers are created as needed, old ones are freed if they
- X * are no longer used.
- X */
- Xstatic void
- Xset_circle_buf(mesg_info, count)
- X struct mesg_info_t *mesg_info;
- X int count;
- X{
- X int i;
- X struct line_element *tail, *curr, *head;
- X
- X if (count < 0) panic("set_circle_buf: bad count [= %d]", count);
- X if (count == mesg_info->num_lines) return; /* no change in size */
- X
- X if (count < mesg_info->num_lines) {
- X /*
- X * Toss num_lines - count line entries from our circular list.
- X *
- X * We lose lines from the front (top) of the list. We _know_
- X * the list is non_empty.
- X */
- X tail = get_previous(mesg_info->head);
- X for (i = mesg_info->num_lines - count; i--; ) {
- X curr = mesg_info->head;
- X mesg_info->head = curr->next;
- X if (curr->line) free(curr->line);
- X free((genericptr_t)curr);
- X }
- X if (count == 0) {
- X /* make sure we don't have a dangling pointer */
- X mesg_info->head = (struct line_element *) 0;
- X } else {
- X tail->next = mesg_info->head; /* link the tail to the head */
- X }
- X } else {
- X /*
- X * Add count - num_lines blank lines to the head of the list.
- X *
- X * Create a separate list, keeping track of the tail.
- X */
- X for (head = tail = 0, i = 0; i < count - mesg_info->num_lines; i++) {
- X curr = (struct line_element *) alloc(sizeof(struct line_element));
- X curr->line = 0;
- X curr->buf_length = 0;
- X curr->str_length = 0;
- X if (tail) {
- X tail->next = curr;
- X tail = curr;
- X } else {
- X head = tail = curr;
- X }
- X }
- X /*
- X * Complete the circle by making the new tail point to the old head
- X * and the old tail point to the new head. If our line count was
- X * zero, then make the new list circular.
- X */
- X if (mesg_info->num_lines) {
- X curr = get_previous(mesg_info->head);/* get end of old list */
- X
- X tail->next = mesg_info->head; /* new tail -> old head */
- X curr->next = head; /* old tail -> new head */
- X } else {
- X tail->next = head;
- X }
- X mesg_info->head = head;
- X }
- X
- X mesg_info->num_lines = count;
- X /* Erase the line on a resize. */
- X mesg_info->last_pause = (struct line_element *) 0;
- X}
- X
- X
- X/*
- X * Make sure the given string is shorter than the given pixel width. If
- X * not, back up from the end by words until we find a place to split.
- X */
- Xstatic char *
- Xsplit(s, fs, pixel_width)
- X char *s;
- X XFontStruct *fs; /* Font for the window. */
- X Dimension pixel_width;
- X{
- X char save, *end, *remainder;
- X
- X save = '\0';
- X remainder = 0;
- X end = eos(s); /* point to null at end of string */
- X
- X /* assume that if end == s, XXXXXX returns 0) */
- X while ((Dimension) XTextWidth(fs, s, (int) strlen(s)) > pixel_width) {
- X *end-- = save;
- X while (*end != ' ') {
- X if (end == s) panic("split: eos!");
- X --end;
- X }
- X save = *end;
- X *end = '\0';
- X remainder = end + 1;
- X }
- X return remainder;
- X}
- X
- X/*
- X * Add a line of text to the window. The first line in the curcular list
- X * becomes the last. So all we have to do is copy the new line over the
- X * old one. If the line buffer is too small, then allocate a new, larger
- X * one.
- X */
- Xstatic void
- Xadd_line(mesg_info, s)
- X struct mesg_info_t *mesg_info;
- X const char *s;
- X{
- X register struct line_element *curr = mesg_info->head;
- X register int new_line_length = strlen(s);
- X
- X if (new_line_length + 1 > curr->buf_length) {
- X if (curr->line) free(curr->line); /* free old line */
- X
- X curr->buf_length = new_line_length + 1;
- X curr->line = (char *) alloc(curr->buf_length);
- X }
- X
- X Strcpy(curr->line, s); /* copy info */
- X curr->str_length = new_line_length; /* save string length */
- X
- X mesg_info->head = mesg_info->head->next; /* move head to next line */
- X mesg_info->dirty = True; /* we have undrawn lines */
- X}
- X
- X
- X/*
- X * Save a position in the text buffer so we can draw a line to seperate
- X * text from the last time this function was called.
- X *
- X * Save the head position, since it is the line "after" the last displayed
- X * line in the message window. The window redraw routine will draw a
- X * line above this saved pointer.
- X */
- Xvoid
- Xset_last_pause(wp)
- X struct xwindow *wp;
- X{
- X register struct mesg_info_t *mesg_info = wp->mesg_information;
- X
- X#ifdef ERASE_LINE
- X /*
- X * If we've erased the pause line and haven't added any new lines,
- X * don't try to erase the line again.
- X */
- X if (!mesg_info->last_pause
- X && mesg_info->last_pause_head == mesg_info->head)
- X return;
- X
- X if (mesg_info->last_pause == mesg_info->head) {
- X /* No new messages in last turn. Redraw window to erase line. */
- X mesg_info->last_pause = (struct line_element *) 0;
- X mesg_info->last_pause_head = mesg_info->head;
- X redraw_message_window(wp);
- X } else {
- X#endif
- X mesg_info->last_pause = mesg_info->head;
- X#ifdef ERASE_LINE
- X }
- X#endif
- X}
- X
- X
- Xstatic void
- Xredraw_message_window(wp)
- X struct xwindow *wp;
- X{
- X struct mesg_info_t *mesg_info = wp->mesg_information;
- X register struct line_element *curr;
- X register int row;
- X
- X /*
- X * Do this the cheap and easy way. Clear the window and just redraw
- X * the whole thing.
- X *
- X * This could be done more effecently with one call to XDrawText() instead
- X * of many calls to XDrawString(). Maybe later.
- X */
- X XClearWindow(XtDisplay(wp->w), XtWindow(wp->w));
- X
- X /* For now, just update the whole shootn' match. */
- X for (row = 0, curr = mesg_info->head;
- X row < mesg_info->num_lines; row++, curr = curr->next) {
- X
- X register int y_base = row * mesg_info->char_height;
- X
- X XDrawString(XtDisplay(wp->w), XtWindow(wp->w),
- X mesg_info->gc,
- X mesg_info->char_lbearing,
- X mesg_info->char_ascent + y_base,
- X curr->line,
- X curr->str_length);
- X
- X /*
- X * This draws a line at the _top_ of the line of text pointed to by
- X * mesg_info->last_pause.
- X */
- X if (appResources.message_line && curr == mesg_info->last_pause) {
- X XDrawLine(XtDisplay(wp->w), XtWindow(wp->w),
- X mesg_info->gc,
- X 0, y_base, wp->pixel_width, y_base);
- X }
- X }
- X
- X mesg_info->dirty = False;
- X}
- X
- X
- X/*
- X * Check the size of the viewport. If it has shrunk, then we want to
- X * move the vertical slider to the bottom.
- X */
- Xstatic void
- Xmesg_check_size_change(wp)
- X struct xwindow *wp;
- X{
- X struct mesg_info_t *mesg_info = wp->mesg_information;
- X Arg arg[2];
- X Dimension new_width, new_height;
- X Widget viewport;
- X
- X viewport = XtParent(wp->w);
- X
- X XtSetArg(arg[0], XtNwidth, &new_width);
- X XtSetArg(arg[1], XtNheight, &new_height);
- X XtGetValues(viewport, arg, TWO);
- X
- X /* Only move slider to bottom if new size is smaller. */
- X if (new_width < mesg_info->viewport_width
- X || new_height < mesg_info->viewport_height) {
- X set_message_slider(wp);
- X }
- X
- X mesg_info->viewport_width = new_width;
- X mesg_info->viewport_height = new_height;
- X}
- X
- X
- X/* Event handler for message window expose events. */
- X/*ARGSUSED*/
- Xstatic void
- Xmesg_exposed(w, event)
- X Widget w;
- X XExposeEvent *event; /* unused */
- X{
- X struct xwindow *wp;
- X
- X if (!XtIsRealized(w)) return;
- X wp = find_widget(w);
- X mesg_check_size_change(wp);
- X redraw_message_window(wp);
- X}
- X
- X
- Xstatic void
- Xget_gc(w, mesg_info)
- X Widget w;
- X struct mesg_info_t *mesg_info;
- X{
- X XGCValues values;
- X XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont;
- X Pixel fgpixel, bgpixel;
- X Arg arg[2];
- X
- X XtSetArg(arg[0], XtNforeground, &fgpixel);
- X XtSetArg(arg[1], XtNbackground, &bgpixel);
- X XtGetValues(w, arg, TWO);
- X
- X values.foreground = fgpixel;
- X values.background = bgpixel;
- X values.function = GXcopy;
- X values.font = WindowFont(w);
- X mesg_info->gc = XtGetGC(w, mask, &values);
- X}
- X
- X/*
- X * Handle resizes on a message window. Correct saved pixel height and width.
- X * Adjust circle buffer to accomidate the new size.
- X *
- X * Problem: If the resize decreases the width of the window such that
- X * some lines are now longer than the window, they will be cut off by
- X * X itself. All new lines will be split to the new size, but the ends
- X * of the old ones will not be seen again unless the window is lengthened.
- X * I don't deal with this problem because it isn't worth the trouble.
- X */
- X/* ARGSUSED */
- Xstatic void
- Xmesg_resized(w, client_data, call_data)
- X Widget w;
- X XtPointer call_data, client_data;
- X{
- X Arg args[4];
- X Cardinal num_args;
- X Dimension pixel_width, pixel_height;
- X struct xwindow *wp;
- X#ifdef VERBOSE
- X int old_lines;
- X
- X old_lines = wp->mesg_information->num_lines;;
- X#endif
- X
- X num_args = 0;
- X XtSetArg(args[num_args], XtNwidth, &pixel_width); num_args++;
- X XtSetArg(args[num_args], XtNheight, &pixel_height); num_args++;
- X XtGetValues(w, args, num_args);
- X
- X wp = find_widget(w);
- X wp->pixel_width = pixel_width;
- X wp->pixel_height = pixel_height;
- X
- X set_circle_buf(wp->mesg_information,
- X (int) pixel_height / wp->mesg_information->char_height);
- X
- X#ifdef VERBOSE
- X printf("Message resize. Pixel: width = %d, height = %d; Lines: old = %d, new = %d\n",
- X pixel_width,
- X pixel_height,
- X old_lines,
- X wp->mesg_information->num_lines);
- X#endif
- X}
- END_OF_FILE
- if test 16667 -ne `wc -c <'win/X11/winmesg.c'`; then
- echo shar: \"'win/X11/winmesg.c'\" unpacked with wrong size!
- fi
- # end of 'win/X11/winmesg.c'
- fi
- echo shar: End of archive 85 \(of 108\).
- cp /dev/null ark85isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
- 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
- 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
- 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
- 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
- 101 102 103 104 105 106 107 108 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 108 archives.
- echo "Now execute 'rebuild.sh'"
- rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-