OSDN Git Service

再びエンバグ修正。タイルの1byte目を表す 0x80 と Bigtile の2byte目を表
[hengband/hengband.git] / src / z-term.c
1 /* File: z-term.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10
11 /* Purpose: a generic, efficient, terminal window package -BEN- */
12 #include "angband.h"
13
14 #include "z-term.h"
15
16 #include "z-virt.h"
17
18 /* Special flags in the attr data */
19 #define AF_BIGTILE2 0xf0
20
21 #ifdef JP
22 #define AF_TILE1   0x80
23 #define AF_KANJI1  0x10
24 #define AF_KANJI2  0x20
25 #define AF_KANJIC  0x0f
26 /*
27  * Á´³Ñʸ»úÂбþ¡£
28  * Â°À­¤ËÁ´³Ñʸ»ú¤Î£±¥Ð¥¤¥ÈÌÜ¡¢£²¥Ð¥¤¥ÈÌܤ⵭²±¡£
29  * By FIRST
30  */
31 #endif
32 /*
33  * This file provides a generic, efficient, terminal window package,
34  * which can be used not only on standard terminal environments such
35  * as dumb terminals connected to a Unix box, but also in more modern
36  * "graphic" environments, such as the Macintosh or Unix/X11.
37  *
38  * Each "window" works like a standard "dumb terminal", that is, it
39  * can display a two dimensional array of grids containing colored
40  * textual symbols, plus an optional cursor, and it can be used to
41  * get keypress events from the user.
42  *
43  * In fact, this package can simply be used, if desired, to support
44  * programs which will look the same on a dumb terminal as they do
45  * on a graphic platform such as the Macintosh.
46  *
47  * This package was designed to help port the game "Angband" to a wide
48  * variety of different platforms.  Angband, like many other games in
49  * the "rogue-like" heirarchy, requires, at the minimum, the ability
50  * to display "colored textual symbols" in a standard 80x24 "window",
51  * such as that provided by most dumb terminals, and many old personal
52  * computers, and to check for "keypresses" from the user.  The major
53  * concerns were thus portability and efficiency, so Angband could be
54  * easily ported to many different systems, with minimal effort, and
55  * yet would run quickly on each of these systems, no matter what kind
56  * of underlying hardware/software support was being used.
57  *
58  * It is important to understand the differences between the older
59  * "dumb terminals" and the newer "graphic interface" machines, since
60  * this package was designed to work with both types of systems.
61  *
62  * New machines:
63  *   waiting for a keypress is complex
64  *   checking for a keypress is often cheap
65  *   changing "colors" may be expensive
66  *   the "color" of a "blank" is rarely important
67  *   moving the "cursor" is relatively cheap
68  *   use a "software" cursor (only moves when requested)
69  *   drawing characters normally will not erase old ones
70  *   drawing a character on the cursor often erases it
71  *   may have fast routines for "clear a region"
72  *   the bottom right corner is usually not special
73  *
74  * Old machines:
75  *   waiting for a keypress is simple
76  *   checking for a keypress is often expensive
77  *   changing "colors" is usually cheap
78  *   the "color" of a "blank" may be important
79  *   moving the "cursor" may be expensive
80  *   use a "hardware" cursor (moves during screen updates)
81  *   drawing new symbols automatically erases old ones
82  *   characters may only be drawn at the cursor location
83  *   drawing a character on the cursor will move the cursor
84  *   may have fast routines for "clear entire window"
85  *   may have fast routines for "clear to end of line"
86  *   the bottom right corner is often dangerous
87  *
88  *
89  * This package provides support for multiple windows, each of an
90  * arbitrary size (up to 255x255), each with its own set of flags,
91  * and its own hooks to handle several low-level procedures which
92  * differ from platform to platform.  Then the main program simply
93  * creates one or more "term" structures, setting the various flags
94  * and hooks in a manner appropriate for the current platform, and
95  * then it can use the various "term" structures without worrying
96  * about the underlying platform.
97  *
98  *
99  * This package allows each "grid" in each window to hold an attr/char
100  * pair, with each ranging from 0 to 255, and makes very few assumptions
101  * about the meaning of any attr/char values.  Normally, we assume that
102  * "attr 0" is "black", with the semantics that "black" text should be
103  * sent to "Term_wipe()" instead of "Term_text()", but this sematics is
104  * modified if either the "always_pict" or the "always_text" flags are
105  * set.  We assume that "char 0" is "dangerous", since placing such a
106  * "char" in the middle of a string "terminates" the string, and usually
107  * we prevent its use.
108  *
109  * Finally, we use a special attr/char pair, defaulting to "attr 0" and
110  * "char 32", also known as "black space", when we "erase" or "clear"
111  * any window, but this pair can be redefined to any pair, including
112  * the standard "white space", or the bizarre "emptiness" ("attr 0"
113  * and "char 0"), as long as various obscure restrictions are met.
114  *
115  *
116  * This package provides several functions which allow a program to
117  * interact with the "term" structures.  Most of the functions allow
118  * the program to "request" certain changes to the current "term",
119  * such as moving the cursor, drawing an attr/char pair, erasing a
120  * region of grids, hiding the cursor, etc.  Then there is a special
121  * function which causes all of the "pending" requests to be performed
122  * in an efficient manner.  There is another set of functions which
123  * allow the program to query the "requested state" of the current
124  * "term", such as asking for the cursor location, or what attr/char
125  * is at a given location, etc.  There is another set of functions
126  * dealing with "keypress" events, which allows the program to ask if
127  * the user has pressed any keys, or to forget any keys the user pressed.
128  * There is a pair of functions to allow this package to memorize the
129  * contents of the current "term", and to restore these contents at
130  * a later time.  There is a special function which allows the program
131  * to specify which "term" structure should be the "current" one.  At
132  * the lowest level, there is a set of functions which allow a new
133  * "term" to be initialized or destroyed, and which allow this package,
134  * or a program, to access the special "hooks" defined for the current
135  * "term", and a set of functions which those "hooks" can use to inform
136  * this package of the results of certain occurances, for example, one
137  * such function allows this package to learn about user keypresses,
138  * detected by one of the special "hooks".
139  *
140  * We provide, among other things, the functions "Term_keypress()"
141  * to "react" to keypress events, and "Term_redraw()" to redraw the
142  * entire window, plus "Term_resize()" to note a new size.
143  *
144  *
145  * Note that the current "term" contains two "window images".  One of
146  * these images represents the "requested" contents of the "term", and
147  * the other represents the "actual" contents of the "term", at the time
148  * of the last performance of pending requests.  This package uses these
149  * two images to determine the "minimal" amount of work needed to make
150  * the "actual" contents of the "term" match the "requested" contents of
151  * the "term".  This method is not perfect, but it often reduces the
152  * amount of work needed to perform the pending requests, which thus
153  * increases the speed of the program itself.  This package promises
154  * that the requested changes will appear to occur either "all at once"
155  * or in a "top to bottom" order.  In addition, a "cursor" is maintained,
156  * and this cursor is updated along with the actual window contents.
157  *
158  * Currently, the "Term_fresh()" routine attempts to perform the "minimum"
159  * number of physical updates, in terms of total "work" done by the hooks
160  * Term_wipe(), Term_text(), and Term_pict(), making use of the fact that
161  * adjacent characters of the same color can both be drawn together using
162  * the "Term_text()" hook, and that "black" text can often be sent to the
163  * "Term_wipe()" hook instead of the "Term_text()" hook, and if something
164  * is already displayed in a window, then it is not necessary to display
165  * it again.  Unfortunately, this may induce slightly non-optimal results
166  * in some cases, in particular, those in which, say, a string of ten
167  * characters needs to be written, but the fifth character has already
168  * been displayed.  Currently, this will cause the "Term_text()" routine
169  * to be called once for each half of the string, instead of once for the
170  * whole string, which, on some machines, may be non-optimal behavior.
171  *
172  * The new formalism includes a "displayed" screen image (old) which
173  * is actually seen by the user, a "requested" screen image (scr)
174  * which is being prepared for display, a "memorized" screen image
175  * (mem) which is used to save and restore screen images, and a
176  * "temporary" screen image (tmp) which is currently unused.
177  *
178  *
179  * Several "flags" are available in each "term" to allow the underlying
180  * visual system (which initializes the "term" structure) to "optimize"
181  * the performance of this package for the given system, or to request
182  * certain behavior which is helpful/required for the given system.
183  *
184  * The "soft_cursor" flag indicates the use of a "soft" cursor, which
185  * only moves when explicitly requested,and which is "erased" when
186  * any characters are drawn on top of it.  This flag is used for all
187  * "graphic" systems which handle the cursor by "drawing" it.
188  *
189  * The "icky_corner" flag indicates that the bottom right "corner"
190  * of the windows are "icky", and "printing" anything there may
191  * induce "messy" behavior, such as "scrolling".  This flag is used
192  * for most old "dumb terminal" systems.
193  *
194  *
195  * The "term" structure contains the following function "hooks":
196  *
197  *   Term->init_hook = Init the term
198  *   Term->nuke_hook = Nuke the term
199  *   Term->user_hook = Perform user actions
200  *   Term->xtra_hook = Perform extra actions
201  *   Term->curs_hook = Draw (or Move) the cursor
202  *   Term->bigcurs_hook = Draw (or Move) the big cursor (bigtile mode)
203  *   Term->wipe_hook = Draw some blank spaces
204  *   Term->text_hook = Draw some text in the window
205  *   Term->pict_hook = Draw some attr/chars in the window
206  *
207  * The "Term->user_hook" hook provides a simple hook to an implementation
208  * defined function, with application defined semantics.  It is available
209  * to the program via the "Term_user()" function.
210  *
211  * The "Term->xtra_hook" hook provides a variety of different functions,
212  * based on the first parameter (which should be taken from the various
213  * TERM_XTRA_* defines) and the second parameter (which may make sense
214  * only for some first parameters).  It is available to the program via
215  * the "Term_xtra()" function, though some first parameters are only
216  * "legal" when called from inside this package.
217  *
218  * The "Term->curs_hook" hook provides this package with a simple way
219  * to "move" or "draw" the cursor to the grid "x,y", depending on the
220  * setting of the "soft_cursor" flag.  Note that the cursor is never
221  * redrawn if "nothing" has happened to the screen (even temporarily).
222  * This hook is required.
223  *
224  * The "Term->wipe_hook" hook provides this package with a simple way
225  * to "erase", starting at "x,y", the next "n" grids.  This hook assumes
226  * that the input is valid.  This hook is required, unless the setting
227  * of the "always_pict" or "always_text" flags makes it optional.
228  *
229  * The "Term->text_hook" hook provides this package with a simple way
230  * to "draw", starting at "x,y", the "n" chars contained in "cp", using
231  * the attr "a".  This hook assumes that the input is valid, and that
232  * "n" is between 1 and 256 inclusive, but it should NOT assume that
233  * the contents of "cp" are null-terminated.  This hook is required,
234  * unless the setting of the "always_pict" flag makes it optional.
235  *
236  * The "Term->pict_hook" hook provides this package with a simple way
237  * to "draw", starting at "x,y", the "n" attr/char pairs contained in
238  * the arrays "ap" and "cp".  This hook assumes that the input is valid,
239  * and that "n" is between 1 and 256 inclusive, but it should NOT assume
240  * that the contents of "cp" are null-terminated.  This hook is optional,
241  * unless the setting of the "always_pict" or "higher_pict" flags make
242  * it required.  Note that recently, this hook was changed from taking
243  * a byte "a" and a char "c" to taking a length "n", an array of bytes
244  * "ap" and an array of chars "cp".  Old implementations of this hook
245  * should now iterate over all "n" attr/char pairs.
246  *
247  *
248  * The game "Angband" uses a set of files called "main-xxx.c", for
249  * various "xxx" suffixes.  Most of these contain a function called
250  * "init_xxx()", that will prepare the underlying visual system for
251  * use with Angband, and then create one or more "term" structures,
252  * using flags and hooks appropriate to the given platform, so that
253  * the "main()" function can call one (or more) of the "init_xxx()"
254  * functions, as appropriate, to prepare the required "term" structs
255  * (one for each desired sub-window), and these "init_xxx()" functions
256  * are called from a centralized "main()" function in "main.c".  Other
257  * "main-xxx.c" systems contain their own "main()" function which, in
258  * addition to doing everything needed to initialize the actual program,
259  * also does everything that the normal "init_xxx()" functions would do.
260  *
261  * The game "Angband" defines, in addition to "attr 0", all of the
262  * attr codes from 1 to 15, using definitions in "defines.h", and
263  * thus the "main-xxx.c" files used by Angband must handle these
264  * attr values correctly.  Also, they must handle all other attr
265  * values, though they may do so in any way they wish, for example,
266  * by always taking every attr code mod 16.  Many of the "main-xxx.c"
267  * files use "white space" ("attr 1" / "char 32") to "erase" or "clear"
268  * any window, for efficiency.
269  *
270  * The game "Angband" uses the "Term_user" hook to allow any of the
271  * "main-xxx.c" files to interact with the user, by calling this hook
272  * whenever the user presses the "!" key when the game is waiting for
273  * a new command.  This could be used, for example, to provide "unix
274  * shell commands" to the Unix versions of the game.
275  *
276  * See "main-xxx.c" for a simple skeleton file which can be used to
277  * create a "visual system" for a new platform when porting Angband.
278  */
279
280
281
282
283
284
285 /*
286  * The current "term"
287  */
288 term *Term = NULL;
289
290
291
292
293 /*** Local routines ***/
294
295
296 /*
297  * Nuke a term_win (see below)
298  */
299 static errr term_win_nuke(term_win *s, int w, int h)
300 {
301         /* Free the window access arrays */
302         C_KILL(s->a, h, byte*);
303         C_KILL(s->c, h, char*);
304
305         /* Free the window content arrays */
306         C_KILL(s->va, h * w, byte);
307         C_KILL(s->vc, h * w, char);
308
309         /* Free the terrain access arrays */
310         C_KILL(s->ta, h, byte*);
311         C_KILL(s->tc, h, char*);
312
313         /* Free the terrain content arrays */
314         C_KILL(s->vta, h * w, byte);
315         C_KILL(s->vtc, h * w, char);
316
317         /* Success */
318         return (0);
319 }
320
321
322 /*
323  * Initialize a "term_win" (using the given window size)
324  */
325 static errr term_win_init(term_win *s, int w, int h)
326 {
327         int y;
328
329         /* Make the window access arrays */
330         C_MAKE(s->a, h, byte*);
331         C_MAKE(s->c, h, char*);
332
333         /* Make the window content arrays */
334         C_MAKE(s->va, h * w, byte);
335         C_MAKE(s->vc, h * w, char);
336
337         /* Make the terrain access arrays */
338         C_MAKE(s->ta, h, byte*);
339         C_MAKE(s->tc, h, char*);
340
341         /* Make the terrain content arrays */
342         C_MAKE(s->vta, h * w, byte);
343         C_MAKE(s->vtc, h * w, char);
344
345
346         /* Prepare the window access arrays */
347         for (y = 0; y < h; y++)
348         {
349                 s->a[y] = s->va + w * y;
350                 s->c[y] = s->vc + w * y;
351
352                 s->ta[y] = s->vta + w * y;
353                 s->tc[y] = s->vtc + w * y;
354         }
355
356         /* Success */
357         return (0);
358 }
359
360
361 /*
362  * Copy a "term_win" from another
363  */
364 static errr term_win_copy(term_win *s, term_win *f, int w, int h)
365 {
366         int x, y;
367
368         /* Copy contents */
369         for (y = 0; y < h; y++)
370         {
371                 byte *f_aa = f->a[y];
372                 char *f_cc = f->c[y];
373
374                 byte *s_aa = s->a[y];
375                 char *s_cc = s->c[y];
376
377                 byte *f_taa = f->ta[y];
378                 char *f_tcc = f->tc[y];
379
380                 byte *s_taa = s->ta[y];
381                 char *s_tcc = s->tc[y];
382
383                 for (x = 0; x < w; x++)
384                 {
385                         *s_aa++ = *f_aa++;
386                         *s_cc++ = *f_cc++;
387
388                         *s_taa++ = *f_taa++;
389                         *s_tcc++ = *f_tcc++;
390                 }
391         }
392
393         /* Copy cursor */
394         s->cx = f->cx;
395         s->cy = f->cy;
396         s->cu = f->cu;
397         s->cv = f->cv;
398
399         /* Success */
400         return (0);
401 }
402
403
404
405 /*** External hooks ***/
406
407
408 /*
409  * Execute the "Term->user_hook" hook, if available (see above).
410  */
411 errr Term_user(int n)
412 {
413         /* Verify the hook */
414         if (!Term->user_hook) return (-1);
415
416         /* Call the hook */
417         return ((*Term->user_hook)(n));
418 }
419
420 /*
421  * Execute the "Term->xtra_hook" hook, if available (see above).
422  */
423 errr Term_xtra(int n, int v)
424 {
425         /* Verify the hook */
426         if (!Term->xtra_hook) return (-1);
427
428 #ifdef CHUUKEI
429         if( n == TERM_XTRA_CLEAR || n == TERM_XTRA_FRESH || n == TERM_XTRA_SHAPE )
430           send_xtra_to_chuukei_server(n);
431 #endif
432         /* Call the hook */
433         return ((*Term->xtra_hook)(n, v));
434 }
435
436
437
438 /*** Fake hooks ***/
439
440
441 /*
442  * Hack -- fake hook for "Term_curs()" (see above)
443  */
444 static errr Term_curs_hack(int x, int y)
445 {
446         /* Compiler silliness */
447         if (x || y) return (-2);
448
449         /* Oops */
450         return (-1);
451 }
452
453 /*
454  * Hack -- fake hook for "Term_wipe()" (see above)
455  */
456 static errr Term_wipe_hack(int x, int y, int n)
457 {
458         /* Compiler silliness */
459         if (x || y || n) return (-2);
460
461         /* Oops */
462         return (-1);
463 }
464
465 /*
466  * Hack -- fake hook for "Term_text()" (see above)
467  */
468 #ifdef JP
469 static errr Term_text_hack(int x, int y, int n, byte a, cptr cp)
470 #else
471 static errr Term_text_hack(int x, int y, int n, byte a, const char *cp)
472 #endif
473
474 {
475         /* Compiler silliness */
476         if (x || y || n || a || cp) return (-2);
477
478         /* Oops */
479         return (-1);
480 }
481
482 /*
483  * Hack -- fake hook for "Term_pict()" (see above)
484  */
485 static errr Term_pict_hack(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp)
486 {
487         /* Compiler silliness */
488         if (x || y || n || ap || cp || tap || tcp) return (-2);
489
490         /* Oops */
491         return (-1);
492 }
493
494
495
496 /*** Efficient routines ***/
497
498
499 /*
500  * Mentally draw an attr/char at a given location
501  *
502  * Assumes given location and values are valid.
503  */
504 void Term_queue_char(int x, int y, byte a, char c, byte ta, char tc)
505 {
506         term_win *scrn = Term->scr; 
507         
508         byte *scr_aa = &scrn->a[y][x];
509         char *scr_cc = &scrn->c[y][x];
510
511         byte *scr_taa = &scrn->ta[y][x];
512         char *scr_tcc = &scrn->tc[y][x];
513
514         /* Hack -- Ignore non-changes */
515         if ((*scr_aa == a) && (*scr_cc == c) &&
516                  (*scr_taa == ta) && (*scr_tcc == tc)) return;
517
518         /* Save the "literal" information */
519         *scr_aa = a;
520         *scr_cc = c;
521
522         *scr_taa = ta;
523         *scr_tcc = tc;
524
525         /* Check for new min/max row info */
526         if (y < Term->y1) Term->y1 = y;
527         if (y > Term->y2) Term->y2 = y;
528
529         /* Check for new min/max col info for this row */
530         if (x < Term->x1[y]) Term->x1[y] = x;
531         if (x > Term->x2[y]) Term->x2[y] = x;
532
533         if ((scrn->a[y][x] & AF_BIGTILE2) == AF_BIGTILE2)
534                 if ((x - 1) < Term->x1[y]) Term->x1[y]--;
535 }
536
537
538 /*
539  * Bigtile version of Term_queue_char().
540  *
541  * If use_bigtile is FALSE, simply call Term_queue_char().
542  *
543  * Otherwise, mentally draw a pair of attr/char at a given location.
544  *
545  * Assumes given location and values are valid.
546  */
547 void Term_queue_bigchar(int x, int y, byte a, char c, byte ta, char tc)
548 {
549
550 #ifdef JP
551         /*
552          * A table which relates each ascii character to a multibyte
553          * character.
554          *
555          * ¡Ö¢£¡×¤ÏÆóÇÜÉýƦÉå¤ÎÆâÉô¥³¡¼¥É¤Ë»ÈÍÑ¡£
556          */
557         static char ascii_to_zenkaku[] =
558                 "¡¡¡ª¡É¡ô¡ð¡ó¡õ¡Ç¡Ê¡Ë¡ö¡Ü¡¤¡Ý¡¥¡¿"
559                 "£°£±£²£³£´£µ£¶£·£¸£¹¡§¡¨¡ã¡á¡ä¡©"
560                 "¡÷£Á£Â£Ã£Ä£Å£Æ£Ç£È£É£Ê£Ë£Ì£Í£Î£Ï"
561                 "£Ð£Ñ£Ò£Ó£Ô£Õ£Ö£×£Ø£Ù£Ú¡Î¡À¡Ï¡°¡²"
562                 "¡Æ£á£â£ã£ä£å£æ£ç£è£é£ê£ë£ì£í£î£ï"
563                 "£ð£ñ£ò£ó£ô£õ£ö£÷£ø£ù£ú¡Ð¡Ã¡Ñ¡Á¢£";
564 #endif
565
566         byte a2;
567         char c2;
568
569         /* If non bigtile mode, call orginal function */
570         if (!use_bigtile)
571         {
572                 Term_queue_char(x, y, a, c, ta, tc);
573                 return;
574         }
575
576         /* A tile becomes a Bigtile */
577         if ((a & AF_TILE1) && (c & 0x80))
578         {
579                 /* Mark it as a Bigtile */
580                 a2 = AF_BIGTILE2;
581
582                 c2 = -1;
583
584                 /* Ignore non-tile background */
585                 if (!((ta & AF_TILE1) && (tc & 0x80)))
586                 {
587                         ta = 0;
588                         tc = 0;
589                 }
590         }
591
592 #ifdef JP
593         /*
594          * Use a multibyte character instead of a dirty pair of ASCII
595          * characters.
596          */
597         else if (' ' <= c) /* isprint(c) */
598         {
599                 c2 = ascii_to_zenkaku[2 * (c - ' ') + 1];
600                 c = ascii_to_zenkaku[2 * (c - ' ')];
601
602                 /* Mark it as a Kanji */
603                 a2 = a | AF_KANJI2;
604                 a |= AF_KANJI1;
605         }
606 #endif
607
608         else
609         {
610                 /* Dirty pair of ASCII characters */
611                 a2 = TERM_WHITE;
612                 c2 = ' ';
613         }
614
615         /* Display pair of attr/char */
616         Term_queue_char(x, y, a, c, ta, tc);
617         Term_queue_char(x + 1, y, a2, c2, 0, 0);
618 }
619
620
621 /*
622  * Mentally draw a string of attr/chars at a given location
623  *
624  * Assumes given location and values are valid.
625  *
626  * This function is designed to be fast, with no consistancy checking.
627  * It is used to update the map in the game.
628  */
629 void Term_queue_line(int x, int y, int n, byte *a, char *c, byte *ta, char *tc)
630 {
631         term_win *scrn = Term->scr;
632
633         int x1 = -1;
634         int x2 = -1;
635
636         byte *scr_aa = &scrn->a[y][x];
637         char *scr_cc = &scrn->c[y][x];
638
639         byte *scr_taa = &scrn->ta[y][x];
640         char *scr_tcc = &scrn->tc[y][x];
641
642         while (n--)
643         {
644                 /* Hack -- Ignore non-changes */
645                 if ((*scr_aa == *a) && (*scr_cc == *c) &&
646                         (*scr_taa == *ta) && (*scr_tcc == *tc))
647                 {
648                         x++;
649                         a++;
650                         c++;
651                         ta++;
652                         tc++;
653                         scr_aa++;
654                         scr_cc++;
655                         scr_taa++;
656                         scr_tcc++;
657                         continue;
658                 }
659
660                 /* Save the "literal" information */
661                 *scr_taa++ = *ta++;
662                 *scr_tcc++ = *tc++;
663
664                 /* Save the "literal" information */
665                 *scr_aa++ = *a++;
666                 *scr_cc++ = *c++;
667
668                 /* Track minimum changed column */
669                 if (x1 < 0) x1 = x;
670
671                 /* Track maximum changed column */
672                 x2 = x;
673
674                 x++;
675         }
676
677         /* Expand the "change area" as needed */
678         if (x1 >= 0)
679         {
680                 /* Check for new min/max row info */
681                 if (y < Term->y1) Term->y1 = y;
682                 if (y > Term->y2) Term->y2 = y;
683
684                 /* Check for new min/max col info in this row */
685                 if (x1 < Term->x1[y]) Term->x1[y] = x1;
686                 if (x2 > Term->x2[y]) Term->x2[y] = x2;
687         }
688 }
689
690
691
692 /*
693  * Mentally draw some attr/chars at a given location
694  *
695  * Assumes that (x,y) is a valid location, that the first "n" characters
696  * of the string "s" are all valid (non-zero), and that (x+n-1,y) is also
697  * a valid location, so the first "n" characters of "s" can all be added
698  * starting at (x,y) without causing any illegal operations.
699  */
700 void Term_queue_chars(int x, int y, int n, byte a, cptr s)
701 {
702         int x1 = -1, x2 = -1;
703
704         byte *scr_aa = Term->scr->a[y];
705 #ifdef JP
706         char *scr_cc = Term->scr->c[y];
707
708         byte *scr_taa = Term->scr->ta[y];
709         char *scr_tcc = Term->scr->tc[y];
710 #else
711         char *scr_cc = Term->scr->c[y];
712
713         byte *scr_taa = Term->scr->ta[y];
714         char *scr_tcc = Term->scr->tc[y];
715 #endif
716
717
718 #ifdef JP
719         /* É½¼¨Ê¸»ú¤Ê¤· */
720         if (n == 0 || *s == 0) return;
721         /*
722          * Á´³Ñʸ»ú¤Î±¦È¾Ê¬¤«¤éʸ»ú¤òɽ¼¨¤¹¤ë¾ì¹ç¡¢
723          * ½Å¤Ê¤Ã¤¿Ê¸»ú¤Îº¸Éôʬ¤ò¾Ãµî¡£
724          * É½¼¨³«»Ï°ÌÃÖ¤¬º¸Ã¼¤Ç¤Ê¤¤¤È²¾Äê¡£
725          */
726         if ((scr_aa[x] & AF_KANJI2) && (scr_aa[x] & AF_BIGTILE2) != AF_BIGTILE2)
727         {
728                 scr_cc[x - 1] = ' ';
729                 scr_aa[x - 1] &= AF_KANJIC;
730                 x1 = x2 = x - 1;
731         }
732 #endif
733         /* Queue the attr/chars */
734         for ( ; n; x++, s++, n--)
735         {
736 #ifdef JP
737                 /* Æüìʸ»ú¤È¤·¤ÆMSB¤¬Î©¤Ã¤Æ¤¤¤ë²ÄǽÀ­¤¬¤¢¤ë */
738                 /* ¤½¤Î¾ì¹çattr¤ÎMSB¤âΩ¤Ã¤Æ¤¤¤ë¤Î¤Ç¤³¤ì¤Ç¼±Ê̤¹¤ë */
739 /* check */
740                 if (!(a & AF_TILE1) && iskanji(*s))
741                 {
742                         char nc1 = *s++;
743                         char nc2 = *s;
744
745                         byte na1 = (a | AF_KANJI1);
746                         byte na2 = (a | AF_KANJI2);
747
748                         if((--n == 0) || !nc2) break;
749
750                         if(scr_aa[x++] == na1 && scr_aa[x] == na2 &&
751                            scr_cc[x - 1] == nc1 && scr_cc[x] == nc2 &&
752                            (scr_taa[x - 1] == 0) && (scr_taa[x]==0) &&
753                            (scr_tcc[x - 1] == 0) && (scr_tcc[x]==0)    )
754                                 continue;
755
756                         scr_aa[x - 1] = na1;
757                         scr_aa[x] = na2;
758                         scr_cc[x - 1] = nc1;
759                         scr_cc[x] = nc2;
760
761                         if(x1 < 0) x1 = x - 1;
762                         x2 = x;
763                 }
764                 else
765                 {
766 #endif
767                 byte oa = scr_aa[x];
768                 char oc = scr_cc[x];
769
770                 byte ota = scr_taa[x];
771                 char otc = scr_tcc[x];
772
773                 /* Hack -- Ignore non-changes */
774                 if ((oa == a) && (oc == *s) && (ota == 0) && (otc == 0)) continue;
775
776                 /* Save the "literal" information */
777                 scr_aa[x] = a;
778                 scr_cc[x] = *s;
779
780                 scr_taa[x] = 0;
781                 scr_tcc[x] = 0;
782
783                 /* Note the "range" of window updates */
784                 if (x1 < 0) x1 = x;
785                 x2 = x;
786 #ifdef JP
787         }
788 #endif
789         }
790
791 #ifdef JP
792         /*
793          * Á´³Ñʸ»ú¤Îº¸È¾Ê¬¤Çɽ¼¨¤ò½ªÎ»¤¹¤ë¾ì¹ç¡¢
794          * ½Å¤Ê¤Ã¤¿Ê¸»ú¤Î±¦Éôʬ¤ò¾Ãµî¡£
795          * (¾ò·ïÄɲ᧥¿¥¤¥ë¤Î1ʸ»úÌܤǤʤ¤»ö¤ò³Î¤«¤á¤ë¤è¤¦¤Ë¡£)
796          */
797         {
798
799                 int w, h;
800                 Term_get_size(&w, &h);
801                 if (x != w && !(scr_aa[x] & AF_TILE1) && (scr_aa[x] & AF_KANJI2))
802                 {
803                         scr_cc[x] = ' ';
804                         scr_aa[x] &= AF_KANJIC;
805                         if (x1 < 0) x1 = x;
806                         x2 = x;
807                 }
808         }
809 #endif
810         /* Expand the "change area" as needed */
811         if (x1 >= 0)
812         {
813                 /* Check for new min/max row info */
814                 if (y < Term->y1) Term->y1 = y;
815                 if (y > Term->y2) Term->y2 = y;
816
817                 /* Check for new min/max col info in this row */
818                 if (x1 < Term->x1[y]) Term->x1[y] = x1;
819                 if (x2 > Term->x2[y]) Term->x2[y] = x2;
820         }
821 }
822
823
824
825 /*** Refresh routines ***/
826
827
828 /*
829  * Flush a row of the current window (see "Term_fresh")
830  *
831  * Display text using "Term_pict()"
832  */
833 static void Term_fresh_row_pict(int y, int x1, int x2)
834 {
835         int x;
836
837         byte *old_aa = Term->old->a[y];
838         char *old_cc = Term->old->c[y];
839
840         byte *scr_aa = Term->scr->a[y];
841         char *scr_cc = Term->scr->c[y];
842
843         byte *old_taa = Term->old->ta[y];
844         char *old_tcc = Term->old->tc[y];
845
846         byte *scr_taa = Term->scr->ta[y];
847         char *scr_tcc = Term->scr->tc[y];
848
849         byte ota;
850         char otc;
851
852         byte nta;
853         char ntc;
854
855
856         /* Pending length */
857         int fn = 0;
858
859         /* Pending start */
860         int fx = 0;
861
862         byte oa;
863         char oc;
864
865         byte na;
866         char nc;
867
868 #ifdef JP
869         /* Á´³Ñʸ»ú¤Î£²¥Ð¥¤¥ÈÌܤ«¤É¤¦¤« */
870         int kanji = 0;
871 #endif
872         /* Scan "modified" columns */
873         for (x = x1; x <= x2; x++)
874         {
875                 /* See what is currently here */
876                 oa = old_aa[x];
877                 oc = old_cc[x];
878
879                 /* See what is desired there */
880                 na = scr_aa[x];
881                 nc = scr_cc[x];
882
883 #ifdef JP
884                 if (kanji)
885                 {
886                         /* Á´³Ñʸ»ú£²¥Ð¥¤¥ÈÌÜ */
887                         kanji = 0;
888                         old_aa[x] = na;
889                         old_cc[x] = nc;
890                         fn++;
891                         continue;
892                 }
893                 /* Æüìʸ»ú¤È¤·¤ÆMSB¤¬Î©¤Ã¤Æ¤¤¤ë²ÄǽÀ­¤¬¤¢¤ë */
894                 /* ¤½¤Î¾ì¹çattr¤ÎMSB¤âΩ¤Ã¤Æ¤¤¤ë¤Î¤Ç¤³¤ì¤Ç¼±Ê̤¹¤ë */
895 /* check */
896                 kanji = (iskanji(nc) && !(na & AF_TILE1));
897 #endif
898
899                 ota = old_taa[x];
900                 otc = old_tcc[x];
901
902                 nta = scr_taa[x];
903                 ntc = scr_tcc[x];
904
905                 /* Handle unchanged grids */
906 #ifdef JP
907                 if ((na == oa) && (nc == oc) && (nta == ota) && (ntc == otc)
908                     &&(!kanji || (scr_aa[x + 1] == old_aa[x + 1] &&
909                                   scr_cc[x + 1] == old_cc[x + 1] &&
910                                   scr_taa[x + 1] == old_taa[x + 1] &&
911                                   scr_tcc[x + 1] == old_tcc[x + 1])))
912 #else
913                 if ((na == oa) && (nc == oc) && (nta == ota) && (ntc == otc))
914 #endif
915                 {
916                         /* Flush */
917                         if (fn)
918                         {
919                                 /* Draw pending attr/char pairs */
920                                 (void)((*Term->pict_hook)(fx, y, fn,
921                                        &scr_aa[fx], &scr_cc[fx],&scr_taa[fx], &scr_tcc[fx]));
922
923                                 /* Forget */
924                                 fn = 0;
925                         }
926
927 #ifdef JP
928                         /* Á´³Ñʸ»ú¤Î»þ¤ÏºÆ³«°ÌÃ֤ϡܣ± */
929                         if(kanji)
930                         {
931                                 x++;
932                                 fx++;
933                                 kanji = 0;
934                         }
935 #endif
936                         /* Skip */
937                         continue;
938                 }
939                 /* Save new contents */
940                 old_aa[x] = na;
941                 old_cc[x] = nc;
942
943                 old_taa[x] = nta;
944                 old_tcc[x] = ntc;
945
946                 /* Restart and Advance */
947                 if (fn++ == 0) fx = x;
948         }
949
950         /* Flush */
951         if (fn)
952         {
953                 /* Draw pending attr/char pairs */
954                 (void)((*Term->pict_hook)(fx, y, fn,
955                         &scr_aa[fx], &scr_cc[fx], &scr_taa[fx], &scr_tcc[fx]));
956         }
957 }
958
959
960
961 /*
962  * Flush a row of the current window (see "Term_fresh")
963  *
964  * Display text using "Term_text()" and "Term_wipe()",
965  * but use "Term_pict()" for high-bit attr/char pairs
966  */
967 static void Term_fresh_row_both(int y, int x1, int x2)
968 {
969         int x;
970
971         byte *old_aa = Term->old->a[y];
972         char *old_cc = Term->old->c[y];
973
974         byte *scr_aa = Term->scr->a[y];
975         char *scr_cc = Term->scr->c[y];
976
977         byte *old_taa = Term->old->ta[y];
978         char *old_tcc = Term->old->tc[y];
979         byte *scr_taa = Term->scr->ta[y];
980         char *scr_tcc = Term->scr->tc[y];
981
982         byte ota;
983         char otc;
984         byte nta;
985         char ntc;
986
987         /* The "always_text" flag */
988         int always_text = Term->always_text;
989
990         /* Pending length */
991         int fn = 0;
992
993         /* Pending start */
994         int fx = 0;
995
996         /* Pending attr */
997         byte fa = Term->attr_blank;
998
999         byte oa;
1000         char oc;
1001
1002         byte na;
1003         char nc;
1004
1005 #ifdef JP
1006         /* Á´³Ñʸ»ú¤Î£²¥Ð¥¤¥ÈÌܤ«¤É¤¦¤« */
1007         int kanji = 0;
1008 #endif
1009         /* Scan "modified" columns */
1010         for (x = x1; x <= x2; x++)
1011         {
1012                 /* See what is currently here */
1013                 oa = old_aa[x];
1014                 oc = old_cc[x];
1015
1016                 /* See what is desired there */
1017                 na = scr_aa[x];
1018                 nc = scr_cc[x];
1019
1020 #ifdef JP
1021                 if (kanji)
1022                 {
1023                         /* Á´³Ñʸ»ú£²¥Ð¥¤¥ÈÌÜ */
1024                         kanji = 0;
1025                         old_aa[x] = na;
1026                         old_cc[x] = nc;
1027                         fn++;
1028                         continue;
1029                 }
1030                 /* Æüìʸ»ú¤È¤·¤ÆMSB¤¬Î©¤Ã¤Æ¤¤¤ë²ÄǽÀ­¤¬¤¢¤ë */
1031                 /* ¤½¤Î¾ì¹çattr¤ÎMSB¤âΩ¤Ã¤Æ¤¤¤ë¤Î¤Ç¤³¤ì¤Ç¼±Ê̤¹¤ë */
1032 /* check */
1033 /*              kanji = (iskanji(nc));  */
1034                 kanji = (iskanji(nc) && !(na & AF_TILE1));
1035 #endif
1036
1037                 ota = old_taa[x];
1038                 otc = old_tcc[x];
1039
1040                 nta = scr_taa[x];
1041                 ntc = scr_tcc[x];
1042
1043                 /* Handle unchanged grids */
1044 #ifdef JP
1045                 if ((na == oa) && (nc == oc) && (nta == ota) && (ntc == otc)&&
1046                     (!kanji || (scr_aa[x + 1] == old_aa[x + 1] &&
1047                                 scr_cc[x + 1] == old_cc[x + 1] &&
1048                                 scr_taa[x + 1] == old_taa[x + 1] &&
1049                                 scr_tcc[x + 1] == old_tcc[x + 1])))
1050 #else
1051                 if ((na == oa) && (nc == oc) && (nta == ota) && (ntc == otc))
1052 #endif
1053                 {
1054                         /* Flush */
1055                         if (fn)
1056                         {
1057                                 /* Draw pending chars (normal) */
1058                                 if (fa || always_text)
1059                                 {
1060 #ifdef CHUUKEI
1061                         send_text_to_chuukei_server(fx, y, fn, fa, &scr_cc[fx]);
1062 #endif
1063                                         (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
1064                                 }
1065
1066                                 /* Draw pending chars (black) */
1067                                 else
1068                                 {
1069 #ifdef CHUUKEI
1070                         send_wipe_to_chuukei_server(fx, y, fn);
1071 #endif
1072                                         (void)((*Term->wipe_hook)(fx, y, fn));
1073                                 }
1074
1075                                 /* Forget */
1076                                 fn = 0;
1077                         }
1078
1079 #ifdef JP
1080                         /* Á´³Ñʸ»ú¤Î»þ¤ÏºÆ³«°ÌÃ֤ϡܣ± */
1081                         if(kanji)
1082                         {
1083                                 x++;
1084                                 fx++;
1085                                 kanji = 0;
1086                         }
1087 #endif
1088                         /* Skip */
1089                         continue;
1090                 }
1091
1092                 /* Save new contents */
1093                 old_aa[x] = na;
1094                 old_cc[x] = nc;
1095
1096                 old_taa[x] = nta;
1097                 old_tcc[x] = ntc;
1098
1099                 /* 2nd byte of bigtile */
1100                 if ((na & AF_BIGTILE2) == AF_BIGTILE2) continue;
1101
1102                 /* Handle high-bit attr/chars */
1103                 if ((na & AF_TILE1) && (nc & 0x80))
1104                 {
1105                         /* Flush */
1106                         if (fn)
1107                         {
1108                                 /* Draw pending chars (normal) */
1109                                 if (fa || always_text)
1110                                 {
1111 #ifdef CHUUKEI
1112                         send_text_to_chuukei_server(fx, y, fn, fa, &scr_cc[fx]);
1113 #endif
1114                                         (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
1115                                 }
1116
1117                                 /* Draw pending chars (black) */
1118                                 else
1119                                 {
1120 #ifdef CHUUKEI
1121                         send_wipe_to_chuukei_server(fx, y, fn);
1122 #endif
1123                                         (void)((*Term->wipe_hook)(fx, y, fn));
1124                                 }
1125
1126                                 /* Forget */
1127                                 fn = 0;
1128                         }
1129
1130                         /* Hack -- Draw the special attr/char pair */
1131                         (void)((*Term->pict_hook)(x, y, 1, &na, &nc, &nta, &ntc));
1132
1133                         /* Skip */
1134                         continue;
1135                 }
1136
1137                 /* Notice new color */
1138 #ifdef JP
1139                 if (fa != (na & AF_KANJIC))
1140 #else
1141                 if (fa != na)
1142 #endif
1143
1144                 {
1145                         /* Flush */
1146                         if (fn)
1147                         {
1148                                 /* Draw the pending chars */
1149                                 if (fa || always_text)
1150                                 {
1151 #ifdef CHUUKEI
1152                         send_text_to_chuukei_server(fx, y, fn, fa, &scr_cc[fx]);
1153 #endif
1154                                         (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
1155                                 }
1156
1157                                 /* Hack -- Erase "leading" spaces */
1158                                 else
1159                                 {
1160 #ifdef CHUUKEI
1161                         send_wipe_to_chuukei_server(fx, y, fn);
1162 #endif
1163                                         (void)((*Term->wipe_hook)(fx, y, fn));
1164                                 }
1165
1166                                 /* Forget */
1167                                 fn = 0;
1168                         }
1169
1170                         /* Save the new color */
1171 #ifdef JP
1172                         fa = (na & AF_KANJIC);
1173 #else
1174                         fa = na;
1175 #endif
1176
1177                 }
1178
1179                 /* Restart and Advance */
1180                 if (fn++ == 0) fx = x;
1181         }
1182
1183         /* Flush */
1184         if (fn)
1185         {
1186                 /* Draw pending chars (normal) */
1187                 if (fa || always_text)
1188                 {
1189 #ifdef CHUUKEI
1190                         send_text_to_chuukei_server(fx, y, fn, fa, &scr_cc[fx]);
1191 #endif
1192                         (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
1193                 }
1194
1195                 /* Draw pending chars (black) */
1196                 else
1197                 {
1198 #ifdef CHUUKEI
1199                         send_wipe_to_chuukei_server(fx, y, fn);
1200 #endif
1201                         (void)((*Term->wipe_hook)(fx, y, fn));
1202                 }
1203         }
1204 }
1205
1206
1207 /*
1208  * Flush a row of the current window (see "Term_fresh")
1209  *
1210  * Display text using "Term_text()" and "Term_wipe()"
1211  */
1212 static void Term_fresh_row_text(int y, int x1, int x2)
1213 {
1214         int x;
1215
1216         byte *old_aa = Term->old->a[y];
1217         char *old_cc = Term->old->c[y];
1218
1219         byte *scr_aa = Term->scr->a[y];
1220         char *scr_cc = Term->scr->c[y];
1221
1222         /* The "always_text" flag */
1223         int always_text = Term->always_text;
1224
1225         /* Pending length */
1226         int fn = 0;
1227
1228         /* Pending start */
1229         int fx = 0;
1230
1231         /* Pending attr */
1232         byte fa = Term->attr_blank;
1233
1234         byte oa;
1235         char oc;
1236
1237         byte na;
1238         char nc;
1239
1240 #ifdef JP
1241         /* Á´³Ñʸ»ú¤Î£²¥Ð¥¤¥ÈÌܤ«¤É¤¦¤« */
1242         int kanji = 0;
1243
1244         for (x = 0; x < x1; x++)
1245                 if (!(old_aa[x] & AF_TILE1) && iskanji(old_cc[x]))
1246                 {
1247                         if (x == x1 - 1)
1248                         {
1249                                 x1--;
1250                                 break;
1251                         }
1252                         else
1253                                 x++;
1254                 }
1255 #endif
1256         /* Scan "modified" columns */
1257         for (x = x1; x <= x2; x++)
1258         {
1259                 /* See what is currently here */
1260                 oa = old_aa[x];
1261                 oc = old_cc[x];
1262
1263                 /* See what is desired there */
1264                 na = scr_aa[x];
1265                 nc = scr_cc[x];
1266
1267 #ifdef JP
1268                 if (kanji)
1269                 {
1270                         /* Á´³Ñʸ»ú£²¥Ð¥¤¥ÈÌÜ */
1271                         kanji = 0;
1272                         old_aa[x] = na;
1273                         old_cc[x] = nc;
1274                         fn++;
1275                         continue;
1276                 }
1277                 /* Æüìʸ»ú¤È¤·¤ÆMSB¤¬Î©¤Ã¤Æ¤¤¤ë²ÄǽÀ­¤¬¤¢¤ë */
1278                 /* ¤½¤Î¾ì¹çattr¤ÎMSB¤âΩ¤Ã¤Æ¤¤¤ë¤Î¤Ç¤³¤ì¤Ç¼±Ê̤¹¤ë */
1279 /* check */
1280                 kanji = (iskanji(nc) && !(na & AF_TILE1));
1281 #endif
1282                 /* Handle unchanged grids */
1283 #ifdef JP
1284                 if ((na == oa) && (nc == oc) &&
1285                     (!kanji || (scr_aa[x + 1] == old_aa[x + 1] &&
1286                                 scr_cc[x + 1] == old_cc[x + 1])))
1287 #else
1288                 if ((na == oa) && (nc == oc))
1289 #endif
1290
1291                 {
1292                         /* Flush */
1293                         if (fn)
1294                         {
1295                                 /* Draw pending chars (normal) */
1296                                 if (fa || always_text)
1297                                 {
1298 #ifdef CHUUKEI
1299                         send_text_to_chuukei_server(fx, y, fn, fa, &scr_cc[fx]);
1300 #endif
1301                                         (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
1302                                 }
1303
1304                                 /* Draw pending chars (black) */
1305                                 else
1306                                 {
1307 #ifdef CHUUKEI
1308                         send_wipe_to_chuukei_server(fx, y, fn);
1309 #endif
1310                                         (void)((*Term->wipe_hook)(fx, y, fn));
1311                                 }
1312
1313                                 /* Forget */
1314                                 fn = 0;
1315                         }
1316
1317 #ifdef JP
1318                         /* Á´³Ñʸ»ú¤Î»þ¤ÏºÆ³«°ÌÃ֤ϡܣ± */
1319                         if(kanji)
1320                         {
1321                                 x++;
1322                                 fx++;
1323                                 kanji = 0;
1324                         }
1325 #endif
1326                         /* Skip */
1327                         continue;
1328                 }
1329
1330                 /* Save new contents */
1331                 old_aa[x] = na;
1332                 old_cc[x] = nc;
1333
1334                 /* Notice new color */
1335 #ifdef JP
1336                 if (fa != (na & AF_KANJIC))
1337 #else
1338                 if (fa != na)
1339 #endif
1340
1341                 {
1342                         /* Flush */
1343                         if (fn)
1344                         {
1345                                 /* Draw the pending chars */
1346                                 if (fa || always_text)
1347                                 {
1348 #ifdef CHUUKEI
1349                         send_text_to_chuukei_server(fx, y, fn, fa, &scr_cc[fx]);
1350 #endif
1351                                         (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
1352                                 }
1353
1354                                 /* Hack -- Erase "leading" spaces */
1355                                 else
1356                                 {
1357 #ifdef CHUUKEI
1358                         send_wipe_to_chuukei_server(fx, y, fn);
1359 #endif
1360                                         (void)((*Term->wipe_hook)(fx, y, fn));
1361                                 }
1362
1363                                 /* Forget */
1364                                 fn = 0;
1365                         }
1366
1367                         /* Save the new color */
1368 #ifdef JP
1369                         fa = (na & AF_KANJIC);
1370 #else
1371                         fa = na;
1372 #endif
1373
1374                 }
1375
1376                 /* Restart and Advance */
1377                 if (fn++ == 0) fx = x;
1378         }
1379
1380         /* Flush */
1381         if (fn)
1382         {
1383                 /* Draw pending chars (normal) */
1384                 if (fa || always_text)
1385                 {
1386 #ifdef CHUUKEI
1387                         send_text_to_chuukei_server(fx, y, fn, fa, &scr_cc[fx]);
1388 #endif
1389                         (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
1390                 }
1391
1392                 /* Draw pending chars (black) */
1393                 else
1394                 {
1395 #ifdef CHUUKEI
1396                         send_wipe_to_chuukei_server(fx, y, fn);
1397 #endif
1398                         (void)((*Term->wipe_hook)(fx, y, fn));
1399                 }
1400         }
1401 }
1402
1403
1404
1405
1406
1407 /*
1408  * Actually perform all requested changes to the window
1409  *
1410  * If absolutely nothing has changed, not even temporarily, or if the
1411  * current "Term" is not mapped, then this function will return 1 and
1412  * do absolutely nothing.
1413  *
1414  * Note that when "soft_cursor" is true, we erase the cursor (if needed)
1415  * whenever anything has changed, and redraw it (if needed) after all of
1416  * the screen updates are complete.  This will induce a small amount of
1417  * "cursor flicker" but only when the screen has been updated.  If the
1418  * screen is updated and then restored, you may still get this flicker.
1419  *
1420  * When "soft_cursor" is not true, we make the cursor invisible before
1421  * doing anything else if it is supposed to be invisible by the time we
1422  * are done, and we make it visible after moving it to its final location
1423  * after all of the screen updates are complete.
1424  *
1425  * Note that "Term_xtra(TERM_XTRA_CLEAR,0)" must erase the entire screen,
1426  * including the cursor, if needed, and may place the cursor anywhere.
1427  *
1428  * Note that "Term_xtra(TERM_XTRA_FROSH,y)" will be always be called
1429  * after any row "y" has been "flushed", unless the "Term->never_frosh"
1430  * flag is set, and "Term_xtra(TERM_XTRA_FRESH,0)" will be called after
1431  * all of the rows have been "flushed".
1432  *
1433  * Note the use of three different functions to handle the actual flush,
1434  * based on the settings of the "Term->always_pict" and "Term->higher_pict"
1435  * flags (see below).
1436  *
1437  * The three helper functions (above) work by collecting similar adjacent
1438  * grids into stripes, and then sending each stripe to "Term->pict_hook",
1439  * "Term->text_hook", or "Term->wipe_hook", based on the settings of the
1440  * "Term->always_pict" and "Term->higher_pict" flags, which select which
1441  * of the helper functions to call to flush each row.
1442  *
1443  * The helper functions currently "skip" any grids which already contain
1444  * the desired contents.  This may or may not be the best method, especially
1445  * when the desired content fits nicely into the current stripe.  For example,
1446  * it might be better to go ahead and queue them while allowed, but keep a
1447  * count of the "trailing skipables", then, when time to flush, or when a
1448  * "non skippable" is found, force a flush if there are too many skippables.
1449  *
1450  * Perhaps an "initialization" stage, where the "text" (and "attr")
1451  * buffers are "filled" with information, converting "blanks" into
1452  * a convenient representation, and marking "skips" with "zero chars",
1453  * and then some "processing" is done to determine which chars to skip.
1454  *
1455  * Currently, the helper functions are optimal for systems which prefer
1456  * to "print a char + move a char + print a char" to "print three chars",
1457  * and for applications that do a lot of "detailed" color printing.
1458  *
1459  * In the two "queue" functions, total "non-changes" are "pre-skipped".
1460  * The helper functions must also handle situations in which the contents
1461  * of a grid are changed, but then changed back to the original value,
1462  * and situations in which two grids in the same row are changed, but
1463  * the grids between them are unchanged.
1464  *
1465  * If the "Term->always_pict" flag is set, then "Term_fresh_row_pict()"
1466  * will be used instead of "Term_fresh_row_text()".  This allows all the
1467  * modified grids to be collected into stripes of attr/char pairs, which
1468  * are then sent to the "Term->pict_hook" hook, which can draw these pairs
1469  * in whatever way it would like.
1470  *
1471  * If the "Term->higher_pict" flag is set, then "Term_fresh_row_both()"
1472  * will be used instead of "Term_fresh_row_text()".  This allows all the
1473  * "special" attr/char pairs (in which both the attr and char have the
1474  * high-bit set) to be sent (one pair at a time) to the "Term->pict_hook"
1475  * hook, which can draw these pairs in whatever way it would like.
1476  *
1477  * Normally, the "Term_wipe()" function is used only to display "blanks"
1478  * that were induced by "Term_clear()" or "Term_erase()", and then only
1479  * if the "attr_blank" and "char_blank" fields have not been redefined
1480  * to use "white space" instead of the default "black space".  Actually,
1481  * the "Term_wipe()" function is used to display all "black" text, such
1482  * as the default "spaces" created by "Term_clear()" and "Term_erase()".
1483  *
1484  * Note that the "Term->always_text" flag will disable the use of the
1485  * "Term_wipe()" function hook entirely, and force all text, even text
1486  * drawn in the color "black", to be explicitly drawn.  This is useful
1487  * for machines which implement "Term_wipe()" by just drawing spaces.
1488  *
1489  * Note that the "Term->always_pict" flag will disable the use of the
1490  * "Term_wipe()" function entirely, and force everything, even text
1491  * drawn in the attr "black", to be explicitly drawn.
1492  *
1493  * Note that if no "black" text is ever drawn, and if "attr_blank" is
1494  * not "zero", then the "Term_wipe" hook will never be used, even if
1495  * the "Term->always_text" flag is not set.
1496  *
1497  * This function does nothing unless the "Term" is "mapped", which allows
1498  * certain systems to optimize the handling of "closed" windows.
1499  *
1500  * On systems with a "soft" cursor, we must explicitly erase the cursor
1501  * before flushing the output, if needed, to prevent a "jumpy" refresh.
1502  * The actual method for this is horrible, but there is very little that
1503  * we can do to simplify it efficiently.  XXX XXX XXX
1504  *
1505  * On systems with a "hard" cursor, we will "hide" the cursor before
1506  * flushing the output, if needed, to avoid a "flickery" refresh.  It
1507  * would be nice to *always* hide the cursor during the refresh, but
1508  * this might be expensive (and/or ugly) on some machines.
1509  *
1510  * The "Term->icky_corner" flag is used to avoid calling "Term_wipe()"
1511  * or "Term_pict()" or "Term_text()" on the bottom right corner of the
1512  * window, which might induce "scrolling" or other nasty stuff on old
1513  * dumb terminals.  This flag is handled very efficiently.  We assume
1514  * that the "Term_curs()" call will prevent placing the cursor in the
1515  * corner, if needed, though I doubt such placement is ever a problem.
1516  * Currently, the use of "Term->icky_corner" and "Term->soft_cursor"
1517  * together may result in undefined behavior.
1518  */
1519 errr Term_fresh(void)
1520 {
1521         int x, y;
1522
1523         int w = Term->wid;
1524         int h = Term->hgt;
1525
1526         int y1 = Term->y1;
1527         int y2 = Term->y2;
1528
1529         term_win *old = Term->old;
1530         term_win *scr = Term->scr;
1531
1532
1533         /* Do nothing unless "mapped" */
1534         if (!Term->mapped_flag) return (1);
1535
1536
1537         /* Trivial Refresh */
1538         if ((y1 > y2) &&
1539             (scr->cu == old->cu) &&
1540             (scr->cv == old->cv) &&
1541             (scr->cx == old->cx) &&
1542             (scr->cy == old->cy) &&
1543             !(Term->total_erase))
1544         {
1545                 /* Nothing */
1546                 return (1);
1547         }
1548
1549
1550         /* Paranoia -- use "fake" hooks to prevent core dumps */
1551         if (!Term->curs_hook) Term->curs_hook = Term_curs_hack;
1552         if (!Term->bigcurs_hook) Term->bigcurs_hook = Term->curs_hook;
1553         if (!Term->wipe_hook) Term->wipe_hook = Term_wipe_hack;
1554         if (!Term->text_hook) Term->text_hook = Term_text_hack;
1555         if (!Term->pict_hook) Term->pict_hook = Term_pict_hack;
1556
1557
1558         /* Handle "total erase" */
1559         if (Term->total_erase)
1560         {
1561                 byte na = Term->attr_blank;
1562                 char nc = Term->char_blank;
1563
1564                 /* Physically erase the entire window */
1565                 Term_xtra(TERM_XTRA_CLEAR, 0);
1566
1567                 /* Hack -- clear all "cursor" data */
1568                 old->cv = old->cu = old->cx = old->cy = 0;
1569
1570                 /* Wipe each row */
1571                 for (y = 0; y < h; y++)
1572                 {
1573                         byte *aa = old->a[y];
1574                         char *cc = old->c[y];
1575
1576                         byte *taa = old->ta[y];
1577                         char *tcc = old->tc[y];
1578
1579
1580                         /* Wipe each column */
1581                         for (x = 0; x < w; x++)
1582                         {
1583                                 /* Wipe each grid */
1584                                 *aa++ = na;
1585                                 *cc++ = nc;
1586
1587                                 *taa++ = na;
1588                                 *tcc++ = nc;
1589                         }
1590                 }
1591
1592                 /* Redraw every row */
1593                 Term->y1 = y1 = 0;
1594                 Term->y2 = y2 = h - 1;
1595
1596                 /* Redraw every column */
1597                 for (y = 0; y < h; y++)
1598                 {
1599                         Term->x1[y] = 0;
1600                         Term->x2[y] = w - 1;
1601                 }
1602
1603                 /* Forget "total erase" */
1604                 Term->total_erase = FALSE;
1605         }
1606
1607
1608         /* Cursor update -- Erase old Cursor */
1609         if (Term->soft_cursor)
1610         {
1611                 /* Cursor was visible */
1612                 if (!old->cu && old->cv)
1613                 {
1614                         int csize = 1;
1615                         int tx = old->cx;
1616                         int ty = old->cy;
1617
1618                         byte *old_aa = old->a[ty];
1619                         char *old_cc = old->c[ty];
1620
1621                         byte *old_taa = old->ta[ty];
1622                         char *old_tcc = old->tc[ty];
1623
1624                         byte ota = old_taa[tx];
1625                         char otc = old_tcc[tx];
1626
1627 #ifdef JP
1628                         if (tx + 1 < Term->wid && !(old_aa[tx] & AF_TILE1)
1629                             && iskanji(old_cc[tx]))
1630                                 csize = 2;
1631 #endif
1632                         /* Hack -- use "Term_pict()" always */
1633                         if (Term->always_pict)
1634                         {
1635                                 (void)((*Term->pict_hook)(tx, ty, csize, &old_aa[tx], &old_cc[tx], &ota, &otc));
1636                         }
1637
1638                         /* Hack -- use "Term_pict()" sometimes */
1639                         else if (Term->higher_pict && (old_aa[tx] & AF_TILE1) && (old_cc[tx] & 0x80))
1640                         {
1641                                 (void)((*Term->pict_hook)(tx, ty, 1, &old_aa[tx], &old_cc[tx], &ota, &otc));
1642                         }
1643
1644                         /* Hack -- restore the actual character */
1645                         else if (old_aa[tx] || Term->always_text)
1646                         {
1647
1648 #ifdef CHUUKEI
1649                                 send_text_to_chuukei_server(tx, ty, csize, (old_aa[tx] & 0xf), &old_cc[tx]);
1650 #endif
1651                                 (void)((*Term->text_hook)(tx, ty, csize, (unsigned char) (old_aa[tx] & 0xf), &old_cc[tx]));
1652                         }
1653
1654                         /* Hack -- erase the grid */
1655                         else
1656                         {
1657 #ifdef CHUUKEI
1658                         send_wipe_to_chuukei_server(tx, ty, 1);
1659 #endif
1660                                 (void)((*Term->wipe_hook)(tx, ty, 1));
1661                         }
1662                 }
1663         }
1664
1665         /* Cursor Update -- Erase old Cursor */
1666         else
1667         {
1668                 /* Cursor will be invisible */
1669                 if (scr->cu || !scr->cv)
1670                 {
1671                         /* Make the cursor invisible */
1672                         Term_xtra(TERM_XTRA_SHAPE, 0);
1673                 }
1674         }
1675
1676
1677         /* Something to update */
1678         if (y1 <= y2)
1679         {
1680                 /* Handle "icky corner" */
1681                 if (Term->icky_corner)
1682                 {
1683                         /* Avoid the corner */
1684                         if (y2 >= h - 1)
1685                         {
1686                                 /* Avoid the corner */
1687                                 if (Term->x2[h - 1] > w - 2)
1688                                 {
1689                                         /* Avoid the corner */
1690                                         Term->x2[h - 1] = w - 2;
1691                                 }
1692                         }
1693                 }
1694
1695
1696                 /* Scan the "modified" rows */
1697                 for (y = y1; y <= y2; ++y)
1698                 {
1699                         int x1 = Term->x1[y];
1700                         int x2 = Term->x2[y];
1701
1702                         /* Flush each "modified" row */
1703                         if (x1 <= x2)
1704                         {
1705                                 /* Always use "Term_pict()" */
1706                                 if (Term->always_pict)
1707                                 {
1708                                         /* Flush the row */
1709                                         Term_fresh_row_pict(y, x1, x2);
1710                                 }
1711
1712                                 /* Sometimes use "Term_pict()" */
1713                                 else if (Term->higher_pict)
1714                                 {
1715                                         /* Flush the row */
1716                                         Term_fresh_row_both(y, x1, x2);
1717                                 }
1718
1719                                 /* Never use "Term_pict()" */
1720                                 else
1721                                 {
1722                                         /* Flush the row */
1723                                         Term_fresh_row_text(y, x1, x2);
1724                                 }
1725
1726                                 /* This row is all done */
1727                                 Term->x1[y] = w;
1728                                 Term->x2[y] = 0;
1729
1730                                 /* Hack -- Flush that row (if allowed) */
1731                                 if (!Term->never_frosh) Term_xtra(TERM_XTRA_FROSH, y);
1732                         }
1733                 }
1734
1735                 /* No rows are invalid */
1736                 Term->y1 = h;
1737                 Term->y2 = 0;
1738         }
1739
1740
1741         /* Cursor update -- Show new Cursor */
1742         if (Term->soft_cursor)
1743         {
1744                 /* Draw the cursor */
1745                 if (!scr->cu && scr->cv)
1746                 {
1747 #ifdef CHUUKEI
1748                         send_curs_to_chuukei_server(scr->cx, scr->cy);
1749 #endif
1750
1751 #ifdef JP
1752                         if ((scr->cx + 1 < w) &&
1753                             ((old->a[scr->cy][scr->cx + 1] & AF_BIGTILE2) == AF_BIGTILE2 ||
1754                              (!(old->a[scr->cy][scr->cx] & AF_TILE1) &&
1755                               iskanji(old->c[scr->cy][scr->cx]))))
1756 #else
1757                         if ((scr->cx + 1 < w) && (old->a[scr->cy][scr->cx + 1] & AF_BIGTILE2) == AF_BIGTILE2)
1758 #endif
1759                         {
1760                                 /* Double width cursor for the Bigtile mode */
1761                                 (void)((*Term->bigcurs_hook)(scr->cx, scr->cy));
1762                         }
1763                         else
1764                         {
1765                                 /* Call the cursor display routine */
1766                                 (void)((*Term->curs_hook)(scr->cx, scr->cy));
1767                         }
1768                 }
1769         }
1770
1771         /* Cursor Update -- Show new Cursor */
1772         else
1773         {
1774                 /* The cursor is useless, hide it */
1775                 if (scr->cu)
1776                 {
1777 #ifdef CHUUKEI
1778                   send_curs_to_chuukei_server(w - 1, scr->cy);
1779 #endif
1780                         /* Paranoia -- Put the cursor NEAR where it belongs */
1781                         (void)((*Term->curs_hook)(w - 1, scr->cy));
1782
1783                         /* Make the cursor invisible */
1784                         /* Term_xtra(TERM_XTRA_SHAPE, 0); */
1785                 }
1786
1787                 /* The cursor is invisible, hide it */
1788                 else if (!scr->cv)
1789                 {
1790 #ifdef CHUUKEI
1791                   send_curs_to_chuukei_server(scr->cx, scr->cy);
1792 #endif
1793                         /* Paranoia -- Put the cursor where it belongs */
1794                         (void)((*Term->curs_hook)(scr->cx, scr->cy));
1795
1796                         /* Make the cursor invisible */
1797                         /* Term_xtra(TERM_XTRA_SHAPE, 0); */
1798                 }
1799
1800                 /* The cursor is visible, display it correctly */
1801                 else
1802                 {
1803 #ifdef CHUUKEI
1804                   send_curs_to_chuukei_server(scr->cx, scr->cy);
1805 #endif
1806                         /* Put the cursor where it belongs */
1807                         (void)((*Term->curs_hook)(scr->cx, scr->cy));
1808
1809                         /* Make the cursor visible */
1810                         Term_xtra(TERM_XTRA_SHAPE, 1);
1811                 }
1812         }
1813
1814
1815         /* Save the "cursor state" */
1816         old->cu = scr->cu;
1817         old->cv = scr->cv;
1818         old->cx = scr->cx;
1819         old->cy = scr->cy;
1820
1821
1822         /* Actually flush the output */
1823         Term_xtra(TERM_XTRA_FRESH, 0);
1824
1825
1826         /* Success */
1827         return (0);
1828 }
1829
1830
1831
1832 /*** Output routines ***/
1833
1834
1835 /*
1836  * Set the cursor visibility
1837  */
1838 errr Term_set_cursor(int v)
1839 {
1840         /* Already done */
1841         if (Term->scr->cv == v) return (1);
1842
1843         /* Change */
1844         Term->scr->cv = v;
1845
1846         /* Success */
1847         return (0);
1848 }
1849
1850
1851 /*
1852  * Place the cursor at a given location
1853  *
1854  * Note -- "illegal" requests do not move the cursor.
1855  */
1856 errr Term_gotoxy(int x, int y)
1857 {
1858         int w = Term->wid;
1859         int h = Term->hgt;
1860
1861         /* Verify */
1862         if ((x < 0) || (x >= w)) return (-1);
1863         if ((y < 0) || (y >= h)) return (-1);
1864
1865         /* Remember the cursor */
1866         Term->scr->cx = x;
1867         Term->scr->cy = y;
1868
1869         /* The cursor is not useless */
1870         Term->scr->cu = 0;
1871
1872         /* Success */
1873         return (0);
1874 }
1875
1876
1877 /*
1878  * At a given location, place an attr/char
1879  * Do not change the cursor position
1880  * No visual changes until "Term_fresh()".
1881  */
1882 errr Term_draw(int x, int y, byte a, char c)
1883 {
1884         int w = Term->wid;
1885         int h = Term->hgt;
1886
1887         /* Verify location */
1888         if ((x < 0) || (x >= w)) return (-1);
1889         if ((y < 0) || (y >= h)) return (-1);
1890
1891         /* Paranoia -- illegal char */
1892         if (!c) return (-2);
1893
1894         /* Queue it for later */
1895         Term_queue_char(x, y, a, c, 0, 0);
1896
1897         /* Success */
1898         return (0);
1899 }
1900
1901
1902 /*
1903  * Using the given attr, add the given char at the cursor.
1904  *
1905  * We return "-2" if the character is "illegal". XXX XXX
1906  *
1907  * We return "-1" if the cursor is currently unusable.
1908  *
1909  * We queue the given attr/char for display at the current
1910  * cursor location, and advance the cursor to the right,
1911  * marking it as unuable and returning "1" if it leaves
1912  * the screen, and otherwise returning "0".
1913  *
1914  * So when this function, or the following one, return a
1915  * positive value, future calls to either function will
1916  * return negative ones.
1917  */
1918 errr Term_addch(byte a, char c)
1919 {
1920         int w = Term->wid;
1921
1922         /* Handle "unusable" cursor */
1923         if (Term->scr->cu) return (-1);
1924
1925         /* Paranoia -- no illegal chars */
1926         if (!c) return (-2);
1927
1928         /* Queue the given character for display */
1929         Term_queue_char(Term->scr->cx, Term->scr->cy, a, c, 0, 0);
1930
1931         /* Advance the cursor */
1932         Term->scr->cx++;
1933
1934         /* Success */
1935         if (Term->scr->cx < w) return (0);
1936
1937         /* Note "Useless" cursor */
1938         Term->scr->cu = 1;
1939
1940         /* Note "Useless" cursor */
1941         return (1);
1942 }
1943
1944
1945 /*
1946  * Bigtile version of Term_addch().
1947  *
1948  * If use_bigtile is FALSE, simply call Term_addch() .
1949  *
1950  * Otherwise, queue a pair of attr/char for display at the current
1951  * cursor location, and advance the cursor to the right by two.
1952  */
1953 errr Term_add_bigch(byte a, char c)
1954 {
1955         if (!use_bigtile) return Term_addch(a, c);
1956
1957         /* Handle "unusable" cursor */
1958         if (Term->scr->cu) return (-1);
1959
1960         /* Paranoia -- no illegal chars */
1961         if (!c) return (-2);
1962
1963         /* Queue the given character for display */
1964         Term_queue_bigchar(Term->scr->cx, Term->scr->cy, a, c, 0, 0);
1965
1966         /* Advance the cursor */
1967         Term->scr->cx += 2;
1968
1969         /* Success */
1970         if (Term->scr->cx < Term->wid) return (0);
1971
1972         /* Note "Useless" cursor */
1973         Term->scr->cu = 1;
1974
1975         /* Note "Useless" cursor */
1976         return (1);
1977 }
1978
1979
1980 /*
1981  * At the current location, using an attr, add a string
1982  *
1983  * We also take a length "n", using negative values to imply
1984  * the largest possible value, and then we use the minimum of
1985  * this length and the "actual" length of the string as the
1986  * actual number of characters to attempt to display, never
1987  * displaying more characters than will actually fit, since
1988  * we do NOT attempt to "wrap" the cursor at the screen edge.
1989  *
1990  * We return "-1" if the cursor is currently unusable.
1991  * We return "N" if we were "only" able to write "N" chars,
1992  * even if all of the given characters fit on the screen,
1993  * and mark the cursor as unusable for future attempts.
1994  *
1995  * So when this function, or the preceding one, return a
1996  * positive value, future calls to either function will
1997  * return negative ones.
1998  */
1999 errr Term_addstr(int n, byte a, cptr s)
2000 {
2001         int k;
2002
2003         int w = Term->wid;
2004
2005         errr res = 0;
2006
2007         /* Handle "unusable" cursor */
2008         if (Term->scr->cu) return (-1);
2009
2010         /* Obtain maximal length */
2011         k = (n < 0) ? (w + 1) : n;
2012
2013         /* Obtain the usable string length */
2014         for (n = 0; (n < k) && s[n]; n++) /* loop */;
2015
2016         /* React to reaching the edge of the screen */
2017         if (Term->scr->cx + n >= w) res = n = w - Term->scr->cx;
2018
2019         /* Queue the first "n" characters for display */
2020         Term_queue_chars(Term->scr->cx, Term->scr->cy, n, a, s);
2021
2022         /* Advance the cursor */
2023         Term->scr->cx += n;
2024
2025         /* Hack -- Notice "Useless" cursor */
2026         if (res) Term->scr->cu = 1;
2027
2028         /* Success (usually) */
2029         return (res);
2030 }
2031
2032
2033 /*
2034  * Move to a location and, using an attr, add a char
2035  */
2036 errr Term_putch(int x, int y, byte a, char c)
2037 {
2038         errr res;
2039
2040         /* Move first */
2041         if ((res = Term_gotoxy(x, y)) != 0) return (res);
2042
2043         /* Then add the char */
2044         if ((res = Term_addch(a, c)) != 0) return (res);
2045
2046         /* Success */
2047         return (0);
2048 }
2049
2050
2051 /*
2052  * Move to a location and, using an attr, add a string
2053  */
2054 errr Term_putstr(int x, int y, int n, byte a, cptr s)
2055 {
2056         errr res;
2057
2058         /* Move first */
2059         if ((res = Term_gotoxy(x, y)) != 0) return (res);
2060
2061         /* Then add the string */
2062         if ((res = Term_addstr(n, a, s)) != 0) return (res);
2063
2064         /* Success */
2065         return (0);
2066 }
2067
2068 #ifdef JP
2069 /*
2070  * Move to a location and, using an attr, add a string vertically
2071  */
2072 errr Term_putstr_v(int x, int y, int n, byte a, cptr s)
2073 {
2074         errr res;
2075         int i;
2076         int y0 = y;
2077
2078
2079         for (i = 0; i < n && s[i] != 0; i++)
2080         {
2081           /* Move first */
2082           if ((res = Term_gotoxy(x, y0)) != 0) return (res);
2083
2084           if (iskanji(s[i]))
2085           {
2086             if ((res = Term_addstr(2, a, &s[i])) != 0) return (res);
2087             i++;
2088             y0++;
2089             if (s[i] == 0) break;
2090           } else {
2091             if ((res = Term_addstr(1, a, &s[i])) != 0) return (res);
2092             y0++;
2093           }
2094         }
2095
2096         /* Success */
2097         return (0);
2098 }
2099 #endif
2100
2101 /*
2102  * Place cursor at (x,y), and clear the next "n" chars
2103  */
2104 errr Term_erase(int x, int y, int n)
2105 {
2106         int i;
2107
2108         int w = Term->wid;
2109         /* int h = Term->hgt; */
2110
2111         int x1 = -1;
2112         int x2 = -1;
2113
2114         int na = Term->attr_blank;
2115         int nc = Term->char_blank;
2116
2117         byte *scr_aa;
2118         char *scr_cc;
2119
2120         byte *scr_taa;
2121         char *scr_tcc;
2122
2123         /* Place cursor */
2124         if (Term_gotoxy(x, y)) return (-1);
2125
2126         /* Force legal size */
2127         if (x + n > w) n = w - x;
2128
2129         /* Fast access */
2130         scr_aa = Term->scr->a[y];
2131         scr_cc = Term->scr->c[y];
2132
2133         scr_taa = Term->scr->ta[y];
2134         scr_tcc = Term->scr->tc[y];
2135
2136 #ifdef JP
2137         /*
2138          * Á´³Ñʸ»ú¤Î±¦È¾Ê¬¤«¤éʸ»ú¤òɽ¼¨¤¹¤ë¾ì¹ç¡¢
2139          * ½Å¤Ê¤Ã¤¿Ê¸»ú¤Îº¸Éôʬ¤ò¾Ãµî¡£
2140          */
2141         if (n > 0 && (((scr_aa[x] & AF_KANJI2) && !(scr_aa[x] & AF_TILE1))
2142                       || (scr_aa[x] & AF_BIGTILE2) == AF_BIGTILE2))
2143 #else
2144         if (n > 0 && (scr_aa[x] & AF_BIGTILE2) == AF_BIGTILE2)
2145 #endif
2146         {
2147                 x--;
2148                 n++;
2149         }
2150
2151         /* Scan every column */
2152         for (i = 0; i < n; i++, x++)
2153         {
2154                 int oa = scr_aa[x];
2155                 int oc = scr_cc[x];
2156
2157                 /* Hack -- Ignore "non-changes" */
2158                 if ((oa == na) && (oc == nc)) continue;
2159
2160 #ifdef JP
2161                 /*
2162                  * Á´³Ñʸ»ú¤Îº¸È¾Ê¬¤Çɽ¼¨¤ò½ªÎ»¤¹¤ë¾ì¹ç¡¢
2163                  * ½Å¤Ê¤Ã¤¿Ê¸»ú¤Î±¦Éôʬ¤ò¾Ãµî¡£
2164                  *
2165                  * 2001/04/29 -- Habu
2166                  * ¹Ô¤Î±¦Ã¼¤Î¾ì¹ç¤Ï¤³¤Î½èÍý¤ò¤·¤Ê¤¤¤è¤¦¤Ë½¤Àµ¡£
2167                  */
2168                 if ((oa & AF_KANJI1) && (i + 1) == n && x != w - 1)
2169                         n++;
2170 #endif
2171                 /* Save the "literal" information */
2172                 scr_aa[x] = na;
2173                 scr_cc[x] = nc;
2174
2175                 scr_taa[x] = 0;
2176                 scr_tcc[x] = 0;
2177
2178                 /* Track minimum changed column */
2179                 if (x1 < 0) x1 = x;
2180
2181                 /* Track maximum changed column */
2182                 x2 = x;
2183         }
2184
2185         /* Expand the "change area" as needed */
2186         if (x1 >= 0)
2187         {
2188                 /* Check for new min/max row info */
2189                 if (y < Term->y1) Term->y1 = y;
2190                 if (y > Term->y2) Term->y2 = y;
2191
2192                 /* Check for new min/max col info in this row */
2193                 if (x1 < Term->x1[y]) Term->x1[y] = x1;
2194                 if (x2 > Term->x2[y]) Term->x2[y] = x2;
2195         }
2196
2197         /* Success */
2198         return (0);
2199 }
2200
2201
2202 /*
2203  * Clear the entire window, and move to the top left corner
2204  *
2205  * Note the use of the special "total_erase" code
2206  */
2207 errr Term_clear(void)
2208 {
2209         int x, y;
2210
2211         int w = Term->wid;
2212         int h = Term->hgt;
2213
2214         byte na = Term->attr_blank;
2215         char nc = Term->char_blank;
2216
2217         /* Cursor usable */
2218         Term->scr->cu = 0;
2219
2220         /* Cursor to the top left */
2221         Term->scr->cx = Term->scr->cy = 0;
2222
2223         /* Wipe each row */
2224         for (y = 0; y < h; y++)
2225         {
2226                 byte *scr_aa = Term->scr->a[y];
2227                 char *scr_cc = Term->scr->c[y];
2228
2229                 byte *scr_taa = Term->scr->ta[y];
2230                 char *scr_tcc = Term->scr->tc[y];
2231
2232                 /* Wipe each column */
2233                 for (x = 0; x < w; x++)
2234                 {
2235                         scr_aa[x] = na;
2236                         scr_cc[x] = nc;
2237
2238                         scr_taa[x] = 0;
2239                         scr_tcc[x] = 0;
2240                 }
2241
2242                 /* This row has changed */
2243                 Term->x1[y] = 0;
2244                 Term->x2[y] = w - 1;
2245         }
2246
2247         /* Every row has changed */
2248         Term->y1 = 0;
2249         Term->y2 = h - 1;
2250
2251         /* Force "total erase" */
2252         Term->total_erase = TRUE;
2253
2254         /* Success */
2255         return (0);
2256 }
2257
2258
2259
2260
2261
2262 /*
2263  * Redraw (and refresh) the whole window.
2264  */
2265 errr Term_redraw(void)
2266 {
2267         /* Force "total erase" */
2268         Term->total_erase = TRUE;
2269
2270         /* Hack -- Refresh */
2271         Term_fresh();
2272
2273         /* Success */
2274         return (0);
2275 }
2276
2277
2278 /*
2279  * Redraw part of a widow.
2280  */
2281 errr Term_redraw_section(int x1, int y1, int x2, int y2)
2282 {
2283         int i, j;
2284
2285         char *c_ptr;
2286
2287         /* Bounds checking */
2288         if (y2 >= Term->hgt) y2 = Term->hgt - 1;
2289         if (x2 >= Term->wid) x2 = Term->wid - 1;
2290         if (y1 < 0) y1 = 0;
2291         if (x1 < 0) x1 = 0;
2292
2293         /* Set y limits */
2294         Term->y1 = y1;
2295         Term->y2 = y2;
2296
2297         /* Set the x limits */
2298         for (i = Term->y1; i <= Term->y2; i++)
2299         {
2300 #ifdef JP
2301                 int x1j = x1;
2302                 int x2j = x2;
2303    
2304                 if (x1j > 0)
2305                 {
2306                         if (Term->scr->a[i][x1j] & AF_KANJI2) x1j--;
2307                 }
2308    
2309                 if (x2j < Term->wid - 1)
2310                 {
2311                         if (Term->scr->a[i][x2j] & AF_KANJI1) x2j++;
2312                 }
2313    
2314                 Term->x1[i] = x1j;
2315                 Term->x2[i] = x2j;
2316    
2317                 c_ptr = Term->old->c[i];
2318    
2319                 /* Clear the section so it is redrawn */
2320                 for (j = x1j; j <= x2j; j++)
2321                 {
2322                         /* Hack - set the old character to "none" */
2323                         c_ptr[j] = 0;
2324                 }
2325 #else
2326                 Term->x1[i] = x1;
2327                 Term->x2[i] = x2;
2328
2329                 c_ptr = Term->old->c[i];
2330
2331                 /* Clear the section so it is redrawn */
2332                 for (j = x1; j <= x2; j++)
2333                 {
2334                         /* Hack - set the old character to "none" */
2335                         c_ptr[j] = 0;
2336                 }
2337 #endif
2338         }
2339
2340         /* Hack -- Refresh */
2341         Term_fresh();
2342
2343         /* Success */
2344         return (0);
2345 }
2346
2347
2348
2349 /*** Access routines ***/
2350
2351
2352 /*
2353  * Extract the cursor visibility
2354  */
2355 errr Term_get_cursor(int *v)
2356 {
2357         /* Extract visibility */
2358         (*v) = Term->scr->cv;
2359
2360         /* Success */
2361         return (0);
2362 }
2363
2364
2365 /*
2366  * Extract the current window size
2367  */
2368 errr Term_get_size(int *w, int *h)
2369 {
2370         /* Access the cursor */
2371         (*w) = Term->wid;
2372         (*h) = Term->hgt;
2373
2374         /* Success */
2375         return (0);
2376 }
2377
2378
2379 /*
2380  * Extract the current cursor location
2381  */
2382 errr Term_locate(int *x, int *y)
2383 {
2384         /* Access the cursor */
2385         (*x) = Term->scr->cx;
2386         (*y) = Term->scr->cy;
2387
2388         /* Warn about "useless" cursor */
2389         if (Term->scr->cu) return (1);
2390
2391         /* Success */
2392         return (0);
2393 }
2394
2395
2396 /*
2397  * At a given location, determine the "current" attr and char
2398  * Note that this refers to what will be on the window after the
2399  * next call to "Term_fresh()".  It may or may not already be there.
2400  */
2401 errr Term_what(int x, int y, byte *a, char *c)
2402 {
2403         int w = Term->wid;
2404         int h = Term->hgt;
2405
2406         /* Verify location */
2407         if ((x < 0) || (x >= w)) return (-1);
2408         if ((y < 0) || (y >= h)) return (-1);
2409
2410         /* Direct access */
2411         (*a) = Term->scr->a[y][x];
2412         (*c) = Term->scr->c[y][x];
2413
2414         /* Success */
2415         return (0);
2416 }
2417
2418
2419
2420 /*** Input routines ***/
2421
2422
2423 /*
2424  * Flush and forget the input
2425  */
2426 errr Term_flush(void)
2427 {
2428         /* Hack -- Flush all events */
2429         Term_xtra(TERM_XTRA_FLUSH, 0);
2430
2431         /* Forget all keypresses */
2432         Term->key_head = Term->key_tail = 0;
2433
2434         /* Success */
2435         return (0);
2436 }
2437
2438
2439
2440 /*
2441  * Add a keypress to the "queue"
2442  */
2443 errr Term_keypress(int k)
2444 {
2445         /* Hack -- Refuse to enqueue non-keys */
2446         if (!k) return (-1);
2447
2448         /* Store the char, advance the queue */
2449         Term->key_queue[Term->key_head++] = k;
2450
2451         /* Circular queue, handle wrap */
2452         if (Term->key_head == Term->key_size) Term->key_head = 0;
2453
2454         /* Success (unless overflow) */
2455         if (Term->key_head != Term->key_tail) return (0);
2456
2457 #if 0
2458         /* Hack -- Forget the oldest key */
2459         if (++Term->key_tail == Term->key_size) Term->key_tail = 0;
2460 #endif
2461
2462         /* Problem */
2463         return (1);
2464 }
2465
2466
2467 /*
2468  * Add a keypress to the FRONT of the "queue"
2469  */
2470 errr Term_key_push(int k)
2471 {
2472         /* Hack -- Refuse to enqueue non-keys */
2473         if (!k) return (-1);
2474
2475         /* Hack -- Overflow may induce circular queue */
2476         if (Term->key_tail == 0) Term->key_tail = Term->key_size;
2477
2478         /* Back up, Store the char */
2479         Term->key_queue[--Term->key_tail] = k;
2480
2481         /* Success (unless overflow) */
2482         if (Term->key_head != Term->key_tail) return (0);
2483
2484 #if 0
2485         /* Hack -- Forget the oldest key */
2486         if (++Term->key_tail == Term->key_size) Term->key_tail = 0;
2487 #endif
2488
2489         /* Problem */
2490         return (1);
2491 }
2492
2493
2494
2495
2496
2497 /*
2498  * Check for a pending keypress on the key queue.
2499  *
2500  * Store the keypress, if any, in "ch", and return "0".
2501  * Otherwise store "zero" in "ch", and return "1".
2502  *
2503  * Wait for a keypress if "wait" is true.
2504  *
2505  * Remove the keypress if "take" is true.
2506  */
2507 errr Term_inkey(char *ch, bool wait, bool take)
2508 {
2509         /* Assume no key */
2510         (*ch) = '\0';
2511
2512 #ifdef CHUUKEI
2513         flush_ringbuf();
2514 #endif
2515
2516         /* Hack -- get bored */
2517         if (!Term->never_bored)
2518         {
2519                 /* Process random events */
2520                 Term_xtra(TERM_XTRA_BORED, 0);
2521         }
2522
2523         /* Wait */
2524         if (wait)
2525         {
2526                 /* Process pending events while necessary */
2527                 while (Term->key_head == Term->key_tail)
2528                 {
2529                         /* Process events (wait for one) */
2530                         Term_xtra(TERM_XTRA_EVENT, TRUE);
2531                 }
2532         }
2533
2534         /* Do not Wait */
2535         else
2536         {
2537                 /* Process pending events if necessary */
2538                 if (Term->key_head == Term->key_tail)
2539                 {
2540                         /* Process events (do not wait) */
2541                         Term_xtra(TERM_XTRA_EVENT, FALSE);
2542                 }
2543         }
2544
2545         /* No keys are ready */
2546         if (Term->key_head == Term->key_tail) return (1);
2547
2548         /* Extract the next keypress */
2549         (*ch) = Term->key_queue[Term->key_tail];
2550
2551         /* If requested, advance the queue, wrap around if necessary */
2552         if (take && (++Term->key_tail == Term->key_size)) Term->key_tail = 0;
2553
2554         /* Success */
2555         return (0);
2556 }
2557
2558
2559
2560 /*** Extra routines ***/
2561
2562
2563 /*
2564  * Save the "requested" screen into the "memorized" screen
2565  *
2566  * Every "Term_save()" should match exactly one "Term_load()"
2567  */
2568 errr Term_save(void)
2569 {
2570         int w = Term->wid;
2571         int h = Term->hgt;
2572
2573         /* Create */
2574         if (!Term->mem)
2575         {
2576                 /* Allocate window */
2577                 MAKE(Term->mem, term_win);
2578
2579                 /* Initialize window */
2580                 term_win_init(Term->mem, w, h);
2581         }
2582
2583         /* Grab */
2584         term_win_copy(Term->mem, Term->scr, w, h);
2585
2586         /* Success */
2587         return (0);
2588 }
2589
2590
2591 /*
2592  * Restore the "requested" contents (see above).
2593  *
2594  * Every "Term_save()" should match exactly one "Term_load()"
2595  */
2596 errr Term_load(void)
2597 {
2598         int y;
2599
2600         int w = Term->wid;
2601         int h = Term->hgt;
2602
2603         /* Create */
2604         if (!Term->mem)
2605         {
2606                 /* Allocate window */
2607                 MAKE(Term->mem, term_win);
2608
2609                 /* Initialize window */
2610                 term_win_init(Term->mem, w, h);
2611         }
2612
2613         /* Load */
2614         term_win_copy(Term->scr, Term->mem, w, h);
2615
2616         /* Assume change */
2617         for (y = 0; y < h; y++)
2618         {
2619                 /* Assume change */
2620                 Term->x1[y] = 0;
2621                 Term->x2[y] = w - 1;
2622         }
2623
2624         /* Assume change */
2625         Term->y1 = 0;
2626         Term->y2 = h - 1;
2627
2628         /* Success */
2629         return (0);
2630 }
2631
2632
2633 /*
2634  * Exchange the "requested" screen with the "tmp" screen
2635  */
2636 errr Term_exchange(void)
2637 {
2638         int y;
2639
2640         int w = Term->wid;
2641         int h = Term->hgt;
2642
2643         term_win *exchanger;
2644
2645
2646         /* Create */
2647         if (!Term->tmp)
2648         {
2649                 /* Allocate window */
2650                 MAKE(Term->tmp, term_win);
2651
2652                 /* Initialize window */
2653                 term_win_init(Term->tmp, w, h);
2654         }
2655
2656         /* Swap */
2657         exchanger = Term->scr;
2658         Term->scr = Term->tmp;
2659         Term->tmp = exchanger;
2660
2661         /* Assume change */
2662         for (y = 0; y < h; y++)
2663         {
2664                 /* Assume change */
2665                 Term->x1[y] = 0;
2666                 Term->x2[y] = w - 1;
2667         }
2668
2669         /* Assume change */
2670         Term->y1 = 0;
2671         Term->y2 = h - 1;
2672
2673         /* Success */
2674         return (0);
2675 }
2676
2677
2678
2679 /*
2680  * React to a new physical window size.
2681  */
2682 errr Term_resize(int w, int h)
2683 {
2684         int i;
2685
2686         int wid, hgt;
2687
2688         byte *hold_x1;
2689         byte *hold_x2;
2690
2691         term_win *hold_old;
2692         term_win *hold_scr;
2693         term_win *hold_mem;
2694         term_win *hold_tmp;
2695
2696         /* Resizing is forbidden */
2697         if (Term->fixed_shape) return (-1);
2698
2699         /* Ignore illegal changes */
2700         if ((w < 1) || (h < 1)) return (-1);
2701
2702
2703         /* Ignore non-changes */
2704         if ((Term->wid == w) && (Term->hgt == h) && (arg_bigtile == use_bigtile))
2705                 return (1);
2706
2707         use_bigtile = arg_bigtile;
2708
2709         /* Minimum dimensions */
2710         wid = MIN(Term->wid, w);
2711         hgt = MIN(Term->hgt, h);
2712
2713         /* Save scanners */
2714         hold_x1 = Term->x1;
2715         hold_x2 = Term->x2;
2716
2717         /* Save old window */
2718         hold_old = Term->old;
2719
2720         /* Save old window */
2721         hold_scr = Term->scr;
2722
2723         /* Save old window */
2724         hold_mem = Term->mem;
2725
2726         /* Save old window */
2727         hold_tmp = Term->tmp;
2728
2729         /* Create new scanners */
2730         C_MAKE(Term->x1, h, byte);
2731         C_MAKE(Term->x2, h, byte);
2732
2733         /* Create new window */
2734         MAKE(Term->old, term_win);
2735
2736         /* Initialize new window */
2737         term_win_init(Term->old, w, h);
2738
2739         /* Save the contents */
2740         term_win_copy(Term->old, hold_old, wid, hgt);
2741
2742         /* Create new window */
2743         MAKE(Term->scr, term_win);
2744
2745         /* Initialize new window */
2746         term_win_init(Term->scr, w, h);
2747
2748         /* Save the contents */
2749         term_win_copy(Term->scr, hold_scr, wid, hgt);
2750
2751         /* If needed */
2752         if (hold_mem)
2753         {
2754                 /* Create new window */
2755                 MAKE(Term->mem, term_win);
2756
2757                 /* Initialize new window */
2758                 term_win_init(Term->mem, w, h);
2759
2760                 /* Save the contents */
2761                 term_win_copy(Term->mem, hold_mem, wid, hgt);
2762         }
2763
2764         /* If needed */
2765         if (hold_tmp)
2766         {
2767                 /* Create new window */
2768                 MAKE(Term->tmp, term_win);
2769
2770                 /* Initialize new window */
2771                 term_win_init(Term->tmp, w, h);
2772
2773                 /* Save the contents */
2774                 term_win_copy(Term->tmp, hold_tmp, wid, hgt);
2775         }
2776
2777         /* Free some arrays */
2778         C_KILL(hold_x1, Term->hgt, byte);
2779         C_KILL(hold_x2, Term->hgt, byte);
2780
2781         /* Nuke */
2782         term_win_nuke(hold_old, Term->wid, Term->hgt);
2783
2784         /* Kill */
2785         KILL(hold_old, term_win);
2786
2787         /* Illegal cursor */
2788         if (Term->old->cx >= w) Term->old->cu = 1;
2789         if (Term->old->cy >= h) Term->old->cu = 1;
2790
2791         /* Nuke */
2792         term_win_nuke(hold_scr, Term->wid, Term->hgt);
2793
2794         /* Kill */
2795         KILL(hold_scr, term_win);
2796
2797         /* Illegal cursor */
2798         if (Term->scr->cx >= w) Term->scr->cu = 1;
2799         if (Term->scr->cy >= h) Term->scr->cu = 1;
2800
2801         /* If needed */
2802         if (hold_mem)
2803         {
2804                 /* Nuke */
2805                 term_win_nuke(hold_mem, Term->wid, Term->hgt);
2806
2807                 /* Kill */
2808                 KILL(hold_mem, term_win);
2809
2810                 /* Illegal cursor */
2811                 if (Term->mem->cx >= w) Term->mem->cu = 1;
2812                 if (Term->mem->cy >= h) Term->mem->cu = 1;
2813         }
2814
2815         /* If needed */
2816         if (hold_tmp)
2817         {
2818                 /* Nuke */
2819                 term_win_nuke(hold_tmp, Term->wid, Term->hgt);
2820
2821                 /* Kill */
2822                 KILL(hold_tmp, term_win);
2823
2824                 /* Illegal cursor */
2825                 if (Term->tmp->cx >= w) Term->tmp->cu = 1;
2826                 if (Term->tmp->cy >= h) Term->tmp->cu = 1;
2827         }
2828
2829         /* Save new size */
2830         Term->wid = w;
2831         Term->hgt = h;
2832
2833         /* Force "total erase" */
2834         Term->total_erase = TRUE;
2835
2836         /* Assume change */
2837         for (i = 0; i < h; i++)
2838         {
2839                 /* Assume change */
2840                 Term->x1[i] = 0;
2841                 Term->x2[i] = w - 1;
2842         }
2843
2844         /* Assume change */
2845         Term->y1 = 0;
2846         Term->y2 = h - 1;
2847
2848         /* Execute the "resize_hook" hook, if available */
2849         if (Term->resize_hook)
2850         {
2851                 Term->resize_hook();
2852         }
2853
2854         /* Success */
2855         return (0);
2856 }
2857
2858
2859
2860 /*
2861  * Activate a new Term (and deactivate the current Term)
2862  *
2863  * This function is extremely important, and also somewhat bizarre.
2864  * It is the only function that should "modify" the value of "Term".
2865  *
2866  * To "create" a valid "term", one should do "term_init(t)", then
2867  * set the various flags and hooks, and then do "Term_activate(t)".
2868  */
2869 errr Term_activate(term *t)
2870 {
2871         /* Hack -- already done */
2872         if (Term == t) return (1);
2873
2874         /* Deactivate the old Term */
2875         if (Term) Term_xtra(TERM_XTRA_LEVEL, 0);
2876
2877         /* Hack -- Call the special "init" hook */
2878         if (t && !t->active_flag)
2879         {
2880                 /* Call the "init" hook */
2881                 if (t->init_hook) (*t->init_hook)(t);
2882
2883                 /* Remember */
2884                 t->active_flag = TRUE;
2885
2886                 /* Assume mapped */
2887                 t->mapped_flag = TRUE;
2888         }
2889
2890         /* Remember the Term */
2891         Term = t;
2892
2893         /* Activate the new Term */
2894         if (Term) Term_xtra(TERM_XTRA_LEVEL, 1);
2895
2896         /* Success */
2897         return (0);
2898 }
2899
2900
2901
2902 /*
2903  * Nuke a term
2904  */
2905 errr term_nuke(term *t)
2906 {
2907         int w = t->wid;
2908         int h = t->hgt;
2909
2910
2911         /* Hack -- Call the special "nuke" hook */
2912         if (t->active_flag)
2913         {
2914                 /* Call the "nuke" hook */
2915                 if (t->nuke_hook) (*t->nuke_hook)(t);
2916
2917                 /* Remember */
2918                 t->active_flag = FALSE;
2919
2920                 /* Assume not mapped */
2921                 t->mapped_flag = FALSE;
2922         }
2923
2924
2925         /* Nuke "displayed" */
2926         term_win_nuke(t->old, w, h);
2927
2928         /* Kill "displayed" */
2929         KILL(t->old, term_win);
2930
2931         /* Nuke "requested" */
2932         term_win_nuke(t->scr, w, h);
2933
2934         /* Kill "requested" */
2935         KILL(t->scr, term_win);
2936
2937         /* If needed */
2938         if (t->mem)
2939         {
2940                 /* Nuke "memorized" */
2941                 term_win_nuke(t->mem, w, h);
2942
2943                 /* Kill "memorized" */
2944                 KILL(t->mem, term_win);
2945         }
2946
2947         /* If needed */
2948         if (t->tmp)
2949         {
2950                 /* Nuke "temporary" */
2951                 term_win_nuke(t->tmp, w, h);
2952
2953                 /* Kill "temporary" */
2954                 KILL(t->tmp, term_win);
2955         }
2956
2957         /* Free some arrays */
2958         C_KILL(t->x1, h, byte);
2959         C_KILL(t->x2, h, byte);
2960
2961         /* Free the input queue */
2962         C_KILL(t->key_queue, t->key_size, char);
2963
2964         /* Success */
2965         return (0);
2966 }
2967
2968
2969 /*
2970  * Initialize a term, using a window of the given size.
2971  * Also prepare the "input queue" for "k" keypresses
2972  * By default, the cursor starts out "invisible"
2973  * By default, we "erase" using "black spaces"
2974  */
2975 errr term_init(term *t, int w, int h, int k)
2976 {
2977         int y;
2978
2979
2980         /* Wipe it */
2981         (void)WIPE(t, term);
2982
2983
2984         /* Prepare the input queue */
2985         t->key_head = t->key_tail = 0;
2986
2987         /* Determine the input queue size */
2988         t->key_size = k;
2989
2990         /* Allocate the input queue */
2991         C_MAKE(t->key_queue, t->key_size, char);
2992
2993
2994         /* Save the size */
2995         t->wid = w;
2996         t->hgt = h;
2997
2998         /* Allocate change arrays */
2999         C_MAKE(t->x1, h, byte);
3000         C_MAKE(t->x2, h, byte);
3001
3002
3003         /* Allocate "displayed" */
3004         MAKE(t->old, term_win);
3005
3006         /* Initialize "displayed" */
3007         term_win_init(t->old, w, h);
3008
3009
3010         /* Allocate "requested" */
3011         MAKE(t->scr, term_win);
3012
3013         /* Initialize "requested" */
3014         term_win_init(t->scr, w, h);
3015
3016
3017         /* Assume change */
3018         for (y = 0; y < h; y++)
3019         {
3020                 /* Assume change */
3021                 t->x1[y] = 0;
3022                 t->x2[y] = w - 1;
3023         }
3024
3025         /* Assume change */
3026         t->y1 = 0;
3027         t->y2 = h - 1;
3028
3029         /* Force "total erase" */
3030         t->total_erase = TRUE;
3031
3032
3033         /* Default "blank" */
3034         t->attr_blank = 0;
3035         t->char_blank = ' ';
3036
3037
3038         /* Success */
3039         return (0);
3040 }
3041
3042