home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
games
/
volume16
/
nethack31
/
part85
< prev
next >
Wrap
Internet Message Format
|
1993-02-06
|
59KB
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