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

  1. Path: uunet!news.tek.com!master!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v16i093:  nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part85/108
  5. Message-ID: <4456@master.CNA.TEK.COM>
  6. Date: 5 Feb 93 19:21:52 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 1787
  9. Approved: billr@saab.CNA.TEK.COM
  10. Xref: uunet comp.sources.games:1644
  11.  
  12. Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
  13. Posting-number: Volume 16, Issue 93
  14. Archive-name: nethack31/Part85
  15. Supersedes: nethack3p9: Volume 10, Issue 46-102
  16. Environment: Amiga, Atari, Mac, MS-DOS, OS2, Unix, VMS, X11
  17.  
  18.  
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of archive 85 (of 108)."
  27. # Contents:  include/vision.h src/end.c sys/msdos/maintovl.doc
  28. #   win/X11/winmesg.c
  29. # Wrapped by billr@saab on Wed Jan 27 16:09:21 1993
  30. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  31. if test -f 'include/vision.h' -a "${1}" != "-c" ; then 
  32.   echo shar: Will not clobber existing file \"'include/vision.h'\"
  33. else
  34. echo shar: Extracting \"'include/vision.h'\" \(1597 characters\)
  35. sed "s/^X//" >'include/vision.h' <<'END_OF_FILE'
  36. X/*    SCCS Id: @(#)vision.h    3.1    92/11/14    */
  37. X/* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990.    */
  38. X/* NetHack may be freely redistributed.  See license for details.    */
  39. X
  40. X#ifndef VISION_H
  41. X#define VISION_H
  42. X
  43. X#if 0    /* (moved to decl.h) */
  44. Xextern boolean vision_full_recalc;    /* TRUE if need vision recalc */
  45. Xextern char **viz_array;        /* could see/in sight row pointers */
  46. Xextern char *viz_rmin;            /* min could see indices */
  47. Xextern char *viz_rmax;            /* max could see indices */
  48. X#endif
  49. X#define COULD_SEE 0x1
  50. X#define IN_SIGHT 0x2
  51. X
  52. X/*
  53. X *  cansee()    - Returns true if the hero can see the location.
  54. X *
  55. X *  couldsee()    - Returns true if the hero has a clear line of sight to
  56. X *          the location.
  57. X */
  58. X#define cansee(x,y)    (viz_array[y][x] & IN_SIGHT)
  59. X#define couldsee(x,y)    (viz_array[y][x] & COULD_SEE)
  60. X
  61. X/*
  62. X *  The following assume the monster is not blind.
  63. X *
  64. X *  m_cansee()    - Returns true if the monster can see the given location.
  65. X *
  66. X *  m_canseeu()    - Returns true if the monster could see the hero.  Assumes
  67. X *          that if the hero has a clear line of sight to the monster's
  68. X *          location and the hero is visible, then monster can see the
  69. X *          hero.
  70. X */
  71. X#define m_cansee(mtmp,x2,y2)    clear_path((mtmp)->mx,(mtmp)->my,(x2),(y2))
  72. X
  73. X#define m_canseeu(m)        ((!Invis || perceives((m)->data)) && !Underwater ? \
  74. X                     couldsee((m)->mx,(m)->my) : 0)
  75. X
  76. X/*
  77. X *  Circle information
  78. X */
  79. X#define MAX_RADIUS 15    /* this is in points from the source */
  80. X
  81. X/* Use this macro to get a list of distances of the edges (see vision.c). */
  82. X#define circle_ptr(z) (&circle_data[circle_start[z]])
  83. X
  84. X#endif /* VISION_H */
  85. END_OF_FILE
  86. if test 1597 -ne `wc -c <'include/vision.h'`; then
  87.     echo shar: \"'include/vision.h'\" unpacked with wrong size!
  88. fi
  89. # end of 'include/vision.h'
  90. fi
  91. if test -f 'src/end.c' -a "${1}" != "-c" ; then 
  92.   echo shar: Will not clobber existing file \"'src/end.c'\"
  93. else
  94. echo shar: Extracting \"'src/end.c'\" \(17434 characters\)
  95. sed "s/^X//" >'src/end.c' <<'END_OF_FILE'
  96. X/*    SCCS Id: @(#)end.c    3.1    93/01/15    */
  97. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  98. X/* NetHack may be freely redistributed.  See license for details. */
  99. X
  100. X#define NEED_VARARGS    /* comment line for pre-compiled headers */
  101. X
  102. X#include "hack.h"
  103. X#include "eshk.h"
  104. X#ifndef NO_SIGNAL
  105. X#include <signal.h>
  106. X#endif
  107. X
  108. XSTATIC_PTR int NDECL(done_intr);
  109. Xstatic void FDECL(disclose,(int,BOOLEAN_P));
  110. Xstatic struct obj *FDECL(get_valuables, (struct obj *));
  111. Xstatic void FDECL(savelife, (int));
  112. X
  113. X/*
  114. X * The order of these needs to match the macros in hack.h.
  115. X */
  116. Xstatic const char NEARDATA *deaths[] = {        /* the array of death */
  117. X    "died", "choked", "poisoned", "starvation", "drowning",
  118. X    "burning", "crushed", "turned to stone", "genocided",
  119. X    "panic", "trickery",
  120. X    "quit", "escaped", "ascended"
  121. X};
  122. X
  123. Xstatic const char NEARDATA *ends[] = {        /* "when you..." */
  124. X    "died", "choked", "were poisoned", "starved", "drowned",
  125. X    "burned", "were crushed", "turned to stone", "were genocided",
  126. X    "panicked", "were tricked",
  127. X    "quit", "escaped", "ascended"
  128. X};
  129. X
  130. Xint
  131. Xdone1()
  132. X{
  133. X#ifndef NO_SIGNAL
  134. X    (void) signal(SIGINT,SIG_IGN);
  135. X#endif
  136. X    if(flags.ignintr) {
  137. X#ifndef NO_SIGNAL
  138. X        (void) signal(SIGINT, (SIG_RET_TYPE) done1);
  139. X#endif
  140. X        clear_nhwindow(WIN_MESSAGE);
  141. X        curs_on_u();
  142. X        wait_synch();
  143. X        if(multi > 0) nomul(0);
  144. X        return 0;
  145. X    }
  146. X    return done2();
  147. X}
  148. X
  149. Xint
  150. Xdone2()
  151. X{
  152. X    if(yn("Really quit?") == 'n') {
  153. X#ifndef NO_SIGNAL
  154. X        (void) signal(SIGINT, (SIG_RET_TYPE) done1);
  155. X#endif
  156. X        clear_nhwindow(WIN_MESSAGE);
  157. X        curs_on_u();
  158. X        wait_synch();
  159. X        if(multi > 0) nomul(0);
  160. X        if(multi == 0) {
  161. X            u.uinvulnerable = FALSE;    /* avoid ctrl-C bug -dlc */
  162. X            u.usleep = 0;
  163. X        }
  164. X        return 0;
  165. X    }
  166. X#if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
  167. X    if(wizard) {
  168. X# ifdef VMS
  169. X        const char *tmp = "Enter debugger?";
  170. X# else
  171. X#  ifdef LATTICE
  172. X        const char *tmp = "Create SnapShot?";
  173. X#  else
  174. X        const char *tmp = "Dump core?";
  175. X#  endif
  176. X# endif
  177. X        if(yn(tmp) == 'y') {
  178. X        (void) signal(SIGINT, (SIG_RET_TYPE) done1);
  179. X        exit_nhwindows(NULL);
  180. X#ifdef AMIGA
  181. X        Abort(0);
  182. X#else
  183. X# ifdef SYSV
  184. X        (void)
  185. X# endif
  186. X            abort();
  187. X#endif
  188. X        }
  189. X    }
  190. X#endif
  191. X#ifndef LINT
  192. X    done(QUIT);
  193. X#endif
  194. X    return 0;
  195. X}
  196. X
  197. XSTATIC_PTR
  198. Xint
  199. Xdone_intr(){
  200. X    done_stopprint++;
  201. X#ifndef NO_SIGNAL
  202. X    (void) signal(SIGINT, SIG_IGN);
  203. X# if defined(UNIX) || defined(VMS)
  204. X    (void) signal(SIGQUIT, SIG_IGN);
  205. X# endif
  206. X#endif /* NO_SIGNAL /* */
  207. X    return 0;
  208. X}
  209. X
  210. X#if defined(UNIX) || defined(VMS)
  211. Xstatic
  212. Xint
  213. Xdone_hangup(){
  214. X    done_hup++;
  215. X    (void)signal(SIGHUP, SIG_IGN);
  216. X    (void)done_intr();
  217. X    return 0;
  218. X}
  219. X#endif
  220. X
  221. Xvoid
  222. Xdone_in_by(mtmp)
  223. Xregister struct monst *mtmp;
  224. X{
  225. X    char buf[BUFSZ];
  226. X
  227. X    You("die...");
  228. X    buf[0] = '\0';
  229. X    if (type_is_pname(mtmp->data) || (mtmp->data->geno & G_UNIQ)) {
  230. X         if (!(type_is_pname(mtmp->data) && (mtmp->data->geno & G_UNIQ)))
  231. X        Strcat(buf, "the ");
  232. X         killer_format = KILLED_BY;
  233. X    }
  234. X    if (mtmp->minvis)
  235. X        Strcat(buf, "invisible ");
  236. X    if (Hallucination)
  237. X        Strcat(buf, "hallucinogen-distorted ");
  238. X
  239. X    if(mtmp->data == &mons[PM_GHOST]) {
  240. X        register char *gn = (char *) mtmp->mextra;
  241. X        if (!Hallucination && !mtmp->minvis && *gn) {
  242. X            Strcat(buf, "the ");
  243. X            killer_format = KILLED_BY;
  244. X        }
  245. X        Sprintf(eos(buf), (*gn ? "ghost of %s" : "ghost%s"), gn);
  246. X    } else if(mtmp->isshk) {
  247. X        Sprintf(eos(buf), "%s %s, the shopkeeper",
  248. X            (mtmp->female ? "Ms." : "Mr."), shkname(mtmp));
  249. X        killer_format = KILLED_BY;
  250. X    } else if (mtmp->ispriest || mtmp->isminion) {
  251. X        killer = priestname(mtmp);
  252. X        if (!strncmp(killer, "the ", 4)) Strcat(buf, killer+4);
  253. X        else Strcat(buf, killer);
  254. X    } else Strcat(buf, mtmp->data->mname);
  255. X    if (mtmp->mnamelth) Sprintf(eos(buf), " called %s", NAME(mtmp));
  256. X    killer = buf;
  257. X    if (mtmp->data->mlet == S_WRAITH)
  258. X        u.ugrave_arise = PM_WRAITH;
  259. X    else if (mtmp->data->mlet == S_MUMMY)
  260. X        u.ugrave_arise = (pl_character[0]=='E') ?
  261. X                        PM_ELF_MUMMY : PM_HUMAN_MUMMY;
  262. X    else if (mtmp->data->mlet == S_VAMPIRE)
  263. X        u.ugrave_arise = PM_VAMPIRE;
  264. X    if (u.ugrave_arise > -1 && (mons[u.ugrave_arise].geno & G_GENOD))
  265. X        u.ugrave_arise = -1;
  266. X    if (mtmp->data->mlet == S_COCKATRICE)
  267. X        done(STONING);
  268. X    else
  269. X        done(DIED);
  270. X    return;
  271. X}
  272. X
  273. X/*VARARGS1*/
  274. Xboolean panicking;
  275. Xextern boolean hu;    /* from save.c */
  276. X
  277. Xvoid
  278. Xpanic VA_DECL(const char *, str)
  279. X    VA_START(str);
  280. X    VA_INIT(str, char *);
  281. X
  282. X    if(panicking++)
  283. X#ifdef AMIGA
  284. X        Abort(0);
  285. X#else
  286. X# ifdef SYSV
  287. X        (void)
  288. X# endif
  289. X        abort();    /* avoid loops - this should never happen*/
  290. X#endif
  291. X
  292. X    if (flags.window_inited) exit_nhwindows(NULL);
  293. X    flags.window_inited = 0; /* they're gone; force raw_print()ing */
  294. X
  295. X    raw_print(" Suddenly, the dungeon collapses.");
  296. X#if defined(WIZARD) && !defined(MICRO)
  297. X    if(!wizard) {
  298. X        raw_printf("Report error to %s and it may be possible to rebuild.",
  299. X# ifdef WIZARD_NAME    /*(KR1ED)*/
  300. X        WIZARD_NAME);
  301. X# else
  302. X        WIZARD);
  303. X# endif
  304. X    }
  305. X    set_error_savefile();
  306. X    hu = FALSE;
  307. X    (void) dosave0();
  308. X#endif
  309. X    {
  310. X        char buf[BUFSZ];
  311. X        Vsprintf(buf,str,VA_ARGS);
  312. X        raw_print(buf);
  313. X    }
  314. X#if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE))
  315. X    if (wizard)
  316. X# ifdef AMIGA
  317. X        Abort(0);
  318. X# else
  319. X#  ifdef SYSV
  320. X        (void)
  321. X#  endif
  322. X            abort();    /* generate core dump */
  323. X# endif
  324. X#endif
  325. X    VA_END();
  326. X    done(PANICKED);
  327. X}
  328. X
  329. Xstatic void
  330. Xdisclose(how,taken)
  331. Xint how;
  332. Xboolean taken;
  333. X{
  334. X    char    c;
  335. X    char    qbuf[QBUFSZ];
  336. X
  337. X    if(invent) {
  338. X        if(taken)
  339. X        Sprintf(qbuf,"Do you want to see what you had when you %s?",
  340. X            (how == QUIT) ? "quit" : "died");
  341. X        else
  342. X        Strcpy(qbuf,"Do you want your possessions identified?");
  343. X        if ((c = yn_function(qbuf, ynqchars, 'y')) == 'y') {
  344. X        /* New dump format by maartenj@cs.vu.nl */
  345. X        struct obj *obj;
  346. X
  347. X        for(obj = invent; obj && !done_stopprint; obj = obj->nobj) {
  348. X            makeknown(obj->otyp);
  349. X            obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
  350. X        }
  351. X        (void) display_inventory(NULL, FALSE);
  352. X        container_contents(invent, TRUE, TRUE);
  353. X        }
  354. X        if (c == 'q')  done_stopprint++;
  355. X        if (taken) {
  356. X        /* paybill has already given the inventory locations
  357. X         * in the shop and put it on the main object list
  358. X         */
  359. X        struct obj *obj;
  360. X
  361. X        for(obj = invent; obj; obj = obj->nobj) {
  362. X            obj->owornmask = 0;
  363. X            if(rn2(5)) curse(obj);
  364. X        }
  365. X        invent = (struct obj *) 0;
  366. X        }
  367. X    }
  368. X
  369. X    if (!done_stopprint) {
  370. X        c = yn_function("Do you want to see your intrinsics?",ynqchars,'y');
  371. X        if (c == 'y') enlightenment(TRUE);    /* final */
  372. X        if (c == 'q') done_stopprint++;
  373. X    }
  374. X
  375. X}
  376. X
  377. X/* try to get the player back in a viable state after being killed */
  378. Xstatic void
  379. Xsavelife(how)
  380. Xint how;
  381. X{
  382. X    u.uswldtim = 0;
  383. X    u.uhp = u.uhpmax;
  384. X    if (u.uhunger < 500) {
  385. X        u.uhunger = 500;
  386. X        newuhs(FALSE);
  387. X    }
  388. X    if (how == CHOKING) init_uhunger();
  389. X    nomovemsg = "You survived that attempt on your life.";
  390. X    flags.move = 0;
  391. X    if(multi > 0) multi = 0; else multi = -1;
  392. X    if(u.utrap && u.utraptype == TT_LAVA) u.utrap = 0;
  393. X    flags.botl = 1;
  394. X    u.ugrave_arise = -1;
  395. X    curs_on_u();
  396. X}
  397. X
  398. X/*
  399. X *  Get valuables from the given list. NOTE: The list is destroyed as it is
  400. X *  processed, so don't expect to use it again!
  401. X */
  402. Xstatic struct obj *
  403. Xget_valuables(list)
  404. X    struct obj *list;
  405. X{
  406. X    struct obj *obj, *next_obj, *c_vals, *temp;
  407. X    struct obj *valuables = (struct obj *)0;
  408. X
  409. X    for (obj = list; obj; obj = next_obj) {
  410. X    if (Is_container(obj) && obj->cobj) {
  411. X        c_vals = get_valuables(obj->cobj);
  412. X
  413. X        if (c_vals) {
  414. X        /* find the end of the list */
  415. X        for (temp = c_vals; temp->nobj; temp = temp->nobj) ;
  416. X
  417. X        temp->nobj = valuables;
  418. X        valuables = c_vals;
  419. X        }
  420. X    }
  421. X
  422. X    next_obj = obj->nobj;
  423. X
  424. X    if ((obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE)
  425. X        || obj->oclass == AMULET_CLASS) {
  426. X        obj->nobj = valuables;
  427. X        valuables = obj;
  428. X    }
  429. X    }
  430. X    return valuables;
  431. X}
  432. X
  433. X/* Be careful not to call panic from here! */
  434. Xvoid
  435. Xdone(how)
  436. Xint how;
  437. X{
  438. X    struct permonst *upmon;
  439. X    boolean taken;
  440. X    char kilbuf[BUFSZ], pbuf[BUFSZ];
  441. X    winid endwin = WIN_ERR;
  442. X    boolean have_windows = flags.window_inited;
  443. X
  444. X    /* kilbuf: used to copy killer in case it comes from something like
  445. X     *    xname(), which would otherwise get overwritten when we call
  446. X     *    xname() when listing possessions
  447. X     * pbuf: holds Sprintf'd output for raw_print and putstr
  448. X     */
  449. X    if (how == ASCENDED)
  450. X        killer_format = NO_KILLER_PREFIX;
  451. X    /* Avoid killed by "a" burning or "a" starvation */
  452. X    if (!killer && (how == STARVING || how == BURNING))
  453. X        killer_format = KILLED_BY;
  454. X    Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer));
  455. X    killer = kilbuf;
  456. X#ifdef WIZARD
  457. X    if (wizard && how == TRICKED) {
  458. X        You("are a very tricky wizard, it seems.");
  459. X        return;
  460. X    }
  461. X#endif
  462. X    if (Lifesaved && how <= GENOCIDED) {
  463. X        pline("But wait...");
  464. X        makeknown(AMULET_OF_LIFE_SAVING);
  465. X        Your("medallion %s!",
  466. X              !Blind ? "begins to glow" : "feels warm");
  467. X        if (how == CHOKING) You("vomit ...");
  468. X        You("feel much better!");
  469. X        pline("The medallion crumbles to dust!");
  470. X        useup(uamul);
  471. X
  472. X        (void) adjattrib(A_CON, -1, TRUE);
  473. X        if(u.uhpmax <= 0) u.uhpmax = 10;    /* arbitrary */
  474. X        savelife(how);
  475. X        if (how == GENOCIDED)
  476. X            pline("Unfortunately you are still genocided...");
  477. X        else {
  478. X            killer = 0;
  479. X            return;
  480. X        }
  481. X    }
  482. X#if defined(WIZARD) || defined(EXPLORE_MODE)
  483. X    if ((wizard || discover) && how <= GENOCIDED) {
  484. X        if(yn("Die?") == 'y') goto die;
  485. X        pline("OK, so you don't %s.",
  486. X            (how == CHOKING) ? "choke" : "die");
  487. X        if(u.uhpmax <= 0) u.uhpmax = u.ulevel * 8;    /* arbitrary */
  488. X        savelife(how);
  489. X        killer = 0;
  490. X        return;
  491. X    }
  492. X#endif /* WIZARD || EXPLORE_MODE */
  493. X    /* Sometimes you die on the first move.  Life's not fair.
  494. X     * On those rare occasions you get hosed immediately, go out
  495. X     * smiling... :-)  -3.
  496. X     */
  497. X    if (moves <= 1 && how < QUIT)
  498. X        /* You die... --More-- */
  499. X        pline("Do not pass go.  Do not collect 200 zorkmids.");
  500. X
  501. Xdie:
  502. X    if (have_windows) wait_synch();    /* flush screen output */
  503. X#ifndef NO_SIGNAL
  504. X    (void) signal(SIGINT, (SIG_RET_TYPE) done_intr);
  505. X# if defined(UNIX) || defined(VMS)
  506. X    (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr);
  507. X    (void) signal(SIGHUP, (SIG_RET_TYPE) done_hangup);
  508. X# endif
  509. X#endif /* NO_SIGNAL /* */
  510. X#ifdef POLYSELF
  511. X    if (u.mtimedone)
  512. X        upmon = uasmon;
  513. X    else
  514. X#endif
  515. X    upmon = player_mon();
  516. X
  517. X    if (u.ugrave_arise < 0) { /* >= 0 means create no corpse */
  518. X        if (how == STONING)
  519. X        u.ugrave_arise = -2;
  520. X
  521. X/*
  522. X * If you're burned to a crisp, why leave a corpse?
  523. X */
  524. X        else if (how != BURNING && how != PANICKED)
  525. X        (void) mk_named_object(CORPSE, upmon, u.ux, u.uy, plname,
  526. X                            (int)strlen(plname));
  527. X    }
  528. X
  529. X    if (how == QUIT) {
  530. X        killer_format = NO_KILLER_PREFIX;
  531. X        if (u.uhp < 1) {
  532. X            how = DIED;
  533. X/* note that killer is pointing at kilbuf */
  534. X            Strcpy(kilbuf, "quit while already on Charon's boat");
  535. X        }
  536. X    }
  537. X    if (how == ESCAPED || how == PANICKED)
  538. X        killer_format = NO_KILLER_PREFIX;
  539. X
  540. X    /* paybill() must be called unconditionally, or strange things will
  541. X     * happen to bones levels */
  542. X    taken = paybill(how != QUIT);
  543. X    paygd();
  544. X    clearlocks();
  545. X#ifdef AMIGA
  546. X    clear_icon();
  547. X#endif
  548. X    if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE);
  549. X
  550. X    if (flags.end_disclose && how != PANICKED) disclose(how,taken);
  551. X
  552. X    if (how < GENOCIDED) {
  553. X#ifdef WIZARD
  554. X        if (!wizard || yn("Save bones?") == 'y')
  555. X#endif
  556. X        savebones();
  557. X    }
  558. X
  559. X    /* clean up unneeded windows */
  560. X    if (have_windows) {
  561. X        destroy_nhwindow(WIN_MAP);
  562. X        destroy_nhwindow(WIN_STATUS);
  563. X        destroy_nhwindow(WIN_MESSAGE);
  564. X
  565. X        if(!done_stopprint || flags.tombstone)
  566. X        endwin = create_nhwindow(NHW_TEXT);
  567. X
  568. X        if(how < GENOCIDED && flags.tombstone) outrip(how, endwin);
  569. X    } else
  570. X        done_stopprint = 1; /* just avoid any more output */
  571. X
  572. X/* changing kilbuf really changes killer. we do it this way because
  573. X   killer is declared a (const char *)
  574. X*/
  575. X    if (u.uhave.amulet) Strcat(kilbuf, " (with the Amulet)");
  576. X    if (!done_stopprint) {
  577. X        Sprintf(pbuf, "%s %s the %s...",
  578. X           (pl_character[0]=='S') ? "Sayonara" : "Goodbye", plname,
  579. X           how != ASCENDED ? (const char *) pl_character :
  580. X           (const char *) (flags.female ? "Demigoddess" : "Demigod"));
  581. X        putstr(endwin, 0, pbuf);
  582. X        putstr(endwin, 0, "");
  583. X    }
  584. X    {   long tmp;
  585. X        int deepest = deepest_lev_reached(FALSE);
  586. X
  587. X        u.ugold += hidden_gold();    /* accumulate gold from containers */
  588. X        tmp = u.ugold - u.ugold0;
  589. X        if (tmp < 0L)
  590. X        tmp = 0L;
  591. X        if (how < PANICKED)
  592. X        tmp -= tmp / 10L;
  593. X        u.urexp += tmp;
  594. X        u.urexp += 50L * (long)(deepest - 1);
  595. X        if (deepest > 20)
  596. X        u.urexp += 1000L * (long)((deepest > 30) ? 10 : deepest - 20);
  597. X        if (how == ASCENDED) u.urexp *= 2L;
  598. X    }
  599. X    if (how == ESCAPED || how == ASCENDED) {
  600. X        register struct monst *mtmp;
  601. X        register struct obj *otmp;
  602. X        struct obj *jewels;
  603. X        long i;
  604. X        register long worthlessct = 0;
  605. X
  606. X        /*
  607. X         *  Put items that count into the jewels chain.  Rewriting
  608. X         *  the invent chain and all the container chains (within
  609. X         *  invent) here is safe.  They will never be used again.
  610. X         */
  611. X        jewels = get_valuables(invent);
  612. X
  613. X        /* add points for jewels */
  614. X        for(otmp = jewels; otmp; otmp = otmp->nobj) {
  615. X            if(otmp->oclass == GEM_CLASS)
  616. X                u.urexp += otmp->quan *
  617. X                        objects[otmp->otyp].oc_cost;
  618. X            else    /* amulet */
  619. X                u.urexp += objects[otmp->otyp].oc_cost;
  620. X        }
  621. X
  622. X        keepdogs();
  623. X        viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */
  624. X        mtmp = mydogs;
  625. X        if(!done_stopprint) Strcpy(pbuf, "You");
  626. X        if(mtmp) {
  627. X            while(mtmp) {
  628. X                if(!done_stopprint) {
  629. X                    Strcat(pbuf, " and ");
  630. X                    Strcat(pbuf, mon_nam(mtmp));
  631. X                }
  632. X                if(mtmp->mtame)
  633. X                    u.urexp += mtmp->mhp;
  634. X                mtmp = mtmp->nmon;
  635. X            }
  636. X            if(!done_stopprint)
  637. X                putstr(endwin, 0, pbuf);
  638. X            pbuf[0] = 0;
  639. X        } else {
  640. X            if(!done_stopprint)
  641. X                Strcat(pbuf, " ");
  642. X        }
  643. X        if(!done_stopprint) {
  644. X            Sprintf(eos(pbuf),
  645. X                "%s with %ld point%s,",
  646. X                how==ASCENDED ? "went to your reward"
  647. X                : "escaped from the dungeon",
  648. X                u.urexp, plur(u.urexp));
  649. X            putstr(endwin, 0, pbuf);
  650. X        }
  651. X
  652. X        /* print jewels chain here */
  653. X        for(otmp = jewels; otmp; otmp = otmp->nobj) {
  654. X            makeknown(otmp->otyp);
  655. X            if(otmp->oclass == GEM_CLASS &&
  656. X               otmp->otyp < LUCKSTONE) {
  657. X                i = otmp->quan *
  658. X                    objects[otmp->otyp].oc_cost;
  659. X                if(i == 0) {
  660. X                    worthlessct += otmp->quan;
  661. X                    continue;
  662. X                }
  663. X            } else {        /* amulet */
  664. X                otmp->known = 1;
  665. X                i = objects[otmp->otyp].oc_cost;
  666. X            }
  667. X            if(!done_stopprint) {
  668. X                Sprintf(pbuf, "        %s (worth %ld zorkmids),",
  669. X                    doname(otmp), i);
  670. X                putstr(endwin, 0, pbuf);
  671. X            }
  672. X        }
  673. X        if(worthlessct && !done_stopprint) {
  674. X            Sprintf(pbuf,
  675. X              "        %ld worthless piece%s of colored glass,",
  676. X              worthlessct, plur(worthlessct));
  677. X            putstr(endwin, 0, pbuf);
  678. X        }
  679. X    } else if (!done_stopprint) {
  680. X        Strcpy(pbuf, "You ");
  681. X        Strcat(pbuf, ends[how]);
  682. X        if (how != ASCENDED) {
  683. X            Strcat(pbuf, " in ");
  684. X            if (Is_astralevel(&u.uz))
  685. X            Strcat(pbuf, "The Astral Plane");
  686. X            else Strcat(pbuf, dungeons[u.uz.dnum].dname);
  687. X            Strcat(pbuf, " ");
  688. X            if (!In_endgame(&u.uz)
  689. X#ifdef MULDGN
  690. X                           && !Is_knox(&u.uz)
  691. X#endif
  692. X            )
  693. X            Sprintf(eos(pbuf), "on dungeon level %d ", (
  694. X#ifdef MULDGN
  695. X                         In_quest(&u.uz) ?
  696. X                            dunlev(&u.uz) :
  697. X#endif
  698. X                            depth(&u.uz)));
  699. X        }
  700. X        Sprintf(eos(pbuf),
  701. X            "with %ld point%s,", u.urexp, plur(u.urexp));
  702. X        putstr(endwin, 0, pbuf);
  703. X    }
  704. X    if (!done_stopprint) {
  705. X        Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.",
  706. X            u.ugold, plur(u.ugold), moves, plur(moves));
  707. X        putstr(endwin, 0, pbuf);
  708. X    }
  709. X    if (!done_stopprint) {
  710. X        Sprintf(pbuf,
  711. X         "You were level %u with a maximum of %d hit point%s when you %s.",
  712. X            u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]);
  713. X        putstr(endwin, 0, pbuf);
  714. X        putstr(endwin, 0, "");
  715. X    }
  716. X#if (defined(WIZARD) || defined(EXPLORE_MODE))
  717. X# ifndef LOGFILE
  718. X    if (wizard || discover) {
  719. X        if (!done_stopprint) {
  720. X        putstr(endwin, 0, "");
  721. X        Sprintf(pbuf, "Since you were in %s mode, the score list \
  722. Xwill not be checked.", wizard ? "wizard" : "discover");
  723. X        putstr(endwin, 0, pbuf);
  724. X        putstr(endwin, 0, "");
  725. X        display_nhwindow(endwin, TRUE);
  726. X        }
  727. X        if (have_windows)
  728. X        exit_nhwindows(NULL);
  729. X    } else
  730. X# endif
  731. X#endif
  732. X    {
  733. X        if (!done_stopprint)
  734. X        display_nhwindow(endwin, TRUE);
  735. X        if (have_windows)
  736. X        exit_nhwindows(NULL);
  737. X/* "So when I die, the first thing I will see in Heaven is a score list?" */
  738. X        topten(how);
  739. X    }
  740. X    if(done_stopprint) { raw_print(""); raw_print(""); }
  741. X    terminate(0);
  742. X}
  743. X
  744. X
  745. X#ifdef NOSAVEONHANGUP
  746. Xint
  747. Xhangup()
  748. X{
  749. X    (void) signal(SIGINT, SIG_IGN);
  750. X    clearlocks();
  751. X# ifndef VMS
  752. X    terminate(1);
  753. X# endif
  754. X}
  755. X#endif
  756. X
  757. X
  758. Xvoid
  759. Xcontainer_contents(list, identified, all_containers)
  760. X    struct obj *list;
  761. X    boolean identified, all_containers;
  762. X{
  763. X    register struct obj *box, *obj;
  764. X    char buf[BUFSZ];
  765. X
  766. X    for (box = list; box; box = box->nobj) {
  767. X        if (Is_container(box) && box->otyp != BAG_OF_TRICKS) {
  768. X        if (box->cobj) {
  769. X            winid tmpwin = create_nhwindow(NHW_MENU);
  770. X            Sprintf(buf, "Contents of the %s:", xname(box));
  771. X            putstr(tmpwin, 0, buf); putstr(tmpwin, 0, "");
  772. X            for (obj = box->cobj; obj; obj = obj->nobj) {
  773. X            if (identified) {
  774. X                makeknown(obj->otyp);
  775. X                obj->known = obj->bknown = obj->dknown = 1;
  776. X            }
  777. X            putstr(tmpwin, 0, doname(obj));
  778. X            }
  779. X            display_nhwindow(tmpwin, TRUE);
  780. X            destroy_nhwindow(tmpwin);
  781. X            if (all_containers)
  782. X            container_contents(box->cobj, identified, TRUE);
  783. X        } else {
  784. X            pline("%s is empty.", The(xname(box)));
  785. X            display_nhwindow(WIN_MESSAGE, FALSE);
  786. X        }
  787. X        }
  788. X        if (!all_containers)
  789. X        break;
  790. X    }
  791. X}
  792. X
  793. Xvoid
  794. Xterminate(status)
  795. Xint status;
  796. X{
  797. X#ifdef MAC
  798. X    if (!hu) {
  799. X        int idx;
  800. X        for (idx = theWindows[BASE_WINDOW].windowTextLen; --idx >= 0; )
  801. X            /* If there is something to show... */
  802. X            if (((unsigned char *)*theWindows[BASE_WINDOW].windowText)[idx] > ' ') {
  803. X                display_nhwindow(BASE_WINDOW, TRUE);
  804. X                break;
  805. X            }
  806. X    }
  807. X#endif
  808. X    exit(status);
  809. X}
  810. X
  811. X/*end.c*/
  812. END_OF_FILE
  813. if test 17434 -ne `wc -c <'src/end.c'`; then
  814.     echo shar: \"'src/end.c'\" unpacked with wrong size!
  815. fi
  816. # end of 'src/end.c'
  817. fi
  818. if test -f 'sys/msdos/maintovl.doc' -a "${1}" != "-c" ; then 
  819.   echo shar: Will not clobber existing file \"'sys/msdos/maintovl.doc'\"
  820. else
  821. echo shar: Extracting \"'sys/msdos/maintovl.doc'\" \(17990 characters\)
  822. sed "s/^X//" >'sys/msdos/maintovl.doc' <<'END_OF_FILE'
  823. X    SCCS Id: @(#)maintovl.doc     3.1        92/11/23
  824. X        Copyright (c) NetHack PC Development Team 1990, 1991, 1992, 1993.
  825. X        NetHack may be freely redistributed.  See license for details.
  826. X             ===========================
  827. X            Maintaining PC NetHack
  828. X             ===========================
  829. X             Last revision: 1992november23
  830. X
  831. XThe installation of the system of overlay management that currently
  832. Xbrings full-featured NetHack to the IBM PC and compatibles has
  833. Xintroduced a number of arcanities into the source code of the
  834. Xprogramme, and unfortunately running afoul of these intricacies can
  835. Xresult (as we ourselves have discovered) in the most bizarre and
  836. Xstrangely inexplicable dysfunctional manifestations, aka sick bugs.
  837. X
  838. XThis document is required reading for anyone making substantive
  839. Xchanges to NetHack for the PC or embarking upon a revision of its
  840. Xoverlay structure.
  841. X
  842. X
  843. X1. The overlay manager
  844. X----------------------
  845. XNetHack is by now a fairly large programme (in excess of 800
  846. Xkilobytes), and in order to compile it for the PC (which typically
  847. Xhas little more than 500k of available memory) it was necessary to
  848. Xrely on the technique of _overlaying_, whereby not all the
  849. Xprogramme is resident in memory at the same time, segments of the
  850. Xprogramme being loaded and discarded as they are needed. Unlike
  851. Xtraditional candidates for the overlaying strategy, however, NetHack
  852. Xdoes not exhibit strongly phased behaviour; although much of the code
  853. Xis not being used at any one moment, there is comparatively little
  854. Xcode that can confidently be said not to be related to or potentially
  855. Xnecessary for the immediate progress of the game.
  856. X    Furthermore we wished to develop an overlaying strategy that
  857. Xdid _not_ involve intimate knowledge of the operation of the
  858. Xprogramme (since NetHack is an international team effort, and few
  859. Xpeople have a good feeling for the totality of the code structure),
  860. Xand which would not require substantive changes to the source code,
  861. Ximpacting on its maintainability and portability.
  862. X    It turned out to be impossible to satisfy these goals with
  863. Xtools that are widely available at the time of writing, and so we
  864. Xundertook to write our own overlay manager (compatible with
  865. XMicrosoft's, but more in concert with NetHack's particular needs).
  866. XThe result is called ovlmgr.asm and is documented in the file
  867. Xovlmgr.doc. You would probably be well advised to read at least the
  868. Xless technical parts of that file now.
  869. X
  870. X
  871. X2. The trampoli mechanism
  872. X-------------------------
  873. XOne of the difficulties with using overlays for C (particularly
  874. XMicrosoft C) is that while common C programming practise places heavy
  875. Xreliance on function pointers, Microsoft's overlay linker is unable
  876. Xto resolve calls through pointers to functions that are in remote
  877. Xoverlays. Nor, unfortunately, does it choose to report such failures;
  878. Xrather, it generates calls into (what often turns out to be in the
  879. Xcase of our nonstandard overlay manager) the deepest of space. This
  880. Xcan result in truly strange behaviour on the part of your programme -
  881. Xincluding bugs that come and go in as close to a random pattern as
  882. Xyou are ever likely to see.
  883. X    Other than the creative use of pattern-matching utilities
  884. Xsuch as grep to locate the offending calls, there is unfortunately no
  885. Xadvice we can offer in tracking down these bugs. Once they have been
  886. Xisolated, however, they can be remedied straightforwardly.
  887. X
  888. XIn order for the linker not to screw up on a pointered function call
  889. Xit is (to simplify an actually rather complicated situation)
  890. Xnecessary that the function called be located in the ROOT "overlay",
  891. Xand thus not be subject to swapping. Rather than linking the full
  892. Xtext of every pointered function into the root, however, it suffices
  893. Xto place a "trampoline" function there which performs a direct call
  894. Xto the "real" function that does the work, in whatever overlay it
  895. Xmight naturally reside in. Due to a not-quite-accident of the
  896. Xbehaviour of the C preprocessor (it was originally intended to make
  897. Xpossible functions whose address can be taken but which expand inline
  898. Xas macros where possible, a not unrelated function), it turns out to
  899. Xbe possible to arrange for this without major change to the C source
  900. Xcode - and without serious impact on the performance of "regular"
  901. Xcalls to the same functions.
  902. X
  903. XThe C preprocessor's expansion of a macro with parameters is triggered
  904. Xby an encounter with the macro name immediately followed by an open
  905. Xparenthesis. If the name is found, but it is not followed by a
  906. Xparenthesis, the macro is not matched and no expansion takes place.
  907. XAt the same time it may be noted that (unless someone has been oddly
  908. Xstrange and enclosed a function name in quite unneeded parentheses!),
  909. Xa function name is typically followed by an open parenthesis if, and
  910. Xonly if, it is being declared, defined or invoked; if its address is
  911. Xbeing taken it will necessarily be followed by some other token.
  912. XFurthermore it will be observed that (except in the unfortunate case
  913. Xof the ill-conceived new-style ANSI declaration of a function that
  914. Xtakes no parameters) the number of parameters to a call of the
  915. Xfunction (assuming that this number is fixed; if not, I grant, we have
  916. Xa problem) is the same in all these contexts. This implies that if all
  917. Xthe modules of a programme are uniformly processed in the context of a
  918. Xmacro definition such as
  919. X
  920. X    #define zook(a,b) plenk(a,b)
  921. X
  922. Xand assuming that all functions named zook() take exactly two
  923. Xarguments, then the resulting programme will be completely identical
  924. Xto the original (without this definition) except that the link
  925. Xmap will report the existence of the function plenk() in place of
  926. Xzook() -- UNLESS there was a place in the programme where the address
  927. Xof zook was taken. In that case, the linker would report an
  928. Xunresolved external reference for zook.
  929. X    That unresolved reference is, of course, precisely what we
  930. Xneed; if in another source file (one that did not see the macro
  931. Xdefinition) we placed the function definition
  932. X
  933. X    some_t zook(this_t a, that_t b)
  934. X      { extern some_t plenk(this_t, that_t);
  935. X        return plenk(a, b);
  936. X      }
  937. X
  938. Xthis would both satisfy the unresolved reference and restore the
  939. Xoriginal semantics of the programme (even including pointer
  940. Xcomparison!) -- while providing us with precisely the kind of
  941. X"trampoline" module that we need to circumvent the problem with the
  942. Xlinker.
  943. X    This is the basis of the approach we have taken in PC
  944. XNetHack; rather than using the somewhat idiosyncratic identifier
  945. X"plenk", however, we have systematically employed (in the files
  946. Xtrampoli.h and trampoli.c) identifiers generated by appending
  947. Xunderscores to the ends of the names of the functions we have needed
  948. Xto so indirect(1).
  949. X
  950. XThere are a few small complications. The first is ensuring that both
  951. Xthe versions of the trampoli'd function (foo() and foo_()) are
  952. Xsimilarly typed by the appropriate extern declarations (which
  953. Xthemselves must be written); this can be accomplished by placing all
  954. Xof these declarations in a header file that is processed _twice_,
  955. Xonce before and once after the inclusion of the file containing the
  956. Xtrampoli macro definitions, thereby ensuring that both variants of
  957. Xthe name have been seen in connection with the appropriate types. The
  958. Xsecond is that some care must be exercised not to employ other macros
  959. Xthat interfere with the normal recognition of function syntax: it is
  960. Xthe presence of the open parenthesis after the name of the function
  961. Xthat triggers name substitution, and not the fact that the function
  962. Xis called; and so (particularly in the case of declarations) it is
  963. Xnecessary that if a macro is used to supply the _arguments_ of a
  964. Xtrampoli'd function, it must also supply the name (this necessity in
  965. Xfact triggered a change in the style of the macros that provide
  966. Xdialect-independent function declaration in NetHack; the new style
  967. Xwould have you write FDECL(functionName, (argTypes...)).
  968. X    Finally, there is the case of functions declared to take no
  969. Xarguments whatsoever; in Standard C this is notated:
  970. X
  971. X    some_t aFunction(void);
  972. X
  973. Xfor no theoretically well-motivated reason I can discern. Such a
  974. Xdeclaration will _not_ match a macro definition such as
  975. X
  976. X    #define aFunction() aFunction_()
  977. X
  978. X-- in fact the compiler will detect an error when processing that
  979. Xdeclaration in the scope of this macro. The only solution is to
  980. Xeschew the use of this strange syntax and unfrabjously forgo the
  981. Xconcomitant security of well- and thoroughly- checked typage. To
  982. Xwhich end we have provided an ecchy macro, NDECL(functionName), which
  983. Xuses the new syntax _unless_ the compiler is not Standard or OVERLAY
  984. Xis enabled.
  985. X
  986. XThere is one further consideration: that this technique only applies,
  987. Xof course, to functions that are published to the linker. For this
  988. Xreason, wherever such trampoli'd functions were originally declared
  989. Xstatic, that declaration has been changed to "STATIC_PTR", a macro
  990. Xthat expands to "static" unless the OVERLAY flag has been selected in
  991. Xthe configuration file, enabling the trampoli mechanism. Thus such
  992. Xfunctions lose their privacy in this one case.
  993. X
  994. X
  995. X3. OVLx
  996. X-------
  997. XThe strategies described above work fine, but they only stretch so
  998. Xfar. In particular, they do not admit of an overlay structure in
  999. Xwhich functions are linked into different overlays even though they
  1000. Xoriginate in the same source file.
  1001. X    Classically, this is not considered a real limitation,
  1002. Xbecause one has the freedom to regroup the functions into different
  1003. Xsource files as needed; however, in the case of NetHack this was not
  1004. Xa realistic option, since what structure this unwieldy programme has
  1005. Xis precisely in the current grouping of functions together.
  1006. XNonetheless, the ability to perform some functional grouping is an
  1007. Xabsolute requirement for acceptable performance, since many NetHack
  1008. Xsource modules (were.c, for example) contain one or two tiny
  1009. Xfunctions that are called with great frequency (several millions of
  1010. Xtimes per game is not unheard of) and whose return value determines
  1011. Xwhether the remaining large, slow functions of the file will be
  1012. Xrequired at all in the near future. Obviously these small checking
  1013. Xfunctions should be linked into the same overlays with their callers,
  1014. Xwhile the remainder of the source module should not.
  1015. X
  1016. XIn order to make this possible we ran a dynamic profile on the game
  1017. Xto determine exactly which functions in which modules required such
  1018. Xdistinguished treatment, and we have flagged each function for
  1019. Xconditional compilation (with #if ... #endif) in groups according
  1020. Xapproximately to their frequency of invocation and functionality.
  1021. XThese groups have been arbitrarily named in each source file (in
  1022. Xdecreasing order of frequency), OVL0, OVL1, OVL2, OVL3 and OVLB (B
  1023. Xfor "base functions", those that deserve no special treatment at
  1024. Xall). It is thus possible to compile only a small number of the
  1025. Xfunctions in a file by defining but one or two of these symbols on
  1026. Xthe compiler's command line (with the switch /DOVL2, for example);
  1027. Xthe compiler will ignore the remainder as if they did not exist.
  1028. X(There is an "escape clause" in hack.h that ensures that if none of
  1029. Xthese flags is defined on the command line, then all of them will be
  1030. Xduring compilation; this makes the non-use of this mechanism
  1031. Xstraightforward!)
  1032. X    By repeated invocation of the compiler on the _same_ source
  1033. Xfile it is possible to accumulate disjoint object modules that
  1034. Xbetween them contain the images of all the functions in the original
  1035. Xsource, but partitioned as is most convenient. Care must, of course,
  1036. Xbe taken over conflicts of name in both the object file put out (all
  1037. Xslices will by default be called SRCFILE.OBJ, and this default must
  1038. Xbe overridden with distinct file names for each output slice) and in
  1039. Xthe names of the text segments the compiler is to generate; you can
  1040. Xsee this at work in Makefile.ovl. (You may wonder, as we did at
  1041. Xfirst, why the text segment name would have to be made distinct in
  1042. Xeach object file slice (the default segment name is a function of the
  1043. Xsource file name and the compilation model only). The reason for this
  1044. Xis, quite daftly to my mind, that the linker considers the identity
  1045. Xof segment names and combine classes better reason to combine
  1046. Xsegments than the programmer's explicit instructions in the requested
  1047. Xoverlay pattern is reason to keep them apart. Programmer, ask not
  1048. Xwhy...).
  1049. X
  1050. XOnce again, that works fine except for the small matter of
  1051. Xdeclarations (where have we heard this before?). For objects that
  1052. Xonce were static must now be made visible to the linker that they may
  1053. Xbe resolved across the reaches of inter-overlay space. To this end we
  1054. Xhave provided three macros, all of which expand simply to "static" if
  1055. Xno OVLx flags are defined on the compilation command line. They are:
  1056. X
  1057. XSTATIC_DCL    which introduces a declaration (as distinct from a
  1058. X        definition) of an object that would be static were it
  1059. X        not for the requirements of the OVLx mechanism. Its
  1060. X        expansion is "static", normally, but it becomes
  1061. X        "extern" in the event that this source file has been
  1062. X        split into slices with the OVLx mechanism.
  1063. X
  1064. XSTATIC_OVL    is used when _defining_ a function (giving its text,
  1065. X        that is) that is logically static but may be called
  1066. X        across slices; it expands to "static" unless OVLx is
  1067. X        active; in the latter case it expands to null,
  1068. X        leaving the function with "previous linkage" as the
  1069. X        standard says. Note that this behaviour is quite
  1070. X        similar to, but very different from, that of
  1071. X        STATIC_PTR (described above), which has the same two
  1072. X        expansions but which is triggered not by OVLx but by
  1073. X        the OVERLAY flag which enables the trampoli mechanism.
  1074. X            STATIC_OVL also differs from the STATIC_DCL
  1075. X        and STATIC_VAR in that it is employed _within_ OVLx
  1076. X        slices, while the others are used to generate
  1077. X        declarations and are deployed in areas common to all
  1078. X        slices.
  1079. X
  1080. XSTATIC_VAR    is used to introduce uninitialised would-be-static
  1081. X        variables. Its expansion is complex, since it must
  1082. X        read as "static" in the usual case, but as "extern"
  1083. X        if OVLx is in use -- in all overlays but one, where
  1084. X        it must expand to the null sequence -- giving it
  1085. X        "previous linkage" and "tentative definition" (to
  1086. X        ensure that the variable gets defined at all).
  1087. X            This one took a while to get right, and
  1088. X        believe me, using the macro is a lot easier than
  1089. X        trying to keep the #ifdefs straight yourself!
  1090. X
  1091. XAn initialised variable that is file-level static unless OVLx is in
  1092. Xuse must now be written with a STATIC_DCL declaration, and a
  1093. Xdefinition (and static initialiser) enclosed within the bracketing
  1094. Xtag of one of the OVLx slices (any will do; we use OVLB).
  1095. X    Type definitions, macro definitions and extern declarations
  1096. Xshould, of course remain outside any OVLx slice.
  1097. X
  1098. XFinally, of course, objects whose visibility need not be extended may
  1099. Xsafely continue to be declared static. And in this case, at least,
  1100. Xthe compiler will provide diagnostics that inform you when an object
  1101. Xhas slipped through the cracks and requires the application of Magic
  1102. XMacro Salve.
  1103. X
  1104. XIt is perhaps less than obvious that when a function is _both_ called
  1105. Xacross an OVLx split and referenced through a pointer, it should be
  1106. Xtreated as a pointered function (that is, it should get trampoli
  1107. Xentries and should be defined STATIC_PTR). The reason for this is that
  1108. Xthe STATIC_xxx macros associated with OVLx _only_ change the
  1109. Xdeclaration patterns of the objects, while trampoli results in the
  1110. Xgeneration of necessary code.
  1111. X    It is correct to do this, because the declarations produced by
  1112. XSTATIC_PTR are triggered by OVERLAY's being defined, and the selection
  1113. Xof OVERLAY is an absolute precondition for the activation of OVLx.
  1114. X
  1115. X
  1116. X4. Hacking
  1117. X----------
  1118. XBefore undertaking any serious modifications to the overlay structure
  1119. Xor support mechanisms, you should know that a _lot_ of work has gone
  1120. Xinto the current scheme. If performance seems poor, remember: the
  1121. Xoverlay manager itself can be invoked up to ten thousand times in a
  1122. Xsecond, and although the space available for loading overlays (once
  1123. Xthe data and stack spaces have been accounted for) is less than half
  1124. Xthe total size of the overlays that are swapped through it, a disk
  1125. Xaccess occurs well under 0.1% of the time(2). Furthermore, this
  1126. Xperformance (such as it is) has been achieved without substantive
  1127. Xchange or restructuring of the NetHack source code, which must remain
  1128. Xportable to many platforms other than the PC.
  1129. X
  1130. XIf these observations do not daunt you, you are a Bit Warrior indeed
  1131. X(or aspiration anyway), and we await your comments with bait.
  1132. X
  1133. X------------------------------------------------------------------------
  1134. X
  1135. XNOTES:
  1136. X------
  1137. X
  1138. X(1) In fact, we have applied this technique throughout NetHack, even
  1139. X    in cases where it is not strictly necessary (since the pointered
  1140. X    calls are not across overlay splits, for example - though note
  1141. X    that there are more splits than might be initially apparent, due
  1142. X    to the effects of the OVLx hackage as described in section 3).
  1143. X    There is, however, one exception; and beware: it is an exception
  1144. X    with fangs. The file termcap.c contains a few pointered functions
  1145. X    that we decided _not_ to trampoli for performance reasons (screen
  1146. X    output is one of the problem areas on the PC port at the moment,
  1147. X    in terms of performance). It is therefore vital to the health of
  1148. X    PC NetHack as it currently stands that the OVLx slice termcap.0 be
  1149. X    linked into the ROOT "overlay".
  1150. X
  1151. X(2) These figures are for a 4.77 MHz PC-XT running in low memory with
  1152. X    an older version of both the overlay manager and the NetHack
  1153. X    overlay arrangement. On a more capable computer and with the
  1154. X    current software, the figures are probably more like a 100kHz peak
  1155. X    service rate and a hit rate (since we fixed the bug in the LRU
  1156. X    clock logic!) in excess of 99.99% -- hopefully not both at the
  1157. X    same time.
  1158. X
  1159. X------------------------------------------------------------------------
  1160. XStephen P Spackman                         stephen@estragon.uchicago.edu
  1161. X------------------------------------------------------------------------
  1162. X                 * Hack On! *
  1163. END_OF_FILE
  1164. if test 17990 -ne `wc -c <'sys/msdos/maintovl.doc'`; then
  1165.     echo shar: \"'sys/msdos/maintovl.doc'\" unpacked with wrong size!
  1166. fi
  1167. # end of 'sys/msdos/maintovl.doc'
  1168. fi
  1169. if test -f 'win/X11/winmesg.c' -a "${1}" != "-c" ; then 
  1170.   echo shar: Will not clobber existing file \"'win/X11/winmesg.c'\"
  1171. else
  1172. echo shar: Extracting \"'win/X11/winmesg.c'\" \(16667 characters\)
  1173. sed "s/^X//" >'win/X11/winmesg.c' <<'END_OF_FILE'
  1174. X/*    SCCS Id: @(#)winmesg.c    3.1    92/05/19          */
  1175. X/* Copyright (c) Dean Luick, 1992                  */
  1176. X/* NetHack may be freely redistributed.  See license for details. */
  1177. X
  1178. X/*
  1179. X * Message window routines.
  1180. X *
  1181. X * Global functions:
  1182. X *    set_message_height()
  1183. X *    create_message_window()
  1184. X *    destroy_message_window()
  1185. X *    display_message_window()
  1186. X *    append_message()
  1187. X */
  1188. X#include <X11/Intrinsic.h>
  1189. X#include <X11/StringDefs.h>
  1190. X#include <X11/Shell.h>
  1191. X#include <X11/Xaw/Cardinals.h>
  1192. X#include <X11/Xaw/Viewport.h>
  1193. X#include "Window.h"    /* Window widget declarations */
  1194. X
  1195. X#include "hack.h"
  1196. X#include "winX.h"
  1197. X
  1198. Xstatic const char message_translations[] =
  1199. X    "#override\n\
  1200. X    <Key>: no-op()";
  1201. X
  1202. Xstatic struct line_element *get_previous();
  1203. Xstatic void set_circle_buf();
  1204. Xstatic char *split();
  1205. Xstatic void add_line();
  1206. Xstatic void redraw_message_window();
  1207. Xstatic void mesg_check_size_change();
  1208. Xstatic void mesg_exposed();
  1209. Xstatic void get_gc();
  1210. Xstatic void mesg_resized();
  1211. X
  1212. X/* Adjust the number of rows on the given message window. */
  1213. Xvoid
  1214. Xset_message_height(wp, rows)
  1215. X    struct xwindow *wp;
  1216. X    Dimension rows;
  1217. X{
  1218. X    Arg args[1];
  1219. X
  1220. X    wp->pixel_height = wp->mesg_information->char_height * rows;
  1221. X
  1222. X    XtSetArg(args[0], XtNheight, wp->pixel_height);
  1223. X    XtSetValues(wp->w, args, ONE);
  1224. X}
  1225. X
  1226. X/* Move the message window's vertical scrollbar's slider to the bottom. */
  1227. Xvoid
  1228. Xset_message_slider(wp)
  1229. X    struct xwindow *wp;
  1230. X{
  1231. X    Widget scrollbar;
  1232. X    float top;
  1233. X
  1234. X    scrollbar = XtNameToWidget(XtParent(wp->w), "vertical");
  1235. X
  1236. X    if (scrollbar) {
  1237. X    top = 1.0;
  1238. X    XtCallCallbacks(scrollbar, XtNjumpProc, &top);
  1239. X    }
  1240. X}
  1241. X
  1242. X
  1243. Xvoid
  1244. Xcreate_message_window(wp, create_popup, parent)
  1245. X    struct xwindow *wp;            /* window pointer */
  1246. X    boolean create_popup;
  1247. X    Widget parent;
  1248. X{
  1249. X    Arg args[8];
  1250. X    Cardinal num_args;
  1251. X    Widget viewport;
  1252. X    struct mesg_info_t *mesg_info;
  1253. X
  1254. X    wp->type = NHW_MESSAGE;
  1255. X
  1256. X    wp->mesg_information = mesg_info =
  1257. X            (struct mesg_info_t *) alloc(sizeof(struct mesg_info_t));
  1258. X
  1259. X    mesg_info->fs = 0;
  1260. X    mesg_info->num_lines = 0;
  1261. X    mesg_info->head = mesg_info->last_pause =
  1262. X            mesg_info->last_pause_head = (struct line_element *) 0;
  1263. X    mesg_info->dirty = False;
  1264. X    mesg_info->viewport_width = mesg_info->viewport_height = 0;
  1265. X
  1266. X    /*
  1267. X     * We should have an .Xdefaults option that specifies the number of lines
  1268. X     * to be displayed.  Until then, we'll use DEFAULT_LINES_DISPLAYED.
  1269. X     * E.g.:
  1270. X     *
  1271. X     *    if (a lines value from .Xdefaults exists)
  1272. X     *        lines_displayed = lines value from .Xdefaults;
  1273. X     *    else
  1274. X     *        lines_displayed = DEFAULT_LINES_DISPLAYED;
  1275. X     */
  1276. X    if (flags.msg_history < DEFAULT_LINES_DISPLAYED)
  1277. X    flags.msg_history = DEFAULT_LINES_DISPLAYED;
  1278. X    if (flags.msg_history > MAX_HISTORY)    /* a sanity check */
  1279. X    flags.msg_history = MAX_HISTORY;
  1280. X
  1281. X    set_circle_buf(mesg_info, (int) flags.msg_history);
  1282. X
  1283. X    /* Create a popup that becomes the parent. */
  1284. X    if (create_popup) {
  1285. X    num_args = 0;
  1286. X    XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
  1287. X
  1288. X    wp->popup = parent = XtCreatePopupShell("message_popup",
  1289. X                    topLevelShellWidgetClass,
  1290. X                    toplevel, args, num_args);
  1291. X    }
  1292. X
  1293. X    /*
  1294. X     * Create the viewport.  We only want the vertical scroll bar ever to be
  1295. X     * visible.  If we allow the horizontal scrollbar to be visible it will
  1296. X     * always be visible, due to the stupid way the Athena viewport operates.
  1297. X     */
  1298. X    num_args = 0;
  1299. X    XtSetArg(args[num_args], XtNallowVert,  True);      num_args++;
  1300. X    viewport = XtCreateManagedWidget(
  1301. X                        "mesg_viewport",         /* name */
  1302. X                        viewportWidgetClass,    /* widget class from Window.h */
  1303. X                        parent,                 /* parent widget */
  1304. X                        args,                   /* set some values */
  1305. X                        num_args);              /* number of values to set */
  1306. X
  1307. X    /*
  1308. X     * Create a message window.  We will change the width and height once
  1309. X     * we know what font we are using.
  1310. X     */
  1311. X    num_args = 0;
  1312. X    XtSetArg(args[num_args], XtNtranslations,
  1313. X    XtParseTranslationTable(message_translations));    num_args++;
  1314. X    wp->w = XtCreateManagedWidget(
  1315. X        "message",        /* name */
  1316. X        windowWidgetClass,    /* widget class from Window.h */
  1317. X        viewport,        /* parent widget */
  1318. X        args,            /* set some values */
  1319. X        num_args);        /* number of values to set */
  1320. X
  1321. X    XtAddCallback(wp->w, XtNexposeCallback, mesg_exposed, (XtPointer) 0);
  1322. X
  1323. X    /*
  1324. X     * Now adjust the height and width of the message window so that it
  1325. X     * is DEFAULT_LINES_DISPLAYED high and DEFAULT_MESSAGE_WIDTH wide.
  1326. X     */
  1327. X
  1328. X    /* Get the font information. */
  1329. X    num_args = 0;
  1330. X    XtSetArg(args[num_args], XtNfont, &mesg_info->fs);           num_args++;
  1331. X    XtGetValues(wp->w, args, num_args);
  1332. X
  1333. X    /* Save character information for fast use later. */
  1334. X    mesg_info->char_width    = mesg_info->fs->max_bounds.width;
  1335. X    mesg_info->char_height   = mesg_info->fs->max_bounds.ascent +
  1336. X                        mesg_info->fs->max_bounds.descent;
  1337. X    mesg_info->char_ascent   = mesg_info->fs->max_bounds.ascent;
  1338. X    mesg_info->char_lbearing = -mesg_info->fs->min_bounds.lbearing;
  1339. X
  1340. X    get_gc(wp->w, mesg_info);
  1341. X
  1342. X    wp->pixel_height = DEFAULT_LINES_DISPLAYED * mesg_info->char_height;
  1343. X
  1344. X    /* If a variable spaced font, only use 2/3 of the default size */
  1345. X    if (mesg_info->fs->min_bounds.width != mesg_info->fs->max_bounds.width) {
  1346. X    wp->pixel_width  = ((2*DEFAULT_MESSAGE_WIDTH)/3) *
  1347. X                    mesg_info->fs->max_bounds.width;
  1348. X    } else
  1349. X    wp->pixel_width  = (DEFAULT_MESSAGE_WIDTH *
  1350. X                    mesg_info->fs->max_bounds.width);
  1351. X
  1352. X    /* Set the new width and height. */
  1353. X    num_args = 0;
  1354. X    XtSetArg(args[num_args], XtNwidth,        wp->pixel_width);  num_args++;
  1355. X    XtSetArg(args[num_args], XtNheight,       wp->pixel_height); num_args++;
  1356. X    XtSetValues(wp->w, args, num_args);
  1357. X
  1358. X    XtAddEventHandler(wp->w, KeyPressMask, False,
  1359. X              (XtEventHandler) msgkey, (XtPointer) 0);
  1360. X    XtAddCallback(wp->w, XtNresizeCallback, mesg_resized, (XtPointer) 0);
  1361. X
  1362. X    /*
  1363. X     * If we have created our own popup, then realize it so that the
  1364. X     * viewport is also realized.  Then resize the mesg window.
  1365. X     */
  1366. X    if (create_popup) {
  1367. X    XtRealizeWidget(wp->popup);
  1368. X    set_message_height(wp, (int) flags.msg_history);
  1369. X    }
  1370. X}
  1371. X
  1372. X
  1373. Xvoid
  1374. Xdestroy_message_window(wp)
  1375. X    struct xwindow *wp;
  1376. X{
  1377. X    if (wp->popup) {
  1378. X    nh_XtPopdown(wp->popup);
  1379. X    XtDestroyWidget(wp->popup);
  1380. X    set_circle_buf(wp->mesg_information, 0);    /* free buffer list */
  1381. X    free((char *)wp->mesg_information);
  1382. X    }
  1383. X    wp->type = NHW_NONE;
  1384. X}
  1385. X
  1386. X
  1387. X/* Redraw message window if new lines have been added. */
  1388. Xvoid
  1389. Xdisplay_message_window(wp)
  1390. X    struct xwindow *wp;
  1391. X{
  1392. X    if (wp->mesg_information->dirty) redraw_message_window(wp);
  1393. X}
  1394. X
  1395. X
  1396. X/*
  1397. X * Append a line of text to the message window.  Split the line if the
  1398. X * rendering of the text is too long for the window.
  1399. X */
  1400. Xvoid
  1401. Xappend_message(wp, str)
  1402. X    struct xwindow *wp;
  1403. X    const char *str;
  1404. X{
  1405. X    char *mark, *remainder, buf[BUFSZ];
  1406. X
  1407. X    if (!str) return;
  1408. X
  1409. X    Strcpy(buf, str);    /* we might mark it up */
  1410. X
  1411. X    remainder = buf;
  1412. X    do {
  1413. X    mark = remainder;
  1414. X    remainder = split(mark, wp->mesg_information->fs, wp->pixel_width);
  1415. X    add_line(wp->mesg_information, mark);
  1416. X    } while (remainder);
  1417. X}
  1418. X
  1419. X/* private functions ======================================================= */
  1420. X
  1421. X/*
  1422. X * Return the element in the circular linked list just before the given
  1423. X * element.
  1424. X */
  1425. Xstatic struct line_element *
  1426. Xget_previous(mark)
  1427. X    struct line_element *mark;
  1428. X{
  1429. X    struct line_element *curr;
  1430. X
  1431. X    if (!mark) return (struct line_element *) 0;
  1432. X
  1433. X    for (curr = mark; curr->next != mark; curr = curr->next)
  1434. X    ;
  1435. X    return curr;
  1436. X}
  1437. X
  1438. X
  1439. X/*
  1440. X * Set the information buffer size to count lines.  We do this by creating
  1441. X * a circular linked list of elements, each of which represents a line of
  1442. X * text.  New buffers are created as needed, old ones are freed if they
  1443. X * are no longer used.
  1444. X */
  1445. Xstatic void
  1446. Xset_circle_buf(mesg_info, count)
  1447. X    struct mesg_info_t *mesg_info;
  1448. X    int count;
  1449. X{
  1450. X    int i;
  1451. X    struct line_element *tail, *curr, *head;
  1452. X
  1453. X    if (count < 0) panic("set_circle_buf: bad count [= %d]", count);
  1454. X    if (count == mesg_info->num_lines) return;    /* no change in size */
  1455. X
  1456. X    if (count < mesg_info->num_lines) {
  1457. X    /*
  1458. X     * Toss num_lines - count line entries from our circular list.
  1459. X     *  
  1460. X     * We lose lines from the front (top) of the list.  We _know_
  1461. X     * the list is non_empty.
  1462. X     */
  1463. X    tail = get_previous(mesg_info->head);
  1464. X    for (i = mesg_info->num_lines - count;    i--; ) {
  1465. X        curr = mesg_info->head;
  1466. X        mesg_info->head = curr->next;
  1467. X        if (curr->line) free(curr->line);
  1468. X        free((genericptr_t)curr);
  1469. X    }
  1470. X    if (count == 0) {
  1471. X        /* make sure we don't have a dangling pointer */
  1472. X        mesg_info->head = (struct line_element *) 0;
  1473. X    } else {
  1474. X        tail->next = mesg_info->head;    /* link the tail to the head */
  1475. X    }
  1476. X    } else {
  1477. X    /*
  1478. X     * Add count - num_lines blank lines to the head of the list.
  1479. X     *
  1480. X     * Create a separate list, keeping track of the tail.
  1481. X     */
  1482. X    for (head = tail = 0, i = 0; i < count - mesg_info->num_lines; i++) {
  1483. X        curr = (struct line_element *) alloc(sizeof(struct line_element));
  1484. X        curr->line = 0;
  1485. X        curr->buf_length = 0;
  1486. X        curr->str_length = 0;
  1487. X        if (tail) {
  1488. X        tail->next = curr;
  1489. X        tail = curr;
  1490. X        } else {
  1491. X        head = tail = curr;
  1492. X        }
  1493. X    }
  1494. X    /*
  1495. X     * Complete the circle by making the new tail point to the old head
  1496. X     * and the old tail point to the new head.  If our line count was
  1497. X     * zero, then make the new list circular.
  1498. X     */
  1499. X    if (mesg_info->num_lines) {
  1500. X        curr = get_previous(mesg_info->head);/* get end of old list */
  1501. X
  1502. X        tail->next = mesg_info->head;    /* new tail -> old head */
  1503. X        curr->next = head;            /* old tail -> new head */
  1504. X    } else {
  1505. X        tail->next = head;
  1506. X    }
  1507. X    mesg_info->head = head;
  1508. X    }
  1509. X
  1510. X    mesg_info->num_lines = count;
  1511. X    /* Erase the line on a resize. */
  1512. X    mesg_info->last_pause = (struct line_element *) 0;
  1513. X}
  1514. X
  1515. X
  1516. X/*
  1517. X * Make sure the given string is shorter than the given pixel width.  If
  1518. X * not, back up from the end by words until we find a place to split.
  1519. X */
  1520. Xstatic char *
  1521. Xsplit(s, fs, pixel_width)
  1522. X    char *s;
  1523. X    XFontStruct *fs;        /* Font for the window. */
  1524. X    Dimension pixel_width;
  1525. X{
  1526. X    char save, *end, *remainder;
  1527. X
  1528. X    save = '\0';
  1529. X    remainder = 0;
  1530. X    end = eos(s);    /* point to null at end of string */
  1531. X
  1532. X    /* assume that if end == s, XXXXXX returns 0) */
  1533. X    while ((Dimension) XTextWidth(fs, s, (int) strlen(s)) > pixel_width) {
  1534. X    *end-- = save;
  1535. X    while (*end != ' ') {
  1536. X        if (end == s) panic("split: eos!");
  1537. X        --end;
  1538. X    }
  1539. X    save = *end;
  1540. X    *end = '\0';
  1541. X    remainder = end + 1;
  1542. X    }
  1543. X    return remainder;
  1544. X}
  1545. X
  1546. X/*
  1547. X * Add a line of text to the window.  The first line in the curcular list
  1548. X * becomes the last.  So all we have to do is copy the new line over the
  1549. X * old one.  If the line buffer is too small, then allocate a new, larger
  1550. X * one.
  1551. X */
  1552. Xstatic void
  1553. Xadd_line(mesg_info, s)
  1554. X    struct mesg_info_t *mesg_info;
  1555. X    const char *s;
  1556. X{
  1557. X    register struct line_element *curr = mesg_info->head;
  1558. X    register int new_line_length = strlen(s);
  1559. X
  1560. X    if (new_line_length + 1 > curr->buf_length) {
  1561. X    if (curr->line) free(curr->line);    /* free old line */
  1562. X
  1563. X    curr->buf_length = new_line_length + 1;
  1564. X    curr->line = (char *) alloc(curr->buf_length);
  1565. X    }
  1566. X
  1567. X    Strcpy(curr->line, s);            /* copy info */
  1568. X    curr->str_length = new_line_length;        /* save string length */
  1569. X
  1570. X    mesg_info->head = mesg_info->head->next;    /* move head to next line */
  1571. X    mesg_info->dirty = True;            /* we have undrawn lines */
  1572. X}
  1573. X
  1574. X
  1575. X/*
  1576. X * Save a position in the text buffer so we can draw a line to seperate
  1577. X * text from the last time this function was called.
  1578. X *
  1579. X * Save the head position, since it is the line "after" the last displayed
  1580. X * line in the message window.  The window redraw routine will draw a
  1581. X * line above this saved pointer.
  1582. X */
  1583. Xvoid
  1584. Xset_last_pause(wp)
  1585. X    struct xwindow *wp;
  1586. X{
  1587. X    register struct mesg_info_t *mesg_info = wp->mesg_information;
  1588. X
  1589. X#ifdef ERASE_LINE
  1590. X    /*
  1591. X     * If we've erased the pause line and haven't added any new lines,
  1592. X     * don't try to erase the line again.
  1593. X     */
  1594. X    if (!mesg_info->last_pause
  1595. X                && mesg_info->last_pause_head == mesg_info->head)
  1596. X    return;
  1597. X
  1598. X    if (mesg_info->last_pause == mesg_info->head) {
  1599. X    /* No new messages in last turn.  Redraw window to erase line. */
  1600. X    mesg_info->last_pause = (struct line_element *) 0;
  1601. X    mesg_info->last_pause_head = mesg_info->head;
  1602. X    redraw_message_window(wp);
  1603. X    } else {
  1604. X#endif
  1605. X    mesg_info->last_pause = mesg_info->head;
  1606. X#ifdef ERASE_LINE
  1607. X    }
  1608. X#endif
  1609. X}
  1610. X
  1611. X
  1612. Xstatic void
  1613. Xredraw_message_window(wp)
  1614. X    struct xwindow *wp;
  1615. X{
  1616. X    struct mesg_info_t *mesg_info = wp->mesg_information;
  1617. X    register struct line_element *curr;
  1618. X    register int row;
  1619. X
  1620. X    /*
  1621. X     * Do this the cheap and easy way.  Clear the window and just redraw
  1622. X     * the whole thing.
  1623. X     *
  1624. X     * This could be done more effecently with one call to XDrawText() instead
  1625. X     * of many calls to XDrawString().  Maybe later.
  1626. X     */
  1627. X    XClearWindow(XtDisplay(wp->w), XtWindow(wp->w));
  1628. X
  1629. X    /* For now, just update the whole shootn' match. */
  1630. X    for (row = 0, curr = mesg_info->head;
  1631. X            row < mesg_info->num_lines; row++, curr = curr->next) {
  1632. X
  1633. X    register int y_base = row * mesg_info->char_height;
  1634. X
  1635. X    XDrawString(XtDisplay(wp->w), XtWindow(wp->w),
  1636. X                mesg_info->gc,
  1637. X        mesg_info->char_lbearing,
  1638. X                mesg_info->char_ascent + y_base,
  1639. X        curr->line,
  1640. X        curr->str_length);
  1641. X
  1642. X    /*
  1643. X     * This draws a line at the _top_ of the line of text pointed to by
  1644. X     * mesg_info->last_pause.
  1645. X     */
  1646. X    if (appResources.message_line && curr == mesg_info->last_pause) {
  1647. X        XDrawLine(XtDisplay(wp->w), XtWindow(wp->w),
  1648. X                mesg_info->gc,
  1649. X        0, y_base, wp->pixel_width, y_base);
  1650. X    }
  1651. X    }
  1652. X
  1653. X    mesg_info->dirty = False;
  1654. X}
  1655. X
  1656. X
  1657. X/*
  1658. X * Check the size of the viewport.  If it has shrunk, then we want to
  1659. X * move the vertical slider to the bottom.
  1660. X */
  1661. Xstatic void
  1662. Xmesg_check_size_change(wp)
  1663. X    struct xwindow *wp;
  1664. X{
  1665. X    struct mesg_info_t *mesg_info = wp->mesg_information;
  1666. X    Arg arg[2];
  1667. X    Dimension new_width, new_height;
  1668. X    Widget viewport;
  1669. X
  1670. X    viewport = XtParent(wp->w);
  1671. X
  1672. X    XtSetArg(arg[0], XtNwidth,  &new_width);
  1673. X    XtSetArg(arg[1], XtNheight, &new_height);
  1674. X    XtGetValues(viewport, arg, TWO);
  1675. X
  1676. X    /* Only move slider to bottom if new size is smaller. */
  1677. X    if (new_width < mesg_info->viewport_width
  1678. X            || new_height < mesg_info->viewport_height) {
  1679. X    set_message_slider(wp);
  1680. X    }
  1681. X
  1682. X    mesg_info->viewport_width = new_width;
  1683. X    mesg_info->viewport_height = new_height;
  1684. X}
  1685. X
  1686. X
  1687. X/* Event handler for message window expose events. */
  1688. X/*ARGSUSED*/
  1689. Xstatic void
  1690. Xmesg_exposed(w, event)
  1691. X    Widget w;
  1692. X    XExposeEvent *event;    /* unused */
  1693. X{
  1694. X    struct xwindow *wp;
  1695. X
  1696. X    if (!XtIsRealized(w)) return;
  1697. X    wp = find_widget(w);
  1698. X    mesg_check_size_change(wp);
  1699. X    redraw_message_window(wp);
  1700. X}
  1701. X
  1702. X
  1703. Xstatic void
  1704. Xget_gc(w, mesg_info)
  1705. X    Widget w;
  1706. X    struct mesg_info_t *mesg_info;
  1707. X{
  1708. X    XGCValues values;
  1709. X    XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont;
  1710. X    Pixel fgpixel, bgpixel;
  1711. X    Arg arg[2];
  1712. X
  1713. X    XtSetArg(arg[0], XtNforeground, &fgpixel);
  1714. X    XtSetArg(arg[1], XtNbackground, &bgpixel);
  1715. X    XtGetValues(w, arg, TWO);
  1716. X
  1717. X    values.foreground = fgpixel;
  1718. X    values.background = bgpixel;
  1719. X    values.function   = GXcopy;
  1720. X    values.font       = WindowFont(w);
  1721. X    mesg_info->gc = XtGetGC(w, mask, &values);
  1722. X}
  1723. X
  1724. X/*
  1725. X * Handle resizes on a message window.  Correct saved pixel height and width.
  1726. X * Adjust circle buffer to accomidate the new size.
  1727. X * 
  1728. X * Problem:  If the resize decreases the width of the window such that
  1729. X * some lines are now longer than the window, they will be cut off by
  1730. X * X itself.  All new lines will be split to the new size, but the ends
  1731. X * of the old ones will not be seen again unless the window is lengthened.
  1732. X * I don't deal with this problem because it isn't worth the trouble.
  1733. X */
  1734. X/* ARGSUSED */
  1735. Xstatic void
  1736. Xmesg_resized(w, client_data, call_data)
  1737. X    Widget w;
  1738. X    XtPointer call_data, client_data;
  1739. X{
  1740. X    Arg args[4];
  1741. X    Cardinal num_args;
  1742. X    Dimension pixel_width, pixel_height;
  1743. X    struct xwindow *wp;
  1744. X#ifdef VERBOSE
  1745. X    int old_lines;
  1746. X
  1747. X    old_lines = wp->mesg_information->num_lines;;
  1748. X#endif
  1749. X
  1750. X    num_args = 0;
  1751. X    XtSetArg(args[num_args], XtNwidth,  &pixel_width);   num_args++;
  1752. X    XtSetArg(args[num_args], XtNheight, &pixel_height);  num_args++;
  1753. X    XtGetValues(w, args, num_args);
  1754. X
  1755. X    wp = find_widget(w);
  1756. X    wp->pixel_width  = pixel_width;
  1757. X    wp->pixel_height = pixel_height;
  1758. X
  1759. X    set_circle_buf(wp->mesg_information,
  1760. X            (int) pixel_height / wp->mesg_information->char_height);
  1761. X
  1762. X#ifdef VERBOSE
  1763. X    printf("Message resize.  Pixel: width = %d, height = %d;  Lines: old = %d, new = %d\n", 
  1764. X    pixel_width,
  1765. X    pixel_height,
  1766. X    old_lines,
  1767. X    wp->mesg_information->num_lines);
  1768. X#endif
  1769. X}
  1770. END_OF_FILE
  1771. if test 16667 -ne `wc -c <'win/X11/winmesg.c'`; then
  1772.     echo shar: \"'win/X11/winmesg.c'\" unpacked with wrong size!
  1773. fi
  1774. # end of 'win/X11/winmesg.c'
  1775. fi
  1776. echo shar: End of archive 85 \(of 108\).
  1777. cp /dev/null ark85isdone
  1778. MISSING=""
  1779. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
  1780. 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
  1781. 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
  1782. 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
  1783. 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
  1784. 101 102 103 104 105 106 107 108 ; do
  1785.     if test ! -f ark${I}isdone ; then
  1786.     MISSING="${MISSING} ${I}"
  1787.     fi
  1788. done
  1789. if test "${MISSING}" = "" ; then
  1790.     echo You have unpacked all 108 archives.
  1791.     echo "Now execute 'rebuild.sh'"
  1792.     rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
  1793. else
  1794.     echo You still need to unpack the following archives:
  1795.     echo "        " ${MISSING}
  1796. fi
  1797. ##  End of shell archive.
  1798. exit 0
  1799.