OSDN Git Service

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