OSDN Git Service

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