home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / win / tty / wintty.c < prev   
Encoding:
C/C++ Source or Header  |  1993-08-01  |  36.7 KB  |  1,616 lines  |  [TEXT/R*ch]

  1. /*    SCCS Id: @(#)wintty.c    3.1    93/05/26    */
  2. /* Copyright (c) David Cohrs, 1991                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * Neither a standard out nor character-based control codes should be
  7.  * part of the "tty look" windowing implementation.
  8.  * h+ 930227
  9.  */
  10.  
  11. #include "hack.h"
  12.  
  13. #ifdef TTY_GRAPHICS
  14.  
  15. #ifdef MAC
  16. # define MICRO /* The Mac is a MICRO only for this file, not in general! */
  17. # ifdef THINK_C
  18.    extern void msmsg(const char *,...);
  19. # endif
  20. #endif
  21.  
  22. #ifndef NO_TERMS
  23. # include "termcap.h"
  24. #endif
  25.  
  26. #include "wintty.h"
  27.  
  28. #if (defined(BSD) || defined(ULTRIX) || defined(AIX_31) || defined(_BULL_SOURCE)) && defined(CLIPPING)
  29. #include <signal.h>
  30. #endif
  31.  
  32. #define DEBUG
  33.  
  34. extern const char *roles[];    /* from u_init.c */
  35.  
  36. /* Interface definition, for windows.c */
  37. struct window_procs tty_procs = {
  38.     "tty",
  39.     tty_init_nhwindows,
  40.     tty_player_selection,
  41.     tty_askname,
  42.     tty_get_nh_event,
  43.     tty_exit_nhwindows,
  44.     tty_suspend_nhwindows,
  45.     tty_resume_nhwindows,
  46.     tty_create_nhwindow,
  47.     tty_clear_nhwindow,
  48.     tty_display_nhwindow,
  49.     tty_destroy_nhwindow,
  50.     tty_curs,
  51.     tty_putstr,
  52.     tty_display_file,
  53.     tty_start_menu,
  54.     tty_add_menu,
  55.     tty_end_menu,
  56.     tty_select_menu,
  57.     tty_update_inventory,
  58.     tty_mark_synch,
  59.     tty_wait_synch,
  60. #ifdef CLIPPING
  61.     tty_cliparound,
  62. #endif
  63.     tty_print_glyph,
  64.     tty_raw_print,
  65.     tty_raw_print_bold,
  66.     tty_nhgetch,
  67.     tty_nh_poskey,
  68.     tty_nhbell,
  69.     tty_doprev_message,
  70.     tty_yn_function,
  71.     tty_getlin,
  72. #ifdef COM_COMPL
  73.     tty_get_ext_cmd,
  74. #endif /* COM_COMPL */
  75.     tty_number_pad,
  76.     tty_delay_output,
  77. #ifdef CHANGE_COLOR    /* the Mac uses a palette device */
  78.     tty_change_color,
  79.     tty_get_color_string,
  80. #endif
  81.  
  82.     /* other defs that really should go away (they're tty specific) */
  83.     tty_start_screen,
  84.     tty_end_screen,
  85.     genl_outrip,
  86. };
  87.  
  88. static int maxwin = 0;            /* number of windows in use */
  89. winid BASE_WINDOW;
  90. struct WinDesc *wins[MAXWIN];
  91. struct DisplayDesc *ttyDisplay;    /* the tty display descriptor */
  92.  
  93. extern void FDECL(cmov, (int,int)); /* from termcap.c */
  94. extern void FDECL(nocmov, (int,int)); /* from termcap.c */
  95. #if defined(UNIX) || defined(VMS)
  96. static char obuf[BUFSIZ];    /* BUFSIZ is defined in stdio.h */
  97. #endif
  98.  
  99. static char winpanicstr[] = "Bad window id %d";
  100. char defmorestr[] = "--More--";
  101.  
  102. #ifdef CLIPPING
  103. static boolean clipping = FALSE;    /* clipping on? */
  104. static int clipx = 0, clipy = 0, clipxmax = 0, clipymax = 0;
  105. #endif
  106.  
  107. #if defined(ASCIIGRAPH) && !defined(NO_TERMS)
  108. boolean GFlag = FALSE;
  109. #endif
  110.  
  111. #ifdef MICRO
  112. static char to_continue[] = "to continue";
  113. #define getret() getreturn(to_continue)
  114. #else
  115. static void NDECL(getret);
  116. #endif
  117. static void FDECL(dmore,(struct WinDesc *));
  118. static const char * FDECL(compress_str, (const char *));
  119. static void FDECL(tty_putsym, (winid, int, int, CHAR_P));
  120.  
  121. #if defined(SIGWINCH) && defined(CLIPPING)
  122. static void
  123. winch()
  124. {
  125.     int oldLI = LI, oldCO = CO, i;
  126.     register struct WinDesc *cw;
  127.  
  128.     getwindowsz();
  129.     if((oldLI != LI || oldCO != CO) && ttyDisplay) {
  130.     ttyDisplay->rows = LI;
  131.     ttyDisplay->cols = CO;
  132.  
  133.     cw = wins[BASE_WINDOW];
  134.     cw->rows = ttyDisplay->rows;
  135.     cw->cols = ttyDisplay->cols;
  136.  
  137.     if(flags.window_inited) {
  138.         cw = wins[WIN_MESSAGE];
  139.         cw->curx = cw->cury = 0;
  140.  
  141.         tty_destroy_nhwindow(WIN_STATUS);
  142.         WIN_STATUS = tty_create_nhwindow(NHW_STATUS);
  143.  
  144.         if(u.ux) {
  145. #ifdef CLIPPING
  146.         if(CO < COLNO || LI < ROWNO+3) {
  147.             setclipped();
  148.             tty_cliparound(u.ux, u.uy);
  149.         } else {
  150.             clipping = FALSE;
  151.             clipx = clipy = 0;
  152.         }
  153. #endif
  154.         i = ttyDisplay->toplin;
  155.         ttyDisplay->toplin = 0;
  156.         docrt();
  157.         bot();
  158.         ttyDisplay->toplin = i;
  159.         flush_screen(1);
  160.         if(i) {
  161.             addtopl(toplines);
  162.         } else
  163.             for(i=WIN_INVEN; i < MAXWIN; i++)
  164.             if(wins[i] && wins[i]->active) {
  165.                 /* cop-out */
  166.                 addtopl("Press Return to continue: ");
  167.                 break;
  168.             }
  169.         (void) fflush(stdout);
  170.         if(i < 2) flush_screen(1);
  171.         }
  172.     }
  173.     }
  174. }
  175. #endif
  176.  
  177. void
  178. tty_init_nhwindows()
  179. {
  180.     int wid, hgt;
  181.  
  182.     /*
  183.      *  Remember tty modes, to be restored on exit.
  184.      *
  185.      *  gettty() must be called before tty_startup()
  186.      *    due to ordering of LI/CO settings
  187.      *  tty_startup() must be called before initoptions()
  188.      *    due to ordering of graphics settings
  189.      */
  190. #if defined(UNIX) || defined(VMS)
  191.     setbuf(stdout,obuf);
  192. #endif
  193.     gettty();
  194.  
  195.     /* to port dependant tty setup */
  196.     tty_startup(&wid, &hgt);
  197.     setftty();            /* calls start_screen */
  198.  
  199.     /* set up tty descriptor */
  200.     ttyDisplay = (struct DisplayDesc*) alloc(sizeof(struct DisplayDesc));
  201.     ttyDisplay->toplin = 0;
  202.     ttyDisplay->rows = hgt;
  203.     ttyDisplay->cols = wid;
  204.     ttyDisplay->curx = ttyDisplay->cury = 0;
  205.     ttyDisplay->inmore = ttyDisplay->inread = ttyDisplay->intr = 0;
  206. #ifdef TEXTCOLOR
  207.     ttyDisplay->color = NO_COLOR;
  208. #endif
  209.     ttyDisplay->attrs = 0;
  210.  
  211.     /* set up the default windows */
  212.     BASE_WINDOW = tty_create_nhwindow(NHW_BASE);
  213.     wins[BASE_WINDOW]->active = 1;
  214.  
  215.     ttyDisplay->lastwin = WIN_ERR;
  216.  
  217. #if defined(SIGWINCH) && defined(CLIPPING)
  218.     (void) signal(SIGWINCH, winch);
  219. #endif
  220.  
  221.     tty_clear_nhwindow(BASE_WINDOW);
  222.  
  223.     tty_putstr(BASE_WINDOW, 0, "");
  224.     tty_putstr(BASE_WINDOW, 0,
  225.      "NetHack, Copyright 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993");
  226.     tty_putstr(BASE_WINDOW, 0,
  227.      "         By Stichting Mathematisch Centrum and M. Stephenson.");
  228.     tty_putstr(BASE_WINDOW, 0, "         See license for details.");
  229.     tty_putstr(BASE_WINDOW, 0, "");
  230.     tty_display_nhwindow(BASE_WINDOW, FALSE);
  231. }
  232.  
  233. void
  234. tty_player_selection()
  235. {
  236.     char pbuf[QBUFSZ];
  237.     char pick, pc;
  238.     int i, linecount;
  239.  
  240.     linecount = wins[BASE_WINDOW]->cury+1;
  241.     if ((pc = highc(pl_character[0])) != 0) {
  242.     if(index(pl_classes, pc) != (char*) 0)
  243.         goto got_suffix;
  244.     tty_putstr(BASE_WINDOW, 0, "");
  245.     Sprintf(pbuf, "Unknown role: %c", pc);
  246.     tty_putstr(BASE_WINDOW, 0, pbuf);
  247.     linecount += 2;
  248.     pl_character[0] = pc = 0;
  249.     }
  250.  
  251. #define PICK_PROMPT "Shall I pick a character for you? [Y, N, or Q(quit)] "
  252.     tty_putstr(BASE_WINDOW, 0, "");
  253.     tty_putstr(BASE_WINDOW, 0, PICK_PROMPT);
  254.  
  255.     while(!index("yYnNqQ", (pick = readchar())) && !index(quitchars, pick))
  256.     tty_nhbell();
  257.  
  258.     pick = index(quitchars, pick) ? 'Y' : highc(pick);
  259.  
  260.     tty_putsym(BASE_WINDOW, (int)strlen(PICK_PROMPT)+1, linecount, pick); /* echo */
  261.  
  262.     if (pick == 'Q') {
  263.     clearlocks();
  264.     tty_exit_nhwindows(NULL);
  265.     terminate(0);
  266.     }
  267.  
  268.     if (pick == 'Y') {
  269.     tty_putstr(BASE_WINDOW, 0, "");
  270.     goto beginner;
  271.     }
  272.  
  273.     tty_curs(BASE_WINDOW, 1, linecount+2);
  274.     tty_putstr(BASE_WINDOW, 0, "What kind of character are you:");
  275.     tty_putstr(BASE_WINDOW, 0, "");
  276.     Sprintf(pbuf, "      %s,", An(roles[0]));
  277.     for(i = 1; roles[i]; i++) {
  278.     Sprintf(eos(pbuf), " %s", an(roles[i]));
  279.     if((((i + 1) % 4) == 0) && roles[i+1]) {
  280.         Strcat(pbuf, ",");
  281.         tty_putstr(BASE_WINDOW, 0, pbuf);
  282.         linecount++;
  283.         Strcpy(pbuf, "        ");
  284.     }
  285.     else if(roles[i+1] && roles[i+2])    Strcat(pbuf, ",");
  286.     if(roles[i+1] && !roles[i+2])    Strcat(pbuf, " or");
  287.     }
  288.     Strcat(pbuf ,"?");
  289.     tty_putstr(BASE_WINDOW, 0, pbuf);
  290.     Strcpy(pbuf, "         [");
  291.     for(i = 0; roles[i]; i++)
  292.     Sprintf(eos(pbuf), "%c,", pl_classes[i]);
  293.     Strcat(pbuf, " or Q] ");
  294.     tty_putstr(BASE_WINDOW, 0, pbuf);
  295.     linecount += 5;
  296.  
  297.     while ((pc = readchar()) != 0) {
  298.     if ((pc = highc(pc)) == 'Q') {
  299.         clearlocks();
  300.         tty_exit_nhwindows(NULL);
  301.         terminate(0);
  302.     }
  303.     if(index(pl_classes, pc) != (char *) 0) {
  304.         tty_putsym(BASE_WINDOW, (int)strlen(pbuf)+1, linecount, pc); /* echo */
  305.         tty_putstr(BASE_WINDOW, 0, "");
  306.         tty_display_nhwindow(BASE_WINDOW, TRUE);
  307.         break;
  308.     }
  309.     if(pc == '\n') {
  310.         pc = 0;
  311.         break;
  312.     }
  313.     tty_nhbell();
  314.     }
  315.  
  316. beginner:
  317.     if(!pc) {
  318.     i = rn2((int)strlen(pl_classes));
  319.     pc = pl_classes[i];
  320.     tty_putstr(BASE_WINDOW, 0, "");
  321.     Sprintf(pbuf, "This game you will be %s.", an(roles[i]));
  322.     tty_putstr(BASE_WINDOW, 0, pbuf);
  323.     tty_putstr(BASE_WINDOW, 0, "");
  324.     tty_display_nhwindow(BASE_WINDOW, TRUE);
  325.     getret();
  326.     }
  327. got_suffix:
  328.  
  329.     tty_clear_nhwindow(BASE_WINDOW);
  330.     pl_character[0] = pc;
  331.     return;
  332. }
  333.  
  334. /*
  335.  * plname is filled either by an option (-u Player  or  -uPlayer) or
  336.  * explicitly (by being the wizard) or by askname.
  337.  * It may still contain a suffix denoting pl_character.
  338.  * Always called after init_nhwindows() and before display_gamewindows().
  339.  */
  340. void
  341. tty_askname()
  342. {
  343.     register int c, ct;
  344.  
  345.     tty_putstr(BASE_WINDOW, 0, "");
  346.     tty_putstr(BASE_WINDOW, 0, "Who are you? ");
  347.     tty_curs(BASE_WINDOW, 14, wins[BASE_WINDOW]->cury-1);
  348.     ct = 0;
  349.     while((c = tty_nhgetch()) != '\n') {
  350.         if(c == EOF) error("End of input\n");
  351.         /* some people get confused when their erase char is not ^H */
  352.         if (c == '\b' || c == '\177') {
  353.             if(ct) {
  354.                 ct--;
  355. #ifdef MICRO
  356. # if defined(WIN32CON)
  357.                 backsp();       /* \b is visible on NT */
  358. # else
  359.                 msmsg("\b \b");
  360. # endif
  361. #else
  362.                 (void) putchar('\b');
  363.                 (void) putchar(' ');
  364.                 (void) putchar('\b');
  365. #endif
  366.             }
  367.             continue;
  368.         }
  369. #if defined(UNIX) || defined(VMS)
  370.         if(c != '-' && c != '@')
  371.         if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
  372. #endif
  373.         if(ct < sizeof(plname)-1) {
  374. #if defined(MICRO)
  375.             msmsg("%c", c);
  376. #else
  377.             (void) putchar(c);
  378. #endif
  379.             plname[ct++] = c;
  380.         }
  381.     }
  382.     plname[ct] = 0;
  383.     tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury+1);
  384.     if(ct == 0) tty_askname();
  385. }
  386.  
  387. void
  388. tty_get_nh_event()
  389. {
  390. #ifdef LINT
  391.     /*
  392.      * We should do absolutely nothing here - but lint
  393.      * complains about that, so we call donull().
  394.      */
  395.      (void) donull();
  396. #endif
  397. }
  398.  
  399. #ifndef MICRO
  400. static void
  401. getret()
  402. {
  403.     xputs("\n");
  404.     if(flags.standout)
  405.         standoutbeg();
  406.     xputs("Hit ");
  407.     xputs(flags.cbreak ? "space" : "return");
  408.     xputs(" to continue: ");
  409.     if(flags.standout)
  410.         standoutend();
  411.     xwaitforspace("");
  412. }
  413. #endif
  414.  
  415. void
  416. tty_suspend_nhwindows(str)
  417.     const char *str;
  418. {
  419.     settty(str);        /* calls end_screen, perhaps raw_print */
  420.     if (!str) tty_raw_print("");    /* calls fflush(stdout) */
  421. }
  422.  
  423. void
  424. tty_resume_nhwindows()
  425. {
  426.     gettty();
  427.     setftty();            /* calls start_screen */
  428.     docrt();
  429. }
  430.  
  431. void
  432. tty_exit_nhwindows(str)
  433.     const char *str;
  434. {
  435.     winid i;
  436.  
  437.     tty_suspend_nhwindows(str);
  438.     /* Just forget any windows existed, since we're about to exit anyway.
  439.      * Disable windows to avoid calls to window routines.
  440.      */
  441.     for(i=0; i<MAXWIN; i++)
  442.     if(i != BASE_WINDOW)
  443.         wins[i] = 0;
  444.     flags.window_inited = 0;
  445. }
  446.  
  447. winid
  448. tty_create_nhwindow(type)
  449.     int type;
  450. {
  451.     struct WinDesc* newwin;
  452.     int i;
  453.     int newid;
  454.  
  455.     if(maxwin == MAXWIN)
  456.     return WIN_ERR;
  457.  
  458.     newwin = (struct WinDesc*) alloc(sizeof(struct WinDesc));
  459.     newwin->type = type;
  460.     newwin->flags = 0;
  461.     newwin->active = FALSE;
  462.     newwin->curx = newwin->cury = 0;
  463.     newwin->resp = newwin->canresp = newwin->morestr = 0;
  464.     switch(type) {
  465.     case NHW_BASE:
  466.     /* base window, used for absolute movement on the screen */
  467.     newwin->offx = newwin->offy = 0;
  468.     newwin->rows = ttyDisplay->rows;
  469.     newwin->cols = ttyDisplay->cols;
  470.     newwin->maxrow = newwin->maxcol = 0;
  471.     break;
  472.     case NHW_MESSAGE:
  473.     /* message window, 1 line long, very wide, top of screen */
  474.     newwin->offx = newwin->offy = 0;
  475.     /* sanity check */
  476.     if(flags.msg_history < 20) flags.msg_history = 20;
  477.     else if(flags.msg_history > 60) flags.msg_history = 60;
  478.     newwin->maxrow = newwin->rows = flags.msg_history;
  479.     newwin->maxcol = newwin->cols = 0;
  480.     break;
  481.     case NHW_STATUS:
  482.     /* status window, 2 lines long, full width, bottom of screen */
  483.     newwin->offx = 0;
  484.     newwin->offy = min((int)ttyDisplay->rows-2, ROWNO+1);
  485.     newwin->rows = newwin->maxrow = 2;
  486.     newwin->cols = newwin->maxcol = min(ttyDisplay->cols, COLNO);
  487.     break;
  488.     case NHW_MAP:
  489.     /* map window, ROWNO lines long, full width, below message window */
  490.     newwin->offx = 0;
  491.     newwin->offy = 1;
  492.     newwin->rows = ROWNO;
  493.     newwin->cols = COLNO;
  494.     newwin->maxrow = 0;    /* no buffering done -- let gbuf do it */
  495.     newwin->maxcol = 0;
  496.     break;
  497.     case NHW_MENU:
  498.     newwin->resp = (char*) alloc(256);
  499.     newwin->resp[0] = 0;
  500.     case NHW_TEXT:
  501.     /* inventory/menu window, variable length, full width, top of screen */
  502.     /* help window, the same, different semantics for display, etc */
  503.     newwin->offx = newwin->offy = 0;
  504.     newwin->rows = 0;
  505.     newwin->cols = ttyDisplay->cols;
  506.     newwin->maxrow = newwin->maxcol = 0;
  507.     break;
  508.    default:
  509.     panic("Tried to create window type %d\n", (int) type);
  510.     return WIN_ERR;
  511.     }
  512.  
  513.     for(newid = 0; newid<MAXWIN; newid++) {
  514.     if(wins[newid] == 0) {
  515.         wins[newid] = newwin;
  516.         break;
  517.     }
  518.     }
  519.     if(newid == MAXWIN) {
  520.     panic("No window slots!");
  521.     return WIN_ERR;
  522.     }
  523.  
  524.     if(newwin->maxrow) {
  525.     newwin->data = (char**) alloc(sizeof(char**) * newwin->maxrow);
  526.     if(newwin->maxcol) {
  527.         for(i=0; i< newwin->maxrow; i++)
  528.         newwin->data[i] = (char*)alloc(sizeof(char*) * newwin->maxcol);
  529.     } else {
  530.         for(i=0; i< newwin->maxrow; i++)
  531.         newwin->data[i] = 0;
  532.     }
  533.     if(newwin->type == NHW_MESSAGE)
  534.         newwin->maxrow = 0;
  535.     } else
  536.     newwin->data = 0;
  537.  
  538.     return newid;
  539. }
  540.  
  541. void
  542. tty_clear_nhwindow(window)
  543.     winid window;
  544. {
  545.     register struct WinDesc *cw = 0;
  546.     int i;
  547.  
  548.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  549.     panic(winpanicstr,  window);
  550.     ttyDisplay->lastwin = window;
  551.  
  552.     switch(cw->type) {
  553.     case NHW_MESSAGE:
  554.     if(ttyDisplay->toplin) {
  555.         home();
  556.         cl_end();
  557.         if(cw->cury)
  558.         docorner(1, cw->cury+1);
  559.         ttyDisplay->toplin = 0;
  560.     }
  561.     break;
  562.     case NHW_STATUS:
  563.     tty_curs(window, 1, 0);
  564.     cl_end();
  565.     tty_curs(window, 1, 1);
  566.     cl_end();
  567.     break;
  568.     case NHW_MAP:
  569.     /* cheap -- clear the whole thing and tell nethack to redraw botl */
  570.     flags.botlx = 1;
  571.     /* fall into ... */
  572.     case NHW_BASE:
  573.     clear_screen();
  574.     break;
  575.     case NHW_MENU:
  576.     case NHW_TEXT:
  577.     if(cw->active) {
  578.         if(cw->offx == 0)
  579.         if(cw->offy) {
  580.             tty_curs(window, 1, 0);
  581.             cl_eos();
  582.         } else
  583.             clear_screen();
  584.         else
  585.         docorner((int)cw->offx, cw->maxrow+1);
  586.     }
  587.     for(i=0; i<cw->maxrow; i++)
  588.         if(cw->data[i]) {
  589.         free((genericptr_t)cw->data[i]);
  590.         cw->data[i] = 0;
  591.         }
  592.     cw->maxrow = cw->maxcol = 0;
  593.     if(cw->resp)
  594.         cw->resp[0] = 0;
  595.     if(cw->canresp) {
  596.         free((genericptr_t)cw->canresp);
  597.         cw->canresp = 0;
  598.     }
  599.     if(cw->morestr) {
  600.         free((genericptr_t)cw->morestr);
  601.         cw->morestr = 0;
  602.     }
  603.     break;
  604.     }
  605.     cw->curx = cw->cury = 0;
  606. }
  607.  
  608. static void
  609. dmore(cw)
  610.     register struct WinDesc *cw;
  611. {
  612.     const char *s = (cw->resp && *cw->resp) ? cw->resp : quitchars;
  613.     const char *prompt = cw->morestr ? cw->morestr : defmorestr;
  614.     if(cw->type == NHW_TEXT)
  615.     tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1, (int)ttyDisplay->cury);
  616.     else
  617.     tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+2, (int)ttyDisplay->cury);
  618.     if(flags.standout)
  619.     standoutbeg();
  620.     xputs(prompt);
  621.     ttyDisplay->curx += strlen(prompt);
  622.     if(flags.standout)
  623.     standoutend();
  624.  
  625.     xwaitforspace(s);
  626. }
  627.  
  628. /*ARGSUSED*/
  629. void
  630. tty_display_nhwindow(window, blocking)
  631.     winid window;
  632.     boolean blocking;    /* with ttys, all windows are blocking */
  633. {
  634.     register struct WinDesc *cw = 0;
  635.     int i, n, attr;
  636.     register char *cp;
  637.  
  638.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  639.     panic(winpanicstr,  window);
  640.     if(cw->flags & WIN_CANCELLED)
  641.     return;
  642.     ttyDisplay->lastwin = window;
  643.     ttyDisplay->rawprint = 0;
  644.  
  645.     switch(cw->type) {
  646.     case NHW_MESSAGE:
  647.     if(ttyDisplay->toplin == 1) {
  648.         more();
  649.         ttyDisplay->toplin = 1; /* more resets this */
  650.         tty_clear_nhwindow(window);
  651.     } else
  652.         ttyDisplay->toplin = 0;
  653.     cw->curx = cw->cury = 0;
  654.     if(!cw->active)
  655.         flags.window_inited = TRUE;
  656.     break;
  657.     case NHW_MAP:
  658.     end_glyphout();
  659.     if(blocking) {
  660.         if(!ttyDisplay->toplin) ttyDisplay->toplin = 1;
  661.         tty_display_nhwindow(WIN_MESSAGE, TRUE);
  662.         return;
  663.     }
  664.     case NHW_BASE:
  665.     (void) fflush(stdout);
  666.     break;
  667.     case NHW_TEXT:
  668.     cw->maxcol = ttyDisplay->cols; /* force full-screen mode */
  669.     case NHW_MENU:
  670.     cw->active = 1;
  671.     /* avoid converting to uchar before calculations are finished */
  672.     cw->offx = (uchar) (int)
  673.         max((int) 10, (int) (ttyDisplay->cols - cw->maxcol - 1));
  674.     if(cw->type == NHW_MENU)
  675.         cw->offy = 0;
  676.     if(ttyDisplay->toplin == 1)
  677.         tty_display_nhwindow(WIN_MESSAGE, TRUE);
  678.     if(cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows) {
  679.         cw->offx = 0;
  680.         if(cw->offy) {
  681.         tty_curs(window, 1, 0);
  682.         cl_eos();
  683.         } else
  684.         clear_screen();
  685.         ttyDisplay->toplin = 0;
  686.     } else
  687.         tty_clear_nhwindow(WIN_MESSAGE);
  688.  
  689.     for(n=0, i=0; i<cw->maxrow; i++) {
  690.         if(!cw->offx && (n+cw->offy == ttyDisplay->rows-1)) {
  691.         tty_curs(window, 1, n);
  692.         cl_end();
  693.         dmore(cw);
  694.         if(morc) {
  695.             if(!cw->canresp && (morc == '\033'))
  696.             cw->flags |= WIN_CANCELLED;
  697.             else if(cw->canresp && index(&cw->canresp[1], morc)) {
  698.             morc = cw->canresp[0];
  699.             cw->flags |= WIN_CANCELLED;
  700.             }
  701.             break;
  702.         }
  703.         if(cw->offy) {
  704.             tty_curs(window, 1, 0);
  705.             cl_eos();
  706.         } else
  707.             clear_screen();
  708.         n = 0;
  709.         }
  710.         tty_curs(window, 1, n++);
  711.         if(cw->offx) cl_end();
  712.         if(cw->data[i]) {
  713.         attr = cw->data[i][0]-1;
  714.         if(cw->type == NHW_MENU) {
  715.             (void) putchar(' '); ++ttyDisplay->curx;
  716.         }
  717.         term_start_attr(attr);
  718.         for(cp = &cw->data[i][1];
  719.             *cp && (int)++ttyDisplay->curx < (int) ttyDisplay->cols; )
  720. #ifdef __SASC
  721.             (void) fputchar(*cp++);
  722. #else
  723.             (void) putchar(*cp++);
  724. #endif
  725.         term_end_attr(attr);
  726.         }
  727.     }
  728.     if(i == cw->maxrow) {
  729.         if(cw->type == NHW_TEXT)
  730.         tty_curs(BASE_WINDOW, (int)cw->offx+1, (int)ttyDisplay->rows-1);
  731.         else
  732.         tty_curs(BASE_WINDOW, (int)cw->offx+1, n);
  733.         cl_end();
  734.         dmore(cw);
  735.         if(morc) {
  736.         if(!cw->canresp && (morc == '\033'))
  737.             cw->flags |= WIN_CANCELLED;
  738.         else if(cw->canresp && index(&cw->canresp[1], morc)) {
  739.             morc = cw->canresp[0];
  740.             cw->flags |= WIN_CANCELLED;
  741.         }
  742.         }
  743.     }
  744.     break;
  745.     }
  746.     cw->active = 1;
  747. }
  748.  
  749. void
  750. tty_dismiss_nhwindow(window)
  751.     winid window;
  752. {
  753.     register struct WinDesc *cw = 0;
  754.  
  755.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  756.     panic(winpanicstr,  window);
  757.  
  758.     switch(cw->type) {
  759.     case NHW_STATUS:
  760.     case NHW_BASE:
  761.     case NHW_MESSAGE:
  762.     case NHW_MAP:
  763.     /*
  764.      * these should only get dismissed when the game is going away
  765.      * or suspending
  766.      */
  767.     tty_curs(BASE_WINDOW, 1, (int)ttyDisplay->rows-1);
  768.     cw->active = 0;
  769.     break;
  770.     case NHW_MENU:
  771.     case NHW_TEXT:
  772.     if(cw->active) {
  773.         if(cw->offx == 0) {
  774.         if(cw->offy) {
  775.             tty_curs(window, 1, 0);
  776.             cl_eos();
  777.         } else
  778.             docrt();
  779.         } else {
  780.         docorner((int)cw->offx, cw->maxrow+1);
  781.         }
  782.         cw->active = 0;
  783.     }
  784.     break;
  785.     }
  786.     cw->flags = 0;
  787. }
  788.  
  789. void
  790. tty_destroy_nhwindow(window)
  791.     winid window;
  792. {
  793.     register struct WinDesc *cw = 0;
  794.     int i;
  795.  
  796.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  797.     panic(winpanicstr,  window);
  798.  
  799.     if(cw->active)
  800.     tty_dismiss_nhwindow(window);
  801.     if(cw->type == NHW_MESSAGE)
  802.     flags.window_inited = 0;
  803.     if(cw->type == NHW_MAP)
  804.     clear_screen();
  805.  
  806.     if(cw->data) {
  807.     for(i=0; i<cw->rows; i++)
  808.         if(cw->data[i])
  809.         free((genericptr_t)cw->data[i]);
  810.     free((genericptr_t)cw->data);
  811.     }
  812.     if(cw->resp)
  813.     free((genericptr_t)cw->resp);
  814.     if(cw->canresp)
  815.     free((genericptr_t)cw->canresp);
  816.     free((genericptr_t)cw);
  817.     wins[window] = 0;
  818. }
  819.  
  820. void
  821. tty_curs(window, x, y)
  822. winid window;
  823. register int x, y;    /* not xchar: perhaps xchar is unsigned and
  824.                curx-x would be unsigned as well */
  825. {
  826.     struct WinDesc *cw = 0;
  827.     int cx = ttyDisplay->curx;
  828.     int cy = ttyDisplay->cury;
  829.  
  830.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  831.     panic(winpanicstr,  window);
  832.     ttyDisplay->lastwin = window;
  833.  
  834.     cw->curx = --x;    /* column 0 is never used */
  835.     cw->cury = y;
  836. #ifdef DEBUG
  837.     if(x<0 || y<0 || y >= cw->rows || x >= cw->cols) {
  838.     const char *s = "[unknown type]";
  839.     switch(cw->type) {
  840.     case NHW_MESSAGE: s = "[topl window]"; break;
  841.     case NHW_STATUS: s = "[status window]"; break;
  842.     case NHW_MAP: s = "[map window]"; break;
  843.     case NHW_MENU: s = "[corner window]"; break;
  844.     case NHW_TEXT: s = "[text window]"; break;
  845.     case NHW_BASE: s = "[base window]"; break;
  846.     }
  847.     impossible("bad curs positioning win %d %s (%d,%d)", window, s, x, y);
  848.     return;
  849.     }
  850. #endif
  851.     x += cw->offx;
  852.     y += cw->offy;
  853.  
  854. #ifdef CLIPPING
  855.     if(clipping && window == WIN_MAP) {
  856.     x -= clipx;
  857.     y -= clipy;
  858.     }
  859. #endif
  860.  
  861.     if (y == cy && x == cx)
  862.     return;
  863.  
  864.     if(cw->type == NHW_MAP)
  865.     end_glyphout();
  866.  
  867. #ifndef NO_TERMS
  868.     if(!ND && (cx != x || x <= 3)) { /* Extremely primitive */
  869.     cmov(x, y); /* bunker!wtm */
  870.     return;
  871.     }
  872. #endif
  873.  
  874.     if((cy -= y) < 0) cy = -cy;
  875.     if((cx -= x) < 0) cx = -cx;
  876.     if(cy <= 3 && cx <= 3) {
  877.     nocmov(x, y);
  878. #ifndef NO_TERMS
  879.     } else if ((x <= 3 && cy <= 3) || (!CM && x < cx)) {
  880.     (void) putchar('\r');
  881.     ttyDisplay->curx = 0;
  882.     nocmov(x, y);
  883.     } else if (!CM) {
  884.     nocmov(x, y);
  885. #endif
  886.     } else
  887.     cmov(x, y);
  888.  
  889.     ttyDisplay->curx = x;
  890.     ttyDisplay->cury = y;
  891. }
  892.  
  893. static void
  894. tty_putsym(window, x, y, ch)
  895.     winid window;
  896.     int x, y;
  897.     char ch;
  898. {
  899.     register struct WinDesc *cw = 0;
  900.  
  901.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
  902.     panic(winpanicstr,  window);
  903.  
  904.     switch(cw->type) {
  905.     case NHW_STATUS:
  906.     case NHW_MAP:
  907.     case NHW_BASE:
  908.     tty_curs(window, x, y);
  909.     (void) putchar(ch);
  910.     ttyDisplay->curx++;
  911.     cw->curx++;
  912.     break;
  913.     case NHW_MESSAGE:
  914.     case NHW_MENU:
  915.     case NHW_TEXT:
  916.     impossible("Can't putsym to window type %d", cw->type);
  917.     break;
  918.     }
  919. }
  920.  
  921.  
  922. static const char*
  923. compress_str(str)
  924. const char *str;
  925. {
  926.     static char cbuf[BUFSZ];
  927.     /* compress in case line too long */
  928.     if((int)strlen(str) >= CO) {
  929.         register const char *bp0 = str;
  930.         register char *bp1 = cbuf;
  931.  
  932.         do {
  933. #ifdef CLIPPING
  934.             if(*bp0 != ' ' || bp0[1] != ' ')
  935. #else
  936.             if(*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ')
  937. #endif
  938.                 *bp1++ = *bp0;
  939.         } while(*bp0++);
  940.     } else
  941.         return str;
  942.     return cbuf;
  943. }
  944.  
  945. void
  946. tty_putstr(window, attr, str)
  947.     winid window;
  948.     int attr;
  949.     const char *str;
  950. {
  951.     register struct WinDesc *cw = 0;
  952.     register char *ob;
  953.     register const char *nb;
  954.     register int i, j, n0;
  955.  
  956.     /* Assume there's a real problem if the window is missing --
  957.      * probably a panic message
  958.      */
  959.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) {
  960.     tty_raw_print(str);
  961.     return;
  962.     }
  963.  
  964.     if(str == (const char*)NULL || (cw->flags & WIN_CANCELLED))
  965.     return;
  966.     if(cw->type != NHW_MESSAGE)
  967.     str = compress_str(str);
  968.  
  969.     ttyDisplay->lastwin = window;
  970.  
  971.     switch(cw->type) {
  972.     case NHW_MESSAGE:
  973.     /* really do this later */
  974.     update_topl(str);
  975.     break;
  976.  
  977.     case NHW_STATUS:
  978.     ob = &cw->data[cw->cury][j = cw->curx];
  979.     if(flags.botlx) *ob = 0;
  980.     if(!cw->cury && (int)strlen(str) >= CO) {
  981.         /* the characters before "St:" are unnecessary */
  982.         nb = index(str, ':');
  983.         if(nb && nb > str+2)
  984.         str = nb - 2;
  985.     }
  986.     nb = str;
  987.     for(i = cw->curx+1, n0 = cw->cols; i < n0; i++, nb++) {
  988.         if(!*nb) {
  989.         if(*ob || flags.botlx) {
  990.             /* last char printed may be in middle of line */
  991.             tty_curs(WIN_STATUS, i, cw->cury);
  992.             cl_end();
  993.         }
  994.         break;
  995.         }
  996.         if(*ob != *nb)
  997.         tty_putsym(WIN_STATUS, i, cw->cury, *nb);
  998.         if(*ob) ob++;
  999.     }
  1000.  
  1001.     (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1);
  1002.     cw->data[cw->cury][cw->cols-1] = '\0'; /* null terminate */
  1003.     cw->cury = (cw->cury+1) % 2;
  1004.     cw->curx = 0;
  1005.     break;
  1006.     case NHW_MAP:
  1007.     case NHW_BASE:
  1008.     tty_curs(window, cw->curx+1, cw->cury);
  1009.     term_start_attr(attr);
  1010.     while(*str && (int) ttyDisplay->curx < (int) ttyDisplay->cols-1) {
  1011. #ifdef __SASC
  1012.         (void) fputchar(*str++);
  1013. #else
  1014.         (void) putchar(*str++);
  1015. #endif
  1016.         ttyDisplay->curx++;
  1017.     }
  1018.     cw->curx = 0;
  1019.     cw->cury++;
  1020.     term_end_attr(attr);
  1021.     break;
  1022.     case NHW_MENU:
  1023.     case NHW_TEXT:
  1024.     if(!(cw->resp && cw->resp[0]) && cw->cury == ttyDisplay->rows-1) {
  1025.         /* not a menu, so save memory and output 1 page at a time */
  1026.         cw->maxcol = ttyDisplay->cols; /* force full-screen mode */
  1027.         tty_display_nhwindow(window, TRUE);
  1028.         cw->maxrow = cw->cury = 0;
  1029.     }
  1030.     /* always grows one at a time, but alloc 12 at a time */
  1031.     if(cw->cury >= cw->rows) {
  1032.         char **tmp;
  1033.  
  1034.         cw->rows += 12;
  1035.         tmp = (char**) alloc(sizeof(char*) * cw->rows);
  1036.         for(i=0; i<cw->maxrow; i++)
  1037.         tmp[i] = cw->data[i];
  1038.         if(cw->data)
  1039.         free((genericptr_t)cw->data);
  1040.         cw->data = tmp;
  1041.  
  1042.         for(i=cw->maxrow; i<cw->rows; i++)
  1043.         cw->data[i] = 0;
  1044.     }
  1045.     if(cw->data[cw->cury])
  1046.         free((genericptr_t)cw->data[cw->cury]);
  1047.     n0 = strlen(str)+1;
  1048.     cw->data[cw->cury] = (char*) alloc(n0+1);
  1049.     cw->data[cw->cury][0] = attr+1;    /* avoid nuls, for convenience */
  1050.     Strcpy(&cw->data[cw->cury][1], str);
  1051.  
  1052.     if(n0 > cw->maxcol)
  1053.         cw->maxcol = n0;
  1054.     if(++cw->cury > cw->maxrow)
  1055.         cw->maxrow = cw->cury;
  1056.     if(n0 > CO) {
  1057.         /* attempt to break the line */
  1058.         for(i = CO-1; i && str[i] != ' ';)
  1059.         i--;
  1060.         if(i) {
  1061.         cw->data[cw->cury-1][++i] = '\0';
  1062.         tty_putstr(window, attr, &str[i]);
  1063.         }
  1064.  
  1065.     }
  1066.     break;
  1067.     }
  1068. }
  1069.  
  1070. void
  1071. tty_display_file(fname, complain)
  1072. const char *fname;
  1073. boolean complain;
  1074. {
  1075. #ifdef DEF_PAGER            /* this implies that UNIX is defined */
  1076.     {
  1077.     /* use external pager; this may give security problems */
  1078.     register int fd = open(fname, 0);
  1079.  
  1080.     if(fd < 0) {
  1081.         if(complain) pline("Cannot open %s.", fname);
  1082.         else docrt();
  1083.         return;
  1084.     }
  1085.     if(child(1)) {
  1086.         /* Now that child() does a setuid(getuid()) and a chdir(),
  1087.            we may not be able to open file fname anymore, so make
  1088.            it stdin. */
  1089.         (void) close(0);
  1090.         if(dup(fd)) {
  1091.         if(complain) raw_printf("Cannot open %s as stdin.", fname);
  1092.         } else {
  1093.         (void) execlp(catmore, "page", NULL);
  1094.         if(complain) raw_printf("Cannot exec %s.", catmore);
  1095.         }
  1096.         if(complain) sleep(10); /* want to wait_synch() but stdin is gone */
  1097.         terminate(1);
  1098.     }
  1099.     (void) close(fd);
  1100.     }
  1101. #else
  1102.     {
  1103. #ifdef MAC
  1104.     int fd;
  1105. #else
  1106.     FILE *f;
  1107. #endif
  1108.     char buf[BUFSZ];
  1109.     char *cr;
  1110.  
  1111.     tty_clear_nhwindow(WIN_MESSAGE);
  1112. #ifdef MAC
  1113.     fd = open(fname, O_RDONLY, TEXT_TYPE);
  1114.     if (fd < 0) {
  1115. #else
  1116.     f = fopen_datafile(fname, "r");
  1117.     if (!f) {
  1118. #endif
  1119.         if(complain) {
  1120.         home();  tty_mark_synch();  tty_raw_print("");
  1121.         perror(fname);  tty_wait_synch();
  1122.         pline("Cannot open \"%s\".", fname);
  1123.         } else if(u.ux) docrt();
  1124.     } else {
  1125.         winid datawin = tty_create_nhwindow(NHW_TEXT);
  1126.         if(complain
  1127. #ifndef NO_TERMS
  1128.         && CD
  1129. #endif
  1130.         ) {
  1131.         /* attempt to scroll text below map window if there's room */
  1132.         wins[datawin]->offy = wins[WIN_STATUS]->offy+3;
  1133.         if((int) wins[datawin]->offy + 12 > (int) ttyDisplay->rows)
  1134.             wins[datawin]->offy = 0;
  1135.         }
  1136. #ifdef MAC
  1137.         while (macgets(fd, buf, BUFSZ)) {
  1138. #else
  1139.         while (fgets(buf, BUFSZ, f)) {
  1140. #endif
  1141.         if ((cr = index(buf, '\n')) != 0) *cr = 0;
  1142.         if (index(buf, '\t') != 0) (void) tabexpand(buf);
  1143.         tty_putstr(datawin, 0, buf);
  1144.         if(wins[datawin]->flags & WIN_CANCELLED)
  1145.             break;
  1146.         }
  1147.         tty_display_nhwindow(datawin, FALSE);
  1148.         tty_destroy_nhwindow(datawin);
  1149. #ifdef MAC
  1150.         (void) close(fd);
  1151. #else
  1152.         (void) fclose(f);
  1153. #endif
  1154.     }
  1155.     }
  1156. #endif /* DEF_PAGER */
  1157. }
  1158.  
  1159. void
  1160. tty_start_menu(window)
  1161.     winid window;
  1162. {
  1163.     tty_clear_nhwindow(window);
  1164.     return;
  1165. }
  1166.  
  1167. /*
  1168.  * Add a menu item.  window must be an NHW_MENU type,
  1169.  * ch is the value to return if this entry is selected.
  1170.  * attr are attributes to set for this line (like tty_putstr())
  1171.  * str is the value to display on this menu line
  1172.  */
  1173. void
  1174. tty_add_menu(window, ch, attr, str)
  1175.     winid window;
  1176.     char ch;
  1177.     int attr;
  1178.     const char *str;
  1179. {
  1180.     register struct WinDesc *cw = 0;
  1181.     char tmpbuf[2];
  1182.  
  1183.     if(str == (const char*)NULL)
  1184.     return;
  1185.  
  1186.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0
  1187.        || cw->type != NHW_MENU)
  1188.     panic(winpanicstr,  window);
  1189.  
  1190.     tty_putstr(window, attr, str);
  1191.     if(ch != '\0') {
  1192.     tmpbuf[0] = ch;
  1193.     tmpbuf[1] = 0;
  1194.     Strcat(cw->resp, tmpbuf);
  1195.     }
  1196. }
  1197.  
  1198. /*
  1199.  * End a menu in this window, window must a type NHW_MENU.
  1200.  * ch is the value to return if the menu is canceled,
  1201.  * str is a list of cancel characters (values that may be input)
  1202.  * morestr is a prompt to display, rather than the default.
  1203.  * str and morestr might be ignored by some ports.
  1204.  */
  1205. void
  1206. tty_end_menu(window, ch, str, morestr)
  1207.     winid window;
  1208.     char ch;
  1209.     const char *str;
  1210.     const char *morestr;
  1211. {
  1212.     register struct WinDesc *cw = 0;
  1213.  
  1214.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 ||
  1215.        cw->type != NHW_MENU || cw->canresp)
  1216.     panic(winpanicstr,  window);
  1217.  
  1218.     if(str) {
  1219.     cw->canresp = (char*) alloc(strlen(str)+2);
  1220.     cw->canresp[0] = ch;            /* this could be NUL? */
  1221.     Strcpy(&cw->canresp[1], str);
  1222.     Strcat(cw->resp, str);
  1223.     }
  1224.     if(morestr) {
  1225.     unsigned int len = strlen(morestr) + 1;
  1226.     cw->morestr = (char*) alloc(len);
  1227.     Strcpy(cw->morestr, morestr);
  1228.     if(++len > cw->maxcol)    /* add one to avoid using the rtmost column */
  1229.         cw->maxcol = len;
  1230.     }
  1231. }
  1232.  
  1233. char
  1234. tty_select_menu(window)
  1235.     winid window;
  1236. {
  1237.     register struct WinDesc *cw = 0;
  1238.  
  1239.     morc = 0;
  1240.     if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0
  1241.        || cw->type != NHW_MENU)
  1242.     panic(winpanicstr,  window);
  1243.     tty_display_nhwindow(window, TRUE);
  1244.     tty_dismiss_nhwindow(window);
  1245.  
  1246.     return morc;
  1247. }
  1248.  
  1249. void
  1250. tty_update_inventory()
  1251. {
  1252. }
  1253.  
  1254. void
  1255. tty_mark_synch()
  1256. {
  1257.     (void) fflush(stdout);
  1258. }
  1259.  
  1260. void
  1261. tty_wait_synch()
  1262. {
  1263.     /* we just need to make sure all windows are synch'd */
  1264.     if(!ttyDisplay || ttyDisplay->rawprint) {
  1265.     getret();
  1266.     if(ttyDisplay) ttyDisplay->rawprint = 0;
  1267.     } else {
  1268.     tty_display_nhwindow(WIN_MAP, FALSE);
  1269.     if(ttyDisplay->inmore) {
  1270.         addtopl("--More--");
  1271.         (void) fflush(stdout);
  1272.     } else if(ttyDisplay->inread) {
  1273.         /* this can only happen if we were reading and got interrupted */
  1274.         ttyDisplay->toplin = 3;
  1275.         /* do this twice; 1st time gets the Quit? message again */
  1276.         (void) tty_doprev_message();
  1277.         (void) tty_doprev_message();
  1278.         ttyDisplay->intr++;
  1279.         (void) fflush(stdout);
  1280.     }
  1281.     }
  1282. }
  1283.  
  1284. void
  1285. docorner(xmin, ymax)
  1286.     register int xmin, ymax;
  1287. {
  1288.     register int y;
  1289.     register struct WinDesc *cw = wins[WIN_MAP];
  1290.  
  1291.     if (u.uswallow) {    /* Can be done more efficiently */
  1292.     swallowed(1);
  1293.     return;
  1294.     }
  1295.  
  1296. #if defined(SIGWINCH) && defined(CLIPPING)
  1297.     if(ymax > LI) ymax = LI;        /* can happen if window gets smaller */
  1298. #endif
  1299.     for (y = 0; y < ymax; y++) {
  1300.     tty_curs(BASE_WINDOW, xmin,y);    /* move cursor */
  1301.     cl_end();            /* clear to end of line */
  1302. #ifdef CLIPPING
  1303.     if (y<(int) cw->offy || y+clipy > ROWNO)
  1304.         continue; /* only refresh board */
  1305.     row_refresh(xmin+clipx-(int)cw->offx,COLNO-1,y+clipy-(int)cw->offy);
  1306. #else
  1307.     if (y<cw->offy || y > ROWNO) continue; /* only refresh board  */
  1308.     row_refresh(xmin-(int)cw->offx,COLNO-1,y-(int)cw->offy);
  1309. #endif
  1310.     }
  1311.  
  1312.     end_glyphout();
  1313.     if (ymax >= (int) wins[WIN_STATUS]->offy) {
  1314.                     /* we have wrecked the bottom line */
  1315.     flags.botlx = 1;
  1316.     bot();
  1317.     }
  1318. }
  1319.  
  1320. void
  1321. end_glyphout()
  1322. {
  1323. #if defined(ASCIIGRAPH) && !defined(NO_TERMS)
  1324.     if (GFlag) {
  1325.     GFlag = FALSE;
  1326.     graph_off();
  1327.     }
  1328. #endif
  1329. #ifdef TEXTCOLOR
  1330.     if(ttyDisplay->color != NO_COLOR) {
  1331.     term_end_color();
  1332.     ttyDisplay->color = NO_COLOR;
  1333.     }
  1334. #endif
  1335. }
  1336.  
  1337. void
  1338. g_putch(in_ch)
  1339. int in_ch;
  1340. {
  1341.     register char ch = (char)in_ch;
  1342.  
  1343. # if defined(ASCIIGRAPH) && !defined(NO_TERMS)
  1344.     if (flags.IBMgraphics)
  1345.     /* IBM-compatible displays don't need other stuff */
  1346.     (void) putchar(ch);
  1347.     else if (ch & 0x80) {
  1348.     if (!GFlag) {
  1349.         graph_on();
  1350.         GFlag = TRUE;
  1351.     }
  1352.     (void) putchar((ch ^ 0x80)); /* Strip 8th bit */
  1353.     } else {
  1354.     if (GFlag) {
  1355.         graph_off();
  1356.         GFlag = FALSE;
  1357.     }
  1358.     (void) putchar(ch);
  1359.     }
  1360.  
  1361. #else
  1362.     (void) putchar(ch);
  1363.  
  1364. #endif    /* ASCIIGRAPH && !NO_TERMS */
  1365.  
  1366.     return;
  1367. }
  1368.  
  1369. #ifdef CLIPPING
  1370. void
  1371. setclipped()
  1372. {
  1373.     clipping = TRUE;
  1374.     clipx = clipy = 0;
  1375.     clipxmax = CO;
  1376.     clipymax = LI - 3;
  1377. }
  1378.  
  1379. void
  1380. tty_cliparound(x, y)
  1381. int x, y;
  1382. {
  1383.     int oldx = clipx, oldy = clipy;
  1384.  
  1385.     if (!clipping) return;
  1386.     if (x < clipx + 5) {
  1387.         clipx = max(0, x - 20);
  1388.         clipxmax = clipx + CO;
  1389.     }
  1390.     else if (x > clipxmax - 5) {
  1391.         clipxmax = min(COLNO, clipxmax + 20);
  1392.         clipx = clipxmax - CO;
  1393.     }
  1394.     if (y < clipy + 2) {
  1395.         clipy = max(0, y - (clipymax - clipy) / 2);
  1396.         clipymax = clipy + (LI - 3);
  1397.     }
  1398.     else if (y > clipymax - 2) {
  1399.         clipymax = min(ROWNO, clipymax + (clipymax - clipy) / 2);
  1400.         clipy = clipymax - (LI - 3);
  1401.     }
  1402.     if (clipx != oldx || clipy != oldy) {
  1403.         (void) doredraw();
  1404.     }
  1405. }
  1406. #endif /* CLIPPING */
  1407.  
  1408.  
  1409. /*
  1410.  *  tty_print_glyph
  1411.  *
  1412.  *  Print the glyph to the output device.  Don't flush the output device.
  1413.  *
  1414.  *  Since this is only called from show_glyph(), it is assumed that the
  1415.  *  position and glyph are always correct (checked there)!
  1416.  */
  1417. void
  1418. tty_print_glyph(window, x, y, glyph)
  1419.     winid window;
  1420.     xchar x, y;
  1421.     int glyph;
  1422. {
  1423.     uchar   ch;
  1424.     register int offset;
  1425. #ifdef TEXTCOLOR
  1426.     int        color;
  1427.  
  1428. #define zap_color(n)  color = flags.use_color ? zapcolors[n] : NO_COLOR
  1429. #define cmap_color(n) color = flags.use_color ? defsyms[n].color : NO_COLOR
  1430. #define trap_color(n) color = flags.use_color ? \
  1431.                 (((n) == WEB) ? defsyms[S_web ].color  : \
  1432.                         defsyms[S_trap].color) : \
  1433.                         NO_COLOR
  1434. #define obj_color(n)  color = flags.use_color ? objects[n].oc_color : NO_COLOR
  1435. #define mon_color(n)  color = flags.use_color ? mons[n].mcolor : NO_COLOR
  1436. #define pet_color(n)  color = flags.use_color ? mons[n].mcolor :          \
  1437.                 /* If no color, try to hilite pets; black  */ \
  1438.                 /* should be HI                   */ \
  1439.                 ((flags.hilite_pet && has_color(BLACK)) ?     \
  1440.                             BLACK : NO_COLOR)
  1441.  
  1442. # else /* no text color */
  1443.  
  1444. #define zap_color(n)
  1445. #define cmap_color(n)
  1446. #define trap_color(n)
  1447. #define obj_color(n)
  1448. #define mon_color(n)
  1449. #define pet_color(c)
  1450. #endif
  1451.  
  1452. #ifdef CLIPPING
  1453.     if(clipping) {
  1454.     if(x <= clipx || y < clipy || x >= clipxmax || y >= clipymax)
  1455.         return;
  1456.     }
  1457. #endif
  1458.     /*
  1459.      *  Map the glyph back to a character.
  1460.      *
  1461.      *  Warning:  For speed, this makes an assumption on the order of
  1462.      *          offsets.  The order is set in display.h.
  1463.      */
  1464.     if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) {        /* swallow */
  1465.     /* see swallow_to_glyph() in display.c */
  1466.     ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)];
  1467.     mon_color(offset >> 3);
  1468.     } else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) {    /* zap beam */
  1469.     /* see zapdir_to_glyph() in display.c */
  1470.     ch = showsyms[S_vbeam + (offset & 0x3)];
  1471.     zap_color((offset >> 2));
  1472.     } else if ((offset = (glyph - GLYPH_CMAP_OFF)) >= 0) {    /* cmap */
  1473.     ch = showsyms[offset];
  1474.     cmap_color(offset);
  1475.     } else if ((offset = (glyph - GLYPH_TRAP_OFF)) >= 0) {    /* trap */
  1476.     ch = (offset == WEB) ? showsyms[S_web] : showsyms[S_trap];
  1477.     trap_color(offset);
  1478.     } else if ((offset = (glyph - GLYPH_OBJ_OFF)) >= 0) {    /* object */
  1479.     ch = oc_syms[(int)objects[offset].oc_class];
  1480.     obj_color(offset);
  1481.     } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) {    /* a corpse */
  1482.     ch = oc_syms[(int)objects[CORPSE].oc_class];
  1483.     mon_color(offset);
  1484.     } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) {    /* a pet */
  1485.     ch = monsyms[(int)mons[offset].mlet];
  1486.     pet_color(offset);
  1487.     } else {                            /* a monster */
  1488.     ch = monsyms[(int)mons[glyph].mlet];
  1489.     mon_color(glyph);
  1490.     }
  1491.  
  1492.     /* Move the cursor. */
  1493.     tty_curs(window, x,y);
  1494.  
  1495. #ifndef NO_TERMS
  1496.     if (ul_hack && ch == '_') {        /* non-destructive underscore */
  1497.     (void) putchar((char) ' ');
  1498.     backsp();
  1499.     }
  1500. #endif
  1501.  
  1502. #ifdef TEXTCOLOR
  1503.     /* Turn off color if no color defined, or rogue level. */
  1504. #  ifdef REINCARNATION
  1505.     if (!has_color(color) || Is_rogue_level(&u.uz))
  1506. #  else
  1507.     if (!has_color(color))
  1508. #  endif
  1509.     color = NO_COLOR;
  1510.  
  1511.     if (color != ttyDisplay->color) {
  1512.     if(ttyDisplay->color != NO_COLOR)
  1513.         term_end_color();
  1514.     ttyDisplay->color = color;
  1515.     if(color != NO_COLOR)
  1516.         term_start_color(color);
  1517.     }
  1518. #endif
  1519.     g_putch((int)ch);        /* print the character */
  1520.     wins[window]->curx++;    /* one character over */
  1521.     ttyDisplay->curx++;        /* the real cursor moved too */
  1522. }
  1523.  
  1524. void
  1525. tty_raw_print(str)
  1526.     const char *str;
  1527. {
  1528.     if(ttyDisplay) ttyDisplay->rawprint++;
  1529. #ifdef MICRO
  1530.     msmsg("%s\n", str);
  1531. #else
  1532.     puts(str); (void) fflush(stdout);
  1533. #endif
  1534. }
  1535.  
  1536. void
  1537. tty_raw_print_bold(str)
  1538.     const char *str;
  1539. {
  1540.     if(ttyDisplay) ttyDisplay->rawprint++;
  1541.     term_start_raw_bold();
  1542. #ifdef MICRO
  1543.     msmsg("%s", str);
  1544. #else
  1545.     (void) fputs(str, stdout);
  1546. #endif
  1547.     term_end_raw_bold();
  1548. #ifdef MICRO
  1549.     msmsg("\n");
  1550. #else
  1551.     puts("");
  1552.     (void) fflush(stdout);
  1553. #endif
  1554. }
  1555.  
  1556. int
  1557. tty_nhgetch()
  1558. {
  1559.     int i;
  1560. #ifdef UNIX
  1561.     /* kludge alert: Some Unix variants return funny values if getc()
  1562.      * is called, interrupted, and then called again.  There
  1563.      * is non-reentrant code in the internal _filbuf() routine, called by
  1564.      * getc().
  1565.      */
  1566.     static volatile int nesting = 0;
  1567.     char nestbuf;
  1568. #endif
  1569.  
  1570.     (void) fflush(stdout);
  1571.     /* Note: if raw_print() and wait_synch() get called to report terminal
  1572.      * initialization problems, then wins[] and ttyDisplay might not be
  1573.      * available yet.  Such problems will probably be fatal before we get
  1574.      * here, but validate those pointers just in case...
  1575.      */
  1576.     if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE])
  1577.         wins[WIN_MESSAGE]->flags &= ~WIN_STOP;
  1578. #ifdef UNIX
  1579.     i = ((++nesting == 1) ? tgetch() :
  1580.      (read(fileno(stdin), (genericptr_t)&nestbuf,1) == 1 ? (int)nestbuf :
  1581.                                 EOF));
  1582.     --nesting;
  1583. #else
  1584.     i = tgetch();
  1585. #endif
  1586.     if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
  1587.     if (ttyDisplay && ttyDisplay->toplin == 1)
  1588.     ttyDisplay->toplin = 2;
  1589.     return i;
  1590. }
  1591.  
  1592. /*
  1593.  * return a key, or 0, in which case a mouse button was pressed
  1594.  * mouse events should be returned as character postitions in the map window.
  1595.  * Since normal tty's don't have mice, just return a key.
  1596.  */
  1597. /*ARGSUSED*/
  1598. int
  1599. tty_nh_poskey(x, y, mod)
  1600.     int *x, *y, *mod;
  1601. {
  1602.     return tty_nhgetch();
  1603. }
  1604.  
  1605. void
  1606. win_tty_init()
  1607. {
  1608. # if defined(WIN32CON)
  1609.     nttty_open();
  1610. # endif
  1611.     return;
  1612. }
  1613.  
  1614. #endif /* TTY_GRAPHICS */
  1615. /*wintty.c*/
  1616.