OSDN Git Service

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