OSDN Git Service

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