OSDN Git Service

[Refactor] #1473 Replaced casting_hex_flags() to reset_casting_flag()
[hengbandforosx/hengbandosx.git] / src / main-cap.cpp
1 /* File: main-cap.c */
2
3 /* Purpose: Support for "term.c" using "termcap" calls */
4
5 #include "io/exit-panic.h"
6 #include "system/angband.h"
7
8 #ifdef USE_CAP
9
10 /*
11  * This file is a total hack, but is often very helpful.  :-)
12  *
13  * This file allows use of the terminal without requiring the
14  * "curses" routines.  In fact, if "USE_HARDCODE" is defined,
15  * this file will attempt to use various hard-coded "vt100"
16  * escape sequences to also avoid the use of the "termcap"
17  * routines.  I do not know if this will work on System V.
18  *
19  * This file is intended for use only on those machines which are
20  * unable, for whatever reason, to compile the "main-gcu.c" file,
21  * but which seem to be able to support the "termcap" library, or
22  * which at least seem able to support "vt100" terminals.
23  *
24  * Large portions of this file were stolen from "main-gcu.c"
25  *
26  * This file incorrectly handles output to column 80, I think.
27  */
28
29 /*
30  * Require a "system"
31  */
32 #if !defined(USE_TERMCAP) && !defined(USE_HARDCODE)
33 #define USE_TERMCAP
34 #endif
35
36 /*
37  * Hack -- try to guess which systems use what commands
38  * Hack -- allow one of the "USE_Txxxxx" flags to be pre-set.
39  * Mega-Hack -- try to guess when "POSIX" is available.
40  * If the user defines two of these, we will probably crash.
41  */
42 #ifdef _POSIX_VERSION
43 #define USE_TPOSIX
44 #else
45 #define USE_TCHARS
46 #endif
47
48 /*
49  * POSIX stuff
50  */
51 #ifdef USE_TPOSIX
52 #include <sys/ioctl.h>
53 #include <termios.h>
54 #endif
55
56 /*
57  * One version needs these files
58  */
59 #ifdef USE_TERMIO
60 #include <sys/ioctl.h>
61 #include <termio.h>
62 #endif
63
64 /*
65  * The other needs these files
66  */
67 #ifdef USE_TCHARS
68 #include <sys/file.h>
69 #include <sys/ioctl.h>
70 #include <sys/param.h>
71 #include <sys/resource.h>
72 #include <sys/types.h>
73 #endif
74
75 /*
76  * XXX XXX Hack -- POSIX uses "O_NONBLOCK" instead of "O_NDELAY"
77  *
78  * They should both work due to the "(i != 1)" test in the code
79  * which checks for the result of the "read()" command.
80  */
81 #ifndef O_NDELAY
82 #define O_NDELAY O_NONBLOCK
83 #endif
84
85 #ifdef USE_TERMCAP
86
87 /*
88  * Termcap string information
89  */
90
91 static char blob[1024]; /* The "termcap" entry */
92 static char area[1024]; /* The string extraction buffer */
93 static char *next = area; /* The current "index" into "area" */
94 static char *desc; /* The terminal name */
95
96 #endif
97
98 /*
99  * Pointers into the "area"
100  */
101
102 static char *cm; /* Move cursor */
103 static char *ch; /* Move cursor to horizontal location */
104 static char *cv; /* Move cursor to vertical location */
105 static char *ho; /* Move cursor to top left */
106 static char *ll; /* Move cursor to bottom left */
107 static char *cs; /* Set scroll area */
108 static char *cl; /* Clear screen */
109 static char *cd; /* Clear to end of display */
110 static char *ce; /* Clear to end of line */
111 static char *cr; /* Move to start of line */
112 static char *so; /* Turn on standout */
113 static char *se; /* Turn off standout */
114 static char *md; /* Turn on bold */
115 static char *me; /* Turn off bold */
116 static char *vi; /* Cursor - invisible */
117 static char *ve; /* Cursor - normal */
118 static char *vs; /* Cursor - bright */
119
120 /*
121  * State variables
122  */
123
124 static int rows; /* Screen size (Y) */
125 static int cols; /* Screen size (X) */
126 static int curx; /* Cursor location (X) */
127 static int cury; /* Cursor location (Y) */
128 static int curv; /* Cursor visibility */
129
130 /*
131  * Extern functions
132  */
133 extern char *getenv();
134 extern char *tgoto();
135 extern char *tgetstr();
136
137 /*
138  * Write some chars to the terminal
139  */
140 static void ewrite(char *str)
141 {
142     int numtowrite, numwritten;
143
144     /* See how much work we have */
145     numtowrite = strlen(str);
146
147     /* Write until done */
148     while (numtowrite > 0) {
149         /* Try to write the chars */
150         numwritten = write(1, str, numtowrite);
151
152         /* Handle FIFOs and EINTR */
153         if (numwritten < 0)
154             numwritten = 0;
155
156         /* See what we completed */
157         numtowrite -= numwritten;
158         str += numwritten;
159
160         /* Hack -- sleep if not done */
161         if (numtowrite > 0)
162             sleep(1);
163     }
164 }
165
166 #ifdef USE_TERMCAP
167
168 static char write_buffer[128];
169 static char *write_buffer_ptr;
170
171 static void output_one(char c)
172 {
173     *write_buffer_ptr++ = c;
174 }
175
176 static void tp(char *s)
177 {
178     /* Dump the string into us */
179     write_buffer_ptr = write_buffer;
180
181     /* Write the string with padding */
182     tputs(s, 1, output_one);
183
184     /* Finish the string */
185     *write_buffer_ptr = '\0';
186
187     /* Dump the recorded buffer */
188     ewrite(write_buffer);
189 }
190
191 #endif
192
193 #ifdef USE_HARDCODE
194
195 static void tp(char *s)
196 {
197     ewrite(s);
198 }
199
200 #endif
201
202 /*
203  * Clear the screen
204  */
205 static void do_cl(void)
206 {
207     if (cl)
208         tp(cl);
209 }
210
211 /*
212  * Clear to the end of the line
213  */
214 static void do_ce(void)
215 {
216     if (ce)
217         tp(ce);
218 }
219
220 /*
221  * Set the cursor visibility (0 = invis, 1 = normal, 2 = bright)
222  */
223 static void curs_set(int vis)
224 {
225     char *v = nullptr;
226
227     if (!vis) {
228         v = vi;
229     } else if (vis > 1) {
230         v = vs ? vs : ve;
231     } else {
232         v = ve ? ve : vs;
233     }
234
235     if (v)
236         tp(v);
237 }
238
239 /*
240  * Restrict scrolling to within these rows
241  */
242 static void do_cs(int y1, int y2)
243 {
244
245 #ifdef USE_TERMCAP
246     if (cs)
247         tp(tgoto(cs, y2, y1));
248 #endif
249
250 #ifdef USE_HARDCODE
251     char temp[64];
252     sprintf(temp, cs, y1, y2);
253     tp(temp);
254 #endif
255 }
256
257 /*
258  * Go to the given screen location directly
259  */
260 static void do_cm(int x, int y)
261 {
262
263 #ifdef USE_TERMCAP
264     if (cm)
265         tp(tgoto(cm, x, y));
266 #endif
267
268 #ifdef USE_HARDCODE
269     char temp[64];
270     sprintf(temp, cm, y + 1, x + 1);
271     tp(temp);
272 #endif
273 }
274
275 /*
276  * Go to the given screen location in a "clever" manner
277  *
278  * XXX XXX XXX This function could use some work!
279  */
280 static void do_move(int x1, int y1, int x2, int y2)
281 {
282     /* Hack -- unknown start location */
283     if ((x1 == x2) && (y1 == y2))
284         do_cm(x2, y2);
285
286     /* Left edge */
287     else if (x2 == 0) {
288         if ((y2 <= 0) && ho)
289             tp(ho);
290         else if ((y2 >= rows - 1) && ll)
291             tp(ll);
292         else if ((y2 == y1) && cr)
293             tp(cr);
294         else
295             do_cm(x2, y2);
296     }
297
298     /* Default -- go directly there */
299     else
300         do_cm(x2, y2);
301 }
302
303 /*
304  * Help initialize this file (see below)
305  */
306 errr init_cap_aux(void)
307 {
308
309 #ifdef USE_TERMCAP
310
311     /* Get the terminal name (if possible) */
312     desc = getenv("TERM");
313     if (!desc)
314         return (1);
315
316     /* Get the terminal info */
317     if (tgetent(blob, desc) != 1)
318         return (2);
319
320     /* Get the (initial) columns and rows, or default */
321     if ((cols = tgetnum("co")) == -1)
322         cols = 80;
323     if ((rows = tgetnum("li")) == -1)
324         rows = 24;
325
326     /* Find out how to move the cursor to a given location */
327     cm = tgetstr("cm", &next);
328     if (!cm)
329         return (10);
330
331     /* Find out how to move the cursor to a given position */
332     ch = tgetstr("ch", &next);
333     cv = tgetstr("cv", &next);
334
335     /* Find out how to "home" the screen */
336     ho = tgetstr("ho", &next);
337
338     /* Find out how to "last-line" the screen */
339     ll = tgetstr("ll", &next);
340
341     /* Find out how to do a "carriage return" */
342     cr = tgetstr("cr", &next);
343     if (!cr)
344         cr = "\r";
345
346     /* Find out how to clear the screen */
347     cl = tgetstr("cl", &next);
348     if (!cl)
349         return (11);
350
351     /* Find out how to clear to the end of display */
352     cd = tgetstr("cd", &next);
353
354     /* Find out how to clear to the end of the line */
355     ce = tgetstr("ce", &next);
356
357     /* Find out how to scroll (set the scroll region) */
358     cs = tgetstr("cs", &next);
359
360     /* Find out how to hilite */
361     so = tgetstr("so", &next);
362     se = tgetstr("se", &next);
363     if (!so || !se)
364         so = se = nullptr;
365
366     /* Find out how to bold */
367     md = tgetstr("md", &next);
368     me = tgetstr("me", &next);
369     if (!md || !me)
370         md = me = nullptr;
371
372     /* Check the cursor visibility stuff */
373     vi = tgetstr("vi", &next);
374     vs = tgetstr("vs", &next);
375     ve = tgetstr("ve", &next);
376
377 #endif
378
379 #ifdef USE_HARDCODE
380
381     /* Assume some defualt information */
382     rows = 24;
383     cols = 80;
384
385     /* Clear screen */
386     cl = "\033[2J\033[H"; /* --]--]-- */
387
388     /* Clear to end of line */
389     ce = "\033[K"; /* --]-- */
390
391     /* Hilite on/off */
392     so = "\033[7m"; /* --]-- */
393     se = "\033[m"; /* --]-- */
394
395     /* Scroll region */
396     cs = "\033[%d;%dr"; /* --]-- */
397
398     /* Move cursor */
399     cm = "\033[%d;%dH"; /* --]-- */
400
401 #endif
402
403     /* Success */
404     return (0);
405 }
406
407 /*
408  * Save the "normal" and "angband" terminal settings
409  */
410
411 #ifdef USE_TPOSIX
412
413 static struct termios norm_termios;
414
415 static struct termios game_termios;
416
417 #endif
418
419 #ifdef USE_TERMIO
420
421 static struct termio norm_termio;
422
423 static struct termio game_termio;
424
425 #endif
426
427 #ifdef USE_TCHARS
428
429 static struct sgttyb norm_ttyb;
430 static struct tchars norm_tchars;
431 static struct ltchars norm_ltchars;
432 static int norm_local_chars;
433
434 static struct sgttyb game_ttyb;
435 static struct tchars game_tchars;
436 static struct ltchars game_ltchars;
437 static int game_local_chars;
438
439 #endif
440
441 /*
442  * Are we active?  Not really needed.
443  */
444 static int active = false;
445
446 /*
447  * The main screen (no sub-screens)
448  */
449 static term term_screen_body;
450
451 /*
452  * Place the "keymap" into its "normal" state
453  */
454 static void keymap_norm(void)
455 {
456
457 #ifdef USE_TPOSIX
458
459     /* restore the saved values of the special chars */
460     (void)tcsetattr(0, TCSAFLUSH, &norm_termios);
461
462 #endif
463
464 #ifdef USE_TERMIO
465
466     /* restore the saved values of the special chars */
467     (void)ioctl(0, TCSETA, (char *)&norm_termio);
468
469 #endif
470
471 #ifdef USE_TCHARS
472
473     /* restore the saved values of the special chars */
474     (void)ioctl(0, TIOCSETP, (char *)&norm_ttyb);
475     (void)ioctl(0, TIOCSETC, (char *)&norm_tchars);
476     (void)ioctl(0, TIOCSLTC, (char *)&norm_ltchars);
477     (void)ioctl(0, TIOCLSET, (char *)&norm_local_chars);
478
479 #endif
480 }
481
482 /*
483  * Place the "keymap" into the "game" state
484  */
485 static void keymap_game(void)
486 {
487
488 #ifdef USE_TPOSIX
489
490     /* restore the saved values of the special chars */
491     (void)tcsetattr(0, TCSAFLUSH, &game_termios);
492
493 #endif
494
495 #ifdef USE_TERMIO
496
497     /* restore the saved values of the special chars */
498     (void)ioctl(0, TCSETA, (char *)&game_termio);
499
500 #endif
501
502 #ifdef USE_TCHARS
503
504     /* restore the saved values of the special chars */
505     (void)ioctl(0, TIOCSETP, (char *)&game_ttyb);
506     (void)ioctl(0, TIOCSETC, (char *)&game_tchars);
507     (void)ioctl(0, TIOCSLTC, (char *)&game_ltchars);
508     (void)ioctl(0, TIOCLSET, (char *)&game_local_chars);
509
510 #endif
511 }
512
513 /*
514  * Save the normal keymap
515  */
516 static void keymap_norm_prepare(void)
517 {
518
519 #ifdef USE_TPOSIX
520
521     /* Get the normal keymap */
522     tcgetattr(0, &norm_termios);
523
524 #endif
525
526 #ifdef USE_TERMIO
527
528     /* Get the normal keymap */
529     (void)ioctl(0, TCGETA, (char *)&norm_termio);
530
531 #endif
532
533 #ifdef USE_TCHARS
534
535     /* Get the normal keymap */
536     (void)ioctl(0, TIOCGETP, (char *)&norm_ttyb);
537     (void)ioctl(0, TIOCGETC, (char *)&norm_tchars);
538     (void)ioctl(0, TIOCGLTC, (char *)&norm_ltchars);
539     (void)ioctl(0, TIOCLGET, (char *)&norm_local_chars);
540
541 #endif
542 }
543
544 /*
545  * Save the keymaps (normal and game)
546  */
547 static void keymap_game_prepare(void)
548 {
549
550 #ifdef USE_TPOSIX
551
552     /* Acquire the current mapping */
553     tcgetattr(0, &game_termios);
554
555     /* Force "Ctrl-C" to interupt */
556     game_termios.c_cc[VINTR] = (char)3;
557
558     /* Force "Ctrl-Z" to suspend */
559     game_termios.c_cc[VSUSP] = (char)26;
560
561     /* Hack -- Leave "VSTART/VSTOP" alone */
562
563     /* Disable the standard control characters */
564     game_termios.c_cc[VQUIT] = (char)-1;
565     game_termios.c_cc[VERASE] = (char)-1;
566     game_termios.c_cc[VKILL] = (char)-1;
567     game_termios.c_cc[VEOF] = (char)-1;
568     game_termios.c_cc[VEOL] = (char)-1;
569
570     /* Normally, block until a character is read */
571     game_termios.c_cc[VMIN] = 1;
572     game_termios.c_cc[VTIME] = 0;
573
574     /* Hack -- Turn off "echo" and "canonical" mode */
575     game_termios.c_lflag &= ~(ECHO | ICANON);
576
577     /* Turn off flow control */
578     game_termios.c_iflag &= ~IXON;
579
580 #endif
581
582 #ifdef USE_TERMIO
583
584     /* Acquire the current mapping */
585     (void)ioctl(0, TCGETA, (char *)&game_termio);
586
587     /* Force "Ctrl-C" to interupt */
588     game_termio.c_cc[VINTR] = (char)3;
589
590     /* Force "Ctrl-Z" to suspend */
591     game_termio.c_cc[VSUSP] = (char)26;
592
593     /* Hack -- Leave "VSTART/VSTOP" alone */
594
595     /* Disable the standard control characters */
596     game_termio.c_cc[VQUIT] = (char)-1;
597     game_termio.c_cc[VERASE] = (char)-1;
598     game_termio.c_cc[VKILL] = (char)-1;
599     game_termio.c_cc[VEOF] = (char)-1;
600     game_termio.c_cc[VEOL] = (char)-1;
601
602     /* Normally, block until a character is read */
603     game_termio.c_cc[VMIN] = 1;
604     game_termio.c_cc[VTIME] = 0;
605
606     /* Hack -- Turn off "echo" and "canonical" mode */
607     game_termio.c_lflag &= ~(ECHO | ICANON);
608
609     /* Turn off flow control */
610     game_termio.c_iflag &= ~IXON;
611
612 #endif
613
614 #ifdef USE_TCHARS
615
616     /* Get the default game characters */
617     (void)ioctl(0, TIOCGETP, (char *)&game_ttyb);
618     (void)ioctl(0, TIOCGETC, (char *)&game_tchars);
619     (void)ioctl(0, TIOCGLTC, (char *)&game_ltchars);
620     (void)ioctl(0, TIOCLGET, (char *)&game_local_chars);
621
622     /* Force interupt (^C) */
623     game_tchars.t_intrc = (char)3;
624
625     /* Force start/stop (^Q, ^S) */
626     game_tchars.t_startc = (char)17;
627     game_tchars.t_stopc = (char)19;
628
629     /* Cancel some things */
630     game_tchars.t_quitc = (char)-1;
631     game_tchars.t_eofc = (char)-1;
632     game_tchars.t_brkc = (char)-1;
633
634     /* Force suspend (^Z) */
635     game_ltchars.t_suspc = (char)26;
636
637     /* Cancel some things */
638     game_ltchars.t_dsuspc = (char)-1;
639     game_ltchars.t_rprntc = (char)-1;
640     game_ltchars.t_flushc = (char)-1;
641     game_ltchars.t_werasc = (char)-1;
642     game_ltchars.t_lnextc = (char)-1;
643
644     /* XXX XXX XXX XXX Verify this before use */
645     /* Hack -- Turn off "echo" and "canonical" mode */
646     /* game_termios.c_lflag &= ~(ECHO | ICANON); */
647     game_ttyb.flag &= ~(ECHO | ICANON);
648
649     /* XXX XXX XXX  Should maybe turn off flow control too.  How? */
650
651 #endif
652 }
653
654 /*
655  * Suspend/Resume
656  */
657 static errr Term_xtra_cap_alive(int v)
658 {
659     /* Suspend */
660     if (!v) {
661         if (!active)
662             return (1);
663
664         /* Hack -- make sure the cursor is visible */
665         curs_set(1);
666
667         /* Move to bottom right */
668         do_move(0, rows - 1, 0, rows - 1);
669
670         /* Go to normal keymap mode */
671         keymap_norm();
672
673         /* No longer active */
674         active = false;
675     }
676
677     /* Resume */
678     else {
679         if (active)
680             return (1);
681
682         /* Hack -- restore the cursor location */
683         do_move(curx, cury, curx, cury);
684
685         /* Hack -- restore the cursor visibility */
686         curs_set(curv);
687
688         /* Go to angband keymap mode */
689         keymap_game();
690
691         /* Now we are active */
692         active = true;
693     }
694
695     /* Success */
696     return (0);
697 }
698
699 /*
700  * Process an event
701  */
702 static errr Term_xtra_cap_event(int v)
703 {
704     int i, arg;
705     char buf[2];
706
707     /* Wait */
708     if (v) {
709         /* Wait for one byte */
710         i = read(0, buf, 1);
711
712         /* Hack -- Handle "errors" */
713         if ((i <= 0) && (errno != EINTR))
714             exit_game_panic(p_ptr);
715     }
716
717     /* Do not wait */
718     else {
719         /* Get the current flags for stdin */
720         if ((arg = fcntl(0, F_GETFL, 0)) < 1)
721             return (1);
722
723         /* Tell stdin not to block */
724         if (fcntl(0, F_SETFL, arg | O_NDELAY) < 0)
725             return (1);
726
727         /* Read one byte, if possible */
728         i = read(0, buf, 1);
729
730         /* Replace the flags for stdin */
731         if (fcntl(0, F_SETFL, arg))
732             return (1);
733     }
734
735     /* No keys ready */
736     if ((i != 1) || (!buf[0]))
737         return (1);
738
739     /* Enqueue the keypress */
740     Term_keypress(buf[0]);
741
742     /* Success */
743     return (0);
744 }
745
746 /*
747  * Actually move the hardware cursor
748  */
749 static errr Term_curs_cap(int x, int y)
750 {
751     /* Literally move the cursor */
752     do_move(curx, cury, x, y);
753
754     /* Save the cursor location */
755     curx = x;
756     cury = y;
757
758     /* Success */
759     return (0);
760 }
761
762 /*
763  * Erase a grid of space
764  *
765  * XXX XXX XXX Note that we will never be asked to clear the
766  * bottom line all the way to the bottom right edge, since we
767  * have set the "avoid the bottom right corner" flag.
768  */
769 static errr Term_wipe_cap(int x, int y, int n)
770 {
771     int dx;
772
773     /* Place the cursor */
774     Term_curs_cap(x, y);
775
776     /* Wipe to end of line */
777     if (x + n >= 80) {
778         do_ce();
779     }
780
781     /* Wipe region */
782     else {
783         for (dx = 0; dx < n; ++dx) {
784             putc(' ', stdout);
785             curx++;
786         }
787     }
788
789     /* Success */
790     return (0);
791 }
792
793 /*
794  * Place some text on the screen using an attribute
795  */
796 static errr Term_text_cap(int x, int y, int n, byte a, concptr s)
797 {
798     int i;
799
800     /* Move the cursor */
801     Term_curs_cap(x, y);
802
803     /* Dump the text, advance the cursor */
804     for (i = 0; s[i]; i++) {
805         /* Dump the char */
806         putc(s[i], stdout);
807
808         /* Advance cursor 'X', and wrap */
809         if (++curx >= cols) {
810             /* Reset cursor 'X' */
811             curx = 0;
812
813             /* Hack -- Advance cursor 'Y', and wrap */
814             if (++cury == rows)
815                 cury = 0;
816         }
817     }
818
819     /* Success */
820     return (0);
821 }
822
823 /*
824  * Handle a "special request"
825  */
826 static errr Term_xtra_cap(int n, int v)
827 {
828     /* Analyze the request */
829     switch (n) {
830     /* Clear the screen */
831     case TERM_XTRA_CLEAR:
832         do_cl();
833         do_move(0, 0, 0, 0);
834         return (0);
835
836     /* Make a noise */
837     case TERM_XTRA_NOISE:
838         (void)write(1, "\007", 1);
839         return (0);
840
841     /* Change the cursor visibility */
842     case TERM_XTRA_SHAPE:
843         curv = v;
844         curs_set(v);
845         return (0);
846
847     /* Suspend/Resume */
848     case TERM_XTRA_ALIVE:
849         return (Term_xtra_cap_alive(v));
850
851     /* Process events */
852     case TERM_XTRA_EVENT:
853         return (Term_xtra_cap_event(v));
854
855     /* Flush events */
856     case TERM_XTRA_FLUSH:
857         while (!Term_xtra_cap_event(false))
858             ;
859         return (0);
860
861     /* Delay */
862     case TERM_XTRA_DELAY:
863         usleep(1000 * v);
864         return (0);
865     }
866
867     /* Not parsed */
868     return (1);
869 }
870
871 /*
872  * Init a "term" for this file
873  */
874 static void Term_init_cap(term *t)
875 {
876     if (active)
877         return;
878
879     /* Assume cursor at top left */
880     curx = 0;
881     cury = 0;
882
883     /* Assume visible cursor */
884     curv = 1;
885
886     /* Clear the screen */
887     do_cl();
888
889     /* Hack -- visible cursor */
890     curs_set(1);
891
892     /* Assume active */
893     active = true;
894 }
895
896 /*
897  * Nuke a "term" for this file
898  */
899 static void Term_nuke_cap(term *t)
900 {
901     if (!active)
902         return;
903
904     /* Hack -- make sure the cursor is visible */
905     curs_set(1);
906
907     /* Move to bottom right */
908     do_move(0, rows - 1, 0, rows - 1);
909
910     /* Normal keymap */
911     keymap_norm();
912
913     /* No longer active */
914     active = false;
915 }
916
917 /*
918  * Prepare this file for Angband usage
919  */
920 errr init_cap(void)
921 {
922     term *t = &term_screen_body;
923
924     /*** Initialize ***/
925
926     /* Initialize the screen */
927     if (init_cap_aux())
928         return (-1);
929
930     /* Hack -- Require large screen, or Quit with message */
931     if ((rows < 24) || (cols < 80))
932         quit("Screen too small!");
933
934     /*** Prepare to play ***/
935
936     /* Extract the normal keymap */
937     keymap_norm_prepare();
938
939     /* Extract the game keymap */
940     keymap_game_prepare();
941
942     /* Hack -- activate the game keymap */
943     keymap_game();
944
945     /* Hack -- Do NOT buffer stdout */
946     setbuf(stdout, nullptr);
947
948     /*** Now prepare the term ***/
949
950     /* Initialize the term */
951     term_init(t, 80, 24, 256);
952
953     /* Avoid the bottom right corner */
954     t->icky_corner = true;
955
956     /* Erase with "white space" */
957     t->attr_blank = TERM_WHITE;
958     t->char_blank = ' ';
959
960     /* Set some hooks */
961     t->init_hook = Term_init_cap;
962     t->nuke_hook = Term_nuke_cap;
963
964     /* Set some more hooks */
965     t->text_hook = Term_text_cap;
966     t->wipe_hook = Term_wipe_cap;
967     t->curs_hook = Term_curs_cap;
968     t->xtra_hook = Term_xtra_cap;
969
970     /* Save the term */
971     term_screen = t;
972
973     /* Activate it */
974     Term_activate(term_screen);
975
976     /* Success */
977     return (0);
978 }
979
980 #endif /* USE_CAP */