OSDN Git Service

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