OSDN Git Service

Merge remote-tracking branch 'remotes/hengbandosx/english-_ptr-in-message' into featu...
[hengband/hengband.git] / src / term / z-term.c
1 /*
2  * @brief Purpose: a generic, efficient, terminal window package -BEN-
3  * Copyright (c) 1997 Ben Harrison
4  *
5  * This software may be copied and distributed for educational, research,
6  * and not for profit purposes provided that this copyright and statement
7  * are included in all such copies.
8  */
9
10 #include "term/z-term.h"
11 #include "core/player-processor.h"
12 #include "game-option/map-screen-options.h"
13 #include "game-option/runtime-arguments.h"
14 #include "game-option/special-options.h"
15 #include "io/input-key-requester.h"
16 #include "term/gameterm.h"
17 #include "term/term-color-types.h"
18 #include "term/z-virt.h"
19
20 /* Special flags in the attr data */
21 #define AF_BIGTILE2 0xf0
22 #define AF_TILE1 0x80
23
24 #ifdef JP
25 /*
26  * 全角文字対応。
27  * 属性に全角文字の1バイト目、2バイト目も記憶。
28  * By FIRST
29  */
30 #define AF_KANJI1 0x10
31 #define AF_KANJI2 0x20
32 #define AF_KANJIC 0x0f
33 #endif
34
35 /* The current "term" */
36 term_type *Term = NULL;
37
38 /*** Local routines ***/
39
40 /*
41  * Nuke a term_win (see below)
42  */
43 errr term_win_nuke(term_win *s, TERM_LEN w, TERM_LEN h)
44 {
45     /* Free the window access arrays */
46     C_KILL(s->a, h, TERM_COLOR *);
47     C_KILL(s->c, h, char *);
48
49     /* Free the window content arrays */
50     C_KILL(s->va, h * w, TERM_COLOR);
51     C_KILL(s->vc, h * w, char);
52
53     /* Free the terrain access arrays */
54     C_KILL(s->ta, h, TERM_COLOR *);
55     C_KILL(s->tc, h, char *);
56
57     /* Free the terrain content arrays */
58     C_KILL(s->vta, h * w, TERM_COLOR);
59     C_KILL(s->vtc, h * w, char);
60
61     return 0;
62 }
63
64 /*
65  * Initialize a "term_win" (using the given window size)
66  */
67 static errr term_win_init(term_win *s, TERM_LEN w, TERM_LEN h)
68 {
69     /* Make the window access arrays */
70     C_MAKE(s->a, h, TERM_COLOR *);
71     C_MAKE(s->c, h, char *);
72
73     /* Make the window content arrays */
74     C_MAKE(s->va, h * w, TERM_COLOR);
75     C_MAKE(s->vc, h * w, char);
76
77     /* Make the terrain access arrays */
78     C_MAKE(s->ta, h, TERM_COLOR *);
79     C_MAKE(s->tc, h, char *);
80
81     /* Make the terrain content arrays */
82     C_MAKE(s->vta, h * w, TERM_COLOR);
83     C_MAKE(s->vtc, h * w, char);
84
85     /* Prepare the window access arrays */
86     for (TERM_LEN y = 0; y < h; y++) {
87         s->a[y] = s->va + w * y;
88         s->c[y] = s->vc + w * y;
89
90         s->ta[y] = s->vta + w * y;
91         s->tc[y] = s->vtc + w * y;
92     }
93
94     return 0;
95 }
96
97 /*
98  * Copy a "term_win" from another
99  */
100 static errr term_win_copy(term_win *s, term_win *f, TERM_LEN w, TERM_LEN h)
101 {
102     /* Copy contents */
103     for (TERM_LEN y = 0; y < h; y++) {
104         TERM_COLOR *f_aa = f->a[y];
105         char *f_cc = f->c[y];
106
107         TERM_COLOR *s_aa = s->a[y];
108         char *s_cc = s->c[y];
109
110         TERM_COLOR *f_taa = f->ta[y];
111         char *f_tcc = f->tc[y];
112
113         TERM_COLOR *s_taa = s->ta[y];
114         char *s_tcc = s->tc[y];
115
116         for (TERM_LEN x = 0; x < w; x++) {
117             *s_aa++ = *f_aa++;
118             *s_cc++ = *f_cc++;
119             *s_taa++ = *f_taa++;
120             *s_tcc++ = *f_tcc++;
121         }
122     }
123
124     /* Copy cursor */
125     s->cx = f->cx;
126     s->cy = f->cy;
127     s->cu = f->cu;
128     s->cv = f->cv;
129
130     return 0;
131 }
132
133 /*** External hooks ***/
134
135 /*
136  * Execute the "Term->user_hook" hook, if available (see above).
137  */
138 errr term_user(int n)
139 {
140     /* Verify the hook */
141     if (!Term->user_hook)
142         return -1;
143
144     /* Call the hook */
145     return ((*Term->user_hook)(n));
146 }
147
148 /*
149  * Execute the "Term->xtra_hook" hook, if available (see above).
150  */
151 errr term_xtra(int n, int v)
152 {
153     /* Verify the hook */
154     if (!Term->xtra_hook)
155         return -1;
156
157     /* Call the hook */
158     return ((*Term->xtra_hook)(n, v));
159 }
160
161 /*** Fake hooks ***/
162
163 /*
164  * Fake hook for "term_curs()" (see above)
165  */
166 static errr term_curs_hack(TERM_LEN x, TERM_LEN y)
167 {
168     /* Unused */
169     (void)x;
170     (void)y;
171
172     return -1;
173 }
174
175 /*
176  * Fake hook for "term_bigcurs()" (see above)
177  */
178 static errr term_bigcurs_hack(TERM_LEN x, TERM_LEN y) { return (*Term->curs_hook)(x, y); }
179
180 /*
181  * Fake hook for "term_wipe()" (see above)
182  */
183 static errr term_wipe_hack(TERM_LEN x, TERM_LEN y, int n)
184 {
185     /* Unused */
186     (void)x;
187     (void)y;
188     (void)n;
189
190     return -1;
191 }
192
193 /*
194  * Fake hook for "term_text()" (see above)
195  */
196 static errr term_text_hack(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, concptr cp)
197 {
198     /* Unused */
199     (void)x;
200     (void)y;
201     (void)n;
202     (void)a;
203     (void)cp;
204
205     return -1;
206 }
207
208 /*
209  * Fake hook for "term_pict()" (see above)
210  */
211 static errr term_pict_hack(TERM_LEN x, TERM_LEN y, int n, const TERM_COLOR *ap, concptr cp, const TERM_COLOR *tap, concptr tcp)
212 {
213     /* Unused */
214     (void)x;
215     (void)y;
216     (void)n;
217     (void)ap;
218     (void)cp;
219     (void)tap;
220     (void)tcp;
221
222     return -1;
223 }
224
225 /*** Efficient routines ***/
226
227 /*
228  * Mentally draw an attr/char at a given location
229  * Assumes given location and values are valid.
230  */
231 void term_queue_char(TERM_LEN x, TERM_LEN y, TERM_COLOR a, char c, TERM_COLOR ta, char tc)
232 {
233     term_win *scrn = Term->scr;
234
235     TERM_COLOR *scr_aa = &scrn->a[y][x];
236     char *scr_cc = &scrn->c[y][x];
237
238     TERM_COLOR *scr_taa = &scrn->ta[y][x];
239     char *scr_tcc = &scrn->tc[y][x];
240
241     /* Ignore non-changes */
242     if ((*scr_aa == a) && (*scr_cc == c) && (*scr_taa == ta) && (*scr_tcc == tc))
243         return;
244
245     /* Save the "literal" information */
246     *scr_aa = a;
247     *scr_cc = c;
248
249     *scr_taa = ta;
250     *scr_tcc = tc;
251
252     /* Check for new min/max row info */
253     if (y < Term->y1)
254         Term->y1 = (byte)y;
255     if (y > Term->y2)
256         Term->y2 = (byte)y;
257
258     /* Check for new min/max col info for this row */
259     if (x < Term->x1[y])
260         Term->x1[y] = (byte)x;
261     if (x > Term->x2[y])
262         Term->x2[y] = (byte)x;
263
264 #ifdef JP
265     if (((scrn->a[y][x] & AF_BIGTILE2) == AF_BIGTILE2) || (scrn->a[y][x] & AF_KANJI2))
266 #else
267     if ((scrn->a[y][x] & AF_BIGTILE2) == AF_BIGTILE2)
268 #endif
269         if ((x - 1) < Term->x1[y])
270             Term->x1[y]--;
271 }
272
273 /*
274  * Bigtile version of term_queue_char().
275  * If use_bigtile is FALSE, simply call term_queue_char().
276  * Otherwise, mentally draw a pair of attr/char at a given location.
277  * Assumes given location and values are valid.
278  */
279 void term_queue_bigchar(TERM_LEN x, TERM_LEN y, TERM_COLOR a, char c, TERM_COLOR ta, char tc)
280 {
281 #ifdef JP
282     /*
283      * A table which relates each ascii character to a multibyte
284      * character.
285      *
286      * 「■」は二倍幅豆腐の内部コードに使用。
287      */
288     static char ascii_to_zenkaku[] = " !”#$%&’()*+,-./"
289                                      "0123456789:;<=>?"
290                                      "@ABCDEFGHIJKLMNO"
291                                      "PQRSTUVWXYZ[\]^_"
292                                      "‘abcdefghijklmno"
293                                      "pqrstuvwxyz{|}~■";
294 #endif
295
296     byte a2;
297     char c2;
298
299     /* If non bigtile mode, call orginal function */
300     if (!use_bigtile) {
301         term_queue_char(x, y, a, c, ta, tc);
302         return;
303     }
304
305     /* A tile becomes a Bigtile */
306     if ((a & AF_TILE1) && (c & 0x80)) {
307         /* Mark it as a Bigtile */
308         a2 = AF_BIGTILE2;
309
310         c2 = -1;
311
312         /* Ignore non-tile background */
313         if (!((ta & AF_TILE1) && (tc & 0x80))) {
314             ta = 0;
315             tc = 0;
316         }
317     }
318
319 #ifdef JP
320     /*
321      * Use a multibyte character instead of a dirty pair of ASCII
322      * characters.
323      */
324     else if (' ' <= c) /* isprint(c) */
325     {
326         c2 = ascii_to_zenkaku[2 * (c - ' ') + 1];
327         c = ascii_to_zenkaku[2 * (c - ' ')];
328
329         /* Mark it as a Kanji */
330         a2 = a | AF_KANJI2;
331         a |= AF_KANJI1;
332     }
333 #endif
334
335     else {
336         /* Dirty pair of ASCII characters */
337         a2 = TERM_WHITE;
338         c2 = ' ';
339     }
340
341     /* Display pair of attr/char */
342     term_queue_char(x, y, a, c, ta, tc);
343     term_queue_char(x + 1, y, a2, c2, 0, 0);
344 }
345
346 /*
347  * Mentally draw a string of attr/chars at a given location
348  * Assumes given location and values are valid.
349  * This function is designed to be fast, with no consistancy checking.
350  * It is used to update the map in the game.
351  */
352 void term_queue_line(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR *a, char *c, TERM_COLOR *ta, char *tc)
353 {
354     term_win *scrn = Term->scr;
355
356     TERM_LEN x1 = -1;
357     TERM_LEN x2 = -1;
358
359     TERM_COLOR *scr_aa = &scrn->a[y][x];
360     char *scr_cc = &scrn->c[y][x];
361
362     TERM_COLOR *scr_taa = &scrn->ta[y][x];
363     char *scr_tcc = &scrn->tc[y][x];
364
365     while (n--) {
366         /* Ignore non-changes */
367         if ((*scr_aa == *a) && (*scr_cc == *c) && (*scr_taa == *ta) && (*scr_tcc == *tc)) {
368             x++;
369             a++;
370             c++;
371             ta++;
372             tc++;
373             scr_aa++;
374             scr_cc++;
375             scr_taa++;
376             scr_tcc++;
377             continue;
378         }
379
380         /* Save the "literal" information */
381         *scr_taa++ = *ta++;
382         *scr_tcc++ = *tc++;
383
384         /* Save the "literal" information */
385         *scr_aa++ = *a++;
386         *scr_cc++ = *c++;
387
388         /* Track minimum changed column */
389         if (x1 < 0)
390             x1 = x;
391
392         /* Track maximum changed column */
393         x2 = x;
394
395         x++;
396     }
397
398     /* Expand the "change area" as needed */
399     if (x1 >= 0) {
400         /* Check for new min/max row info */
401         if (y < Term->y1)
402             Term->y1 = (byte)y;
403         if (y > Term->y2)
404             Term->y2 = (byte)y;
405
406         /* Check for new min/max col info in this row */
407         if (x1 < Term->x1[y])
408             Term->x1[y] = (byte)x1;
409         if (x2 > Term->x2[y])
410             Term->x2[y] = (byte)x2;
411     }
412 }
413
414 /*
415  * Mentally draw some attr/chars at a given location
416  *
417  * Assumes that (x,y) is a valid location, that the first "n" characters
418  * of the string "s" are all valid (non-zero), and that (x+n-1,y) is also
419  * a valid location, so the first "n" characters of "s" can all be added
420  * starting at (x,y) without causing any illegal operations.
421  */
422 static void term_queue_chars(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, concptr s)
423 {
424     TERM_LEN x1 = -1, x2 = -1;
425
426     TERM_COLOR *scr_aa = Term->scr->a[y];
427 #ifdef JP
428     char *scr_cc = Term->scr->c[y];
429
430     TERM_COLOR *scr_taa = Term->scr->ta[y];
431     char *scr_tcc = Term->scr->tc[y];
432 #else
433     char *scr_cc = Term->scr->c[y];
434
435     TERM_COLOR *scr_taa = Term->scr->ta[y];
436     char *scr_tcc = Term->scr->tc[y];
437 #endif
438
439 #ifdef JP
440     /* 表示文字なし */
441     if (n == 0 || *s == 0)
442         return;
443     /*
444      * 全角文字の右半分から文字を表示する場合、
445      * 重なった文字の左部分を消去。
446      * 表示開始位置が左端でないと仮定。
447      */
448     if ((scr_aa[x] & AF_KANJI2) && (scr_aa[x] & AF_BIGTILE2) != AF_BIGTILE2) {
449         scr_cc[x - 1] = ' ';
450         scr_aa[x - 1] &= AF_KANJIC;
451         x1 = x2 = x - 1;
452     }
453 #endif
454     /* Queue the attr/chars */
455     for (; n; x++, s++, n--) {
456 #ifdef JP
457         /* 特殊文字としてMSBが立っている可能性がある */
458         /* その場合attrのMSBも立っているのでこれで識別する */
459         /* check */
460         if (!(a & AF_TILE1) && iskanji(*s)) {
461             char nc1 = *s++;
462             char nc2 = *s;
463
464             byte na1 = (a | AF_KANJI1);
465             byte na2 = (a | AF_KANJI2);
466
467             if ((--n == 0) || !nc2)
468                 break;
469
470             if (scr_aa[x++] == na1 && scr_aa[x] == na2 && scr_cc[x - 1] == nc1 && scr_cc[x] == nc2 && (scr_taa[x - 1] == 0) && (scr_taa[x] == 0)
471                 && (scr_tcc[x - 1] == 0) && (scr_tcc[x] == 0))
472                 continue;
473
474             scr_aa[x - 1] = na1;
475             scr_aa[x] = na2;
476             scr_cc[x - 1] = nc1;
477             scr_cc[x] = nc2;
478
479             if (x1 < 0)
480                 x1 = x - 1;
481             x2 = x;
482         } else {
483 #endif
484             TERM_COLOR oa = scr_aa[x];
485             char oc = scr_cc[x];
486
487             TERM_COLOR ota = scr_taa[x];
488             char otc = scr_tcc[x];
489
490             /* Ignore non-changes */
491             if ((oa == a) && (oc == *s) && (ota == 0) && (otc == 0))
492                 continue;
493
494             /* Save the "literal" information */
495             scr_aa[x] = a;
496             scr_cc[x] = *s;
497
498             scr_taa[x] = 0;
499             scr_tcc[x] = 0;
500
501             /* Note the "range" of window updates */
502             if (x1 < 0)
503                 x1 = x;
504             x2 = x;
505 #ifdef JP
506         }
507 #endif
508     }
509
510 #ifdef JP
511     /*
512      * 全角文字の左半分で表示を終了する場合、
513      * 重なった文字の右部分を消去。
514      * (条件追加:タイルの1文字目でない事を確かめるように。)
515      */
516     {
517         int w, h;
518         term_get_size(&w, &h);
519         if (x != w && !(scr_aa[x] & AF_TILE1) && (scr_aa[x] & AF_KANJI2)) {
520             scr_cc[x] = ' ';
521             scr_aa[x] &= AF_KANJIC;
522             if (x1 < 0)
523                 x1 = x;
524             x2 = x;
525         }
526     }
527 #endif
528     /* Expand the "change area" as needed */
529     if (x1 >= 0) {
530         /* Check for new min/max row info */
531         if (y < Term->y1)
532             Term->y1 = (byte)y;
533         if (y > Term->y2)
534             Term->y2 = (byte)y;
535
536         /* Check for new min/max col info in this row */
537         if (x1 < Term->x1[y])
538             Term->x1[y] = (byte)x1;
539         if (x2 > Term->x2[y])
540             Term->x2[y] = (byte)x2;
541     }
542 }
543
544 /*** Refresh routines ***/
545
546 /*
547  * Flush a row of the current window (see "term_fresh")
548  * Display text using "term_pict()"
549  */
550 static void term_fresh_row_pict(TERM_LEN y, TERM_LEN x1, TERM_LEN x2)
551 {
552     TERM_COLOR *old_aa = Term->old->a[y];
553     char *old_cc = Term->old->c[y];
554
555     TERM_COLOR *scr_aa = Term->scr->a[y];
556     char *scr_cc = Term->scr->c[y];
557
558     TERM_COLOR *old_taa = Term->old->ta[y];
559     char *old_tcc = Term->old->tc[y];
560
561     TERM_COLOR *scr_taa = Term->scr->ta[y];
562     char *scr_tcc = Term->scr->tc[y];
563
564     TERM_COLOR ota;
565     char otc;
566
567     TERM_COLOR nta;
568     char ntc;
569
570     /* Pending length */
571     TERM_LEN fn = 0;
572
573     /* Pending start */
574     TERM_LEN fx = 0;
575
576     TERM_COLOR oa;
577     char oc;
578
579     TERM_COLOR na;
580     char nc;
581
582 #ifdef JP
583     /* 全角文字の2バイト目かどうか */
584     int kanji = 0;
585 #endif
586     /* Scan "modified" columns */
587     for (TERM_LEN x = x1; x <= x2; x++) {
588         /* See what is currently here */
589         oa = old_aa[x];
590         oc = old_cc[x];
591
592         /* See what is desired there */
593         na = scr_aa[x];
594         nc = scr_cc[x];
595
596 #ifdef JP
597         if (kanji) {
598             /* 全角文字2バイト目 */
599             kanji = 0;
600             old_aa[x] = na;
601             old_cc[x] = nc;
602             fn++;
603             continue;
604         }
605         /* 特殊文字としてMSBが立っている可能性がある */
606         /* その場合attrのMSBも立っているのでこれで識別する */
607         /* check */
608         kanji = (iskanji(nc) && !(na & AF_TILE1));
609 #endif
610
611         ota = old_taa[x];
612         otc = old_tcc[x];
613
614         nta = scr_taa[x];
615         ntc = scr_tcc[x];
616
617         /* Handle unchanged grids */
618 #ifdef JP
619         if ((na == oa) && (nc == oc) && (nta == ota) && (ntc == otc)
620             && (!kanji
621                 || (scr_aa[x + 1] == old_aa[x + 1] && scr_cc[x + 1] == old_cc[x + 1] && scr_taa[x + 1] == old_taa[x + 1] && scr_tcc[x + 1] == old_tcc[x + 1])))
622 #else
623         if ((na == oa) && (nc == oc) && (nta == ota) && (ntc == otc))
624 #endif
625         {
626             /* Flush */
627             if (fn) {
628                 /* Draw pending attr/char pairs */
629                 (void)((*Term->pict_hook)(fx, y, fn, &scr_aa[fx], &scr_cc[fx], &scr_taa[fx], &scr_tcc[fx]));
630
631                 /* Forget */
632                 fn = 0;
633             }
634
635 #ifdef JP
636             /* 全角文字の時は再開位置は+1 */
637             if (kanji) {
638                 x++;
639                 fx++;
640                 kanji = 0;
641             }
642 #endif
643             /* Skip */
644             continue;
645         }
646         /* Save new contents */
647         old_aa[x] = na;
648         old_cc[x] = nc;
649
650         old_taa[x] = nta;
651         old_tcc[x] = ntc;
652
653         /* Restart and Advance */
654         if (fn++ == 0)
655             fx = x;
656     }
657
658     /* Flush */
659     if (fn) {
660         /* Draw pending attr/char pairs */
661         (void)((*Term->pict_hook)(fx, y, fn, &scr_aa[fx], &scr_cc[fx], &scr_taa[fx], &scr_tcc[fx]));
662     }
663 }
664
665 /*
666  * Flush a row of the current window (see "term_fresh")
667  *
668  * Display text using "term_text()" and "term_wipe()",
669  * but use "term_pict()" for high-bit attr/char pairs
670  */
671 static void term_fresh_row_both(TERM_LEN y, int x1, int x2)
672 {
673     TERM_COLOR *old_aa = Term->old->a[y];
674     char *old_cc = Term->old->c[y];
675
676     TERM_COLOR *scr_aa = Term->scr->a[y];
677     char *scr_cc = Term->scr->c[y];
678
679     TERM_COLOR *old_taa = Term->old->ta[y];
680     char *old_tcc = Term->old->tc[y];
681     TERM_COLOR *scr_taa = Term->scr->ta[y];
682     char *scr_tcc = Term->scr->tc[y];
683
684     TERM_COLOR ota;
685     char otc;
686     TERM_COLOR nta;
687     char ntc;
688
689     /* The "always_text" flag */
690     int always_text = Term->always_text;
691
692     /* Pending length */
693     int fn = 0;
694
695     /* Pending start */
696     int fx = 0;
697
698     /* Pending attr */
699     byte fa = Term->attr_blank;
700
701     TERM_COLOR oa;
702     char oc;
703
704     TERM_COLOR na;
705     char nc;
706
707 #ifdef JP
708     /* 全角文字の2バイト目かどうか */
709     int kanji = 0;
710 #endif
711     /* Scan "modified" columns */
712     for (TERM_LEN x = x1; x <= x2; x++) {
713         /* See what is currently here */
714         oa = old_aa[x];
715         oc = old_cc[x];
716
717         /* See what is desired there */
718         na = scr_aa[x];
719         nc = scr_cc[x];
720
721 #ifdef JP
722         if (kanji) {
723             /* 全角文字2バイト目 */
724             kanji = 0;
725             old_aa[x] = na;
726             old_cc[x] = nc;
727             fn++;
728             continue;
729         }
730         /* 特殊文字としてMSBが立っている可能性がある */
731         /* その場合attrのMSBも立っているのでこれで識別する */
732         /* check */
733         /*              kanji = (iskanji(nc));  */
734         kanji = (iskanji(nc) && !(na & AF_TILE1));
735 #endif
736
737         ota = old_taa[x];
738         otc = old_tcc[x];
739
740         nta = scr_taa[x];
741         ntc = scr_tcc[x];
742
743         /* Handle unchanged grids */
744 #ifdef JP
745         if ((na == oa) && (nc == oc) && (nta == ota) && (ntc == otc)
746             && (!kanji
747                 || (scr_aa[x + 1] == old_aa[x + 1] && scr_cc[x + 1] == old_cc[x + 1] && scr_taa[x + 1] == old_taa[x + 1] && scr_tcc[x + 1] == old_tcc[x + 1])))
748 #else
749         if ((na == oa) && (nc == oc) && (nta == ota) && (ntc == otc))
750 #endif
751         {
752             /* Flush */
753             if (fn) {
754                 /* Draw pending chars (normal) */
755                 if (fa || always_text) {
756                     (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
757                 }
758
759                 /* Draw pending chars (black) */
760                 else {
761                     (void)((*Term->wipe_hook)(fx, y, fn));
762                 }
763
764                 /* Forget */
765                 fn = 0;
766             }
767
768 #ifdef JP
769             /* 全角文字の時は再開位置は+1 */
770             if (kanji) {
771                 x++;
772                 fx++;
773                 kanji = 0;
774             }
775 #endif
776             /* Skip */
777             continue;
778         }
779
780         /* Save new contents */
781         old_aa[x] = na;
782         old_cc[x] = nc;
783
784         old_taa[x] = nta;
785         old_tcc[x] = ntc;
786
787         /* 2nd byte of bigtile */
788         if ((na & AF_BIGTILE2) == AF_BIGTILE2)
789             continue;
790
791         /* Handle high-bit attr/chars */
792         if ((na & AF_TILE1) && (nc & 0x80)) {
793             /* Flush */
794             if (fn) {
795                 /* Draw pending chars (normal) */
796                 if (fa || always_text) {
797                     (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
798                 }
799
800                 /* Draw pending chars (black) */
801                 else {
802                     (void)((*Term->wipe_hook)(fx, y, fn));
803                 }
804
805                 /* Forget */
806                 fn = 0;
807             }
808
809             /* Draw the special attr/char pair */
810             (void)((*Term->pict_hook)(x, y, 1, &na, &nc, &nta, &ntc));
811
812             /* Skip */
813             continue;
814         }
815
816         /* Notice new color */
817 #ifdef JP
818         if (fa != (na & AF_KANJIC))
819 #else
820         if (fa != na)
821 #endif
822
823         {
824             /* Flush */
825             if (fn) {
826                 /* Draw the pending chars */
827                 if (fa || always_text) {
828                     (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
829                 }
830
831                 /* Erase "leading" spaces */
832                 else {
833                     (void)((*Term->wipe_hook)(fx, y, fn));
834                 }
835
836                 /* Forget */
837                 fn = 0;
838             }
839
840             /* Save the new color */
841 #ifdef JP
842             fa = (na & AF_KANJIC);
843 #else
844             fa = na;
845 #endif
846         }
847
848         /* Restart and Advance */
849         if (fn++ == 0)
850             fx = x;
851     }
852
853     /* Flush */
854     if (fn) {
855         /* Draw pending chars (normal) */
856         if (fa || always_text) {
857             (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
858         }
859
860         /* Draw pending chars (black) */
861         else {
862             (void)((*Term->wipe_hook)(fx, y, fn));
863         }
864     }
865 }
866
867 /*
868  * Flush a row of the current window (see "term_fresh")
869  *
870  * Display text using "term_text()" and "term_wipe()"
871  */
872 static void term_fresh_row_text(TERM_LEN y, TERM_LEN x1, TERM_LEN x2)
873 {
874     TERM_COLOR *old_aa = Term->old->a[y];
875     char *old_cc = Term->old->c[y];
876
877     TERM_COLOR *scr_aa = Term->scr->a[y];
878     char *scr_cc = Term->scr->c[y];
879
880     /* The "always_text" flag */
881     int always_text = Term->always_text;
882
883     /* Pending length */
884     int fn = 0;
885
886     /* Pending start */
887     int fx = 0;
888
889     /* Pending attr */
890     byte fa = Term->attr_blank;
891
892     TERM_COLOR oa;
893     char oc;
894
895     TERM_COLOR na;
896     char nc;
897
898 #ifdef JP
899     /* 全角文字の2バイト目かどうか */
900     int kanji = 0;
901
902     for (TERM_LEN x = 0; x < x1; x++)
903         if (!(old_aa[x] & AF_TILE1) && iskanji(old_cc[x])) {
904             if (x == x1 - 1) {
905                 x1--;
906                 break;
907             } else
908                 x++;
909         }
910 #endif
911     /* Scan "modified" columns */
912     for (TERM_LEN x = x1; x <= x2; x++) {
913         /* See what is currently here */
914         oa = old_aa[x];
915         oc = old_cc[x];
916
917         /* See what is desired there */
918         na = scr_aa[x];
919         nc = scr_cc[x];
920
921 #ifdef JP
922         if (kanji) {
923             /* 全角文字2バイト目 */
924             kanji = 0;
925             old_aa[x] = na;
926             old_cc[x] = nc;
927             fn++;
928             continue;
929         }
930         /* 特殊文字としてMSBが立っている可能性がある */
931         /* その場合attrのMSBも立っているのでこれで識別する */
932         /* check */
933         kanji = (iskanji(nc) && !(na & AF_TILE1));
934 #endif
935         /* Handle unchanged grids */
936 #ifdef JP
937         if ((na == oa) && (nc == oc) && (!kanji || (scr_aa[x + 1] == old_aa[x + 1] && scr_cc[x + 1] == old_cc[x + 1])))
938 #else
939         if ((na == oa) && (nc == oc))
940 #endif
941
942         {
943             /* Flush */
944             if (fn) {
945                 /* Draw pending chars (normal) */
946                 if (fa || always_text) {
947                     (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
948                 }
949
950                 /* Draw pending chars (black) */
951                 else {
952                     (void)((*Term->wipe_hook)(fx, y, fn));
953                 }
954
955                 /* Forget */
956                 fn = 0;
957             }
958
959 #ifdef JP
960             /* 全角文字の時は再開位置は+1 */
961             if (kanji) {
962                 x++;
963                 fx++;
964                 kanji = 0;
965             }
966 #endif
967             /* Skip */
968             continue;
969         }
970
971         /* Save new contents */
972         old_aa[x] = na;
973         old_cc[x] = nc;
974
975         /* Notice new color */
976 #ifdef JP
977         if (fa != (na & AF_KANJIC))
978 #else
979         if (fa != na)
980 #endif
981
982         {
983             /* Flush */
984             if (fn) {
985                 /* Draw the pending chars */
986                 if (fa || always_text) {
987                     (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
988                 }
989
990                 /* Erase "leading" spaces */
991                 else {
992                     (void)((*Term->wipe_hook)(fx, y, fn));
993                 }
994
995                 /* Forget */
996                 fn = 0;
997             }
998
999             /* Save the new color */
1000 #ifdef JP
1001             fa = (na & AF_KANJIC);
1002 #else
1003             fa = na;
1004 #endif
1005         }
1006
1007         /* Restart and Advance */
1008         if (fn++ == 0)
1009             fx = x;
1010     }
1011
1012     /* Flush */
1013     if (fn) {
1014         /* Draw pending chars (normal) */
1015         if (fa || always_text) {
1016             (void)((*Term->text_hook)(fx, y, fn, fa, &scr_cc[fx]));
1017         }
1018
1019         /* Draw pending chars (black) */
1020         else {
1021             (void)((*Term->wipe_hook)(fx, y, fn));
1022         }
1023     }
1024 }
1025
1026 bool macro_running(void)
1027 {
1028     int diff = angband_term[0]->key_head - angband_term[0]->key_tail;
1029     return diff < -1 || 1 < diff;
1030 }
1031
1032 bool need_term_fresh(player_type *player_ptr) { return (!macro_running() && !continuous_action_running(player_ptr)) || fresh_after; }
1033
1034 /*
1035  * @brief Actually perform all requested changes to the window
1036  */
1037 errr term_fresh(void)
1038 {
1039     int w = Term->wid;
1040     int h = Term->hgt;
1041
1042     int y1 = Term->y1;
1043     int y2 = Term->y2;
1044
1045     term_win *old = Term->old;
1046     term_win *scr = Term->scr;
1047
1048     /* Before initialize (Advice from Mr.shimitei)*/
1049     if (!old || !scr)
1050         return 1;
1051
1052     /* Do nothing unless "mapped" */
1053     if (!Term->mapped_flag)
1054         return 1;
1055
1056     /* Trivial Refresh */
1057     if ((y1 > y2) && (scr->cu == old->cu) && (scr->cv == old->cv) && (scr->cx == old->cx) && (scr->cy == old->cy) && !(Term->total_erase)) {
1058         /* Nothing */
1059         return 1;
1060     }
1061
1062     /* Handle "total erase" */
1063     if (Term->total_erase) {
1064         byte na = Term->attr_blank;
1065         char nc = Term->char_blank;
1066
1067         /* Physically erase the entire window */
1068         term_xtra(TERM_XTRA_CLEAR, 0);
1069
1070         /* clear all "cursor" data */
1071         old->cv = old->cu = old->cx = old->cy = 0;
1072
1073         /* Wipe each row */
1074         for (TERM_LEN y = 0; y < h; y++) {
1075             TERM_COLOR *aa = old->a[y];
1076             char *cc = old->c[y];
1077
1078             TERM_COLOR *taa = old->ta[y];
1079             char *tcc = old->tc[y];
1080
1081             /* Wipe each column */
1082             for (TERM_LEN x = 0; x < w; x++) {
1083                 /* Wipe each grid */
1084                 *aa++ = na;
1085                 *cc++ = nc;
1086
1087                 *taa++ = na;
1088                 *tcc++ = nc;
1089             }
1090         }
1091
1092         /* Redraw every row */
1093         Term->y1 = y1 = 0;
1094         Term->y2 = y2 = h - 1;
1095
1096         /* Redraw every column */
1097         for (TERM_LEN y = 0; y < h; y++) {
1098             Term->x1[y] = 0;
1099             Term->x2[y] = w - 1;
1100         }
1101
1102         /* Forget "total erase" */
1103         Term->total_erase = FALSE;
1104     }
1105
1106     /* Cursor update -- Erase old Cursor */
1107     if (Term->soft_cursor) {
1108         /* Cursor was visible */
1109         if (!old->cu && old->cv) {
1110             int csize = 1;
1111             TERM_LEN tx = old->cx;
1112             TERM_LEN ty = old->cy;
1113
1114             TERM_COLOR *old_aa = old->a[ty];
1115             char *old_cc = old->c[ty];
1116
1117             TERM_COLOR *old_taa = old->ta[ty];
1118             char *old_tcc = old->tc[ty];
1119
1120             TERM_COLOR ota = old_taa[tx];
1121             char otc = old_tcc[tx];
1122
1123 #ifdef JP
1124             if (tx + 1 < Term->wid && !(old_aa[tx] & AF_TILE1) && iskanji(old_cc[tx]))
1125                 csize = 2;
1126 #endif
1127             /* Use "term_pict()" always */
1128             if (Term->always_pict)
1129                 (void)((*Term->pict_hook)(tx, ty, csize, &old_aa[tx], &old_cc[tx], &ota, &otc));
1130
1131             /* Use "term_pict()" sometimes */
1132             else if (Term->higher_pict && (old_aa[tx] & AF_TILE1) && (old_cc[tx] & 0x80))
1133                 (void)((*Term->pict_hook)(tx, ty, 1, &old_aa[tx], &old_cc[tx], &ota, &otc));
1134
1135             /*
1136              * Restore the actual character
1137              * 元の文字の描画範囲がカーソルより小さいと、
1138              * 上書きされなかった部分がゴミとして残る。
1139              * wipe_hook でカーソルを消去して text_hook で書き直す。
1140              */
1141             else if (old_aa[tx] || Term->always_text) {
1142                 (void)((*Term->wipe_hook)(tx, ty, 1));
1143                 (void)((*Term->text_hook)(tx, ty, csize, (unsigned char)(old_aa[tx] & 0xf), &old_cc[tx]));
1144             }
1145
1146             /* Erase the grid */
1147             else
1148                 (void)((*Term->wipe_hook)(tx, ty, 1));
1149         }
1150     }
1151
1152     /* Cursor Update -- Erase old Cursor */
1153     else {
1154         /* Cursor will be invisible */
1155         if (scr->cu || !scr->cv) {
1156             /* Make the cursor invisible */
1157             term_xtra(TERM_XTRA_SHAPE, 0);
1158         }
1159     }
1160
1161     /* Something to update */
1162     if (y1 <= y2) {
1163         /* Handle "icky corner" */
1164         if (Term->icky_corner) {
1165             /* Avoid the corner */
1166             if (y2 >= h - 1) {
1167                 /* Avoid the corner */
1168                 if (Term->x2[h - 1] > w - 2) {
1169                     /* Avoid the corner */
1170                     Term->x2[h - 1] = w - 2;
1171                 }
1172             }
1173         }
1174
1175         /* Scan the "modified" rows */
1176         for (TERM_LEN y = y1; y <= y2; ++y) {
1177             TERM_LEN x1 = Term->x1[y];
1178             TERM_LEN x2 = Term->x2[y];
1179
1180             /* Flush each "modified" row */
1181             if (x1 <= x2) {
1182                 /* Always use "term_pict()" */
1183                 if (Term->always_pict) {
1184                     /* Flush the row */
1185                     term_fresh_row_pict(y, x1, x2);
1186                 }
1187
1188                 /* Sometimes use "term_pict()" */
1189                 else if (Term->higher_pict) {
1190                     /* Flush the row */
1191                     term_fresh_row_both(y, x1, x2);
1192                 }
1193
1194                 /* Never use "term_pict()" */
1195                 else {
1196                     /* Flush the row */
1197                     term_fresh_row_text(y, x1, x2);
1198                 }
1199
1200                 /* This row is all done */
1201                 Term->x1[y] = (byte)w;
1202                 Term->x2[y] = 0;
1203
1204                 /* Flush that row (if allowed) */
1205                 if (!Term->never_frosh)
1206                     term_xtra(TERM_XTRA_FROSH, y);
1207             }
1208         }
1209
1210         /* No rows are invalid */
1211         Term->y1 = (byte)h;
1212         Term->y2 = 0;
1213     }
1214
1215     /* Cursor update -- Show new Cursor */
1216     if (Term->soft_cursor) {
1217         /* Draw the cursor */
1218         if (!scr->cu && scr->cv) {
1219 #ifdef JP
1220             if ((scr->cx + 1 < w)
1221                 && ((old->a[scr->cy][scr->cx + 1] & AF_BIGTILE2) == AF_BIGTILE2
1222                     || (!(old->a[scr->cy][scr->cx] & AF_TILE1) && iskanji(old->c[scr->cy][scr->cx]))))
1223 #else
1224             if ((scr->cx + 1 < w) && (old->a[scr->cy][scr->cx + 1] & AF_BIGTILE2) == AF_BIGTILE2)
1225 #endif
1226             {
1227                 /* Double width cursor for the Bigtile mode */
1228                 (void)((*Term->bigcurs_hook)(scr->cx, scr->cy));
1229             } else {
1230                 /* Call the cursor display routine */
1231                 (void)((*Term->curs_hook)(scr->cx, scr->cy));
1232             }
1233         }
1234     }
1235
1236     /* Cursor Update -- Show new Cursor */
1237     else {
1238         /* The cursor is useless, hide it */
1239         if (scr->cu) {
1240             /* Paranoia -- Put the cursor NEAR where it belongs */
1241             (void)((*Term->curs_hook)(w - 1, scr->cy));
1242
1243             /* Make the cursor invisible */
1244             /* term_xtra(TERM_XTRA_SHAPE, 0); */
1245         }
1246
1247         /* The cursor is invisible, hide it */
1248         else if (!scr->cv) {
1249             /* Paranoia -- Put the cursor where it belongs */
1250             (void)((*Term->curs_hook)(scr->cx, scr->cy));
1251
1252             /* Make the cursor invisible */
1253             /* term_xtra(TERM_XTRA_SHAPE, 0); */
1254         }
1255
1256         /* The cursor is visible, display it correctly */
1257         else {
1258             /* Put the cursor where it belongs */
1259             (void)((*Term->curs_hook)(scr->cx, scr->cy));
1260
1261             /* Make the cursor visible */
1262             term_xtra(TERM_XTRA_SHAPE, 1);
1263         }
1264     }
1265
1266     /* Save the "cursor state" */
1267     old->cu = scr->cu;
1268     old->cv = scr->cv;
1269     old->cx = scr->cx;
1270     old->cy = scr->cy;
1271
1272     /* Actually flush the output */
1273     term_xtra(TERM_XTRA_FRESH, 0);
1274     return 0;
1275 }
1276
1277 /*** Output routines ***/
1278
1279 /*
1280  * Set the cursor visibility
1281  */
1282 errr term_set_cursor(int v)
1283 {
1284     /* Already done */
1285     if (Term->scr->cv == v)
1286         return 1;
1287
1288     /* Change */
1289     Term->scr->cv = (bool)v;
1290     return 0;
1291 }
1292
1293 /*
1294  * Place the cursor at a given location
1295  *
1296  * Note -- "illegal" requests do not move the cursor.
1297  */
1298 errr term_gotoxy(TERM_LEN x, TERM_LEN y)
1299 {
1300     int w = Term->wid;
1301     int h = Term->hgt;
1302
1303     /* Verify */
1304     if ((x < 0) || (x >= w))
1305         return -1;
1306     if ((y < 0) || (y >= h))
1307         return -1;
1308
1309     /* Remember the cursor */
1310     Term->scr->cx = (byte)x;
1311     Term->scr->cy = (byte)y;
1312
1313     /* The cursor is not useless */
1314     Term->scr->cu = 0;
1315     return 0;
1316 }
1317
1318 /*
1319  * At a given location, place an attr/char
1320  * Do not change the cursor position
1321  * No visual changes until "term_fresh()".
1322  */
1323 errr term_draw(TERM_LEN x, TERM_LEN y, TERM_COLOR a, char c)
1324 {
1325     int w = Term->wid;
1326     int h = Term->hgt;
1327
1328     if ((x < 0) || (x >= w))
1329         return -1;
1330     if ((y < 0) || (y >= h))
1331         return -1;
1332
1333     /* Paranoia -- illegal char */
1334     if (!c)
1335         return (-2);
1336
1337     /* Queue it for later */
1338     term_queue_char(x, y, a, c, 0, 0);
1339     return 0;
1340 }
1341
1342 /*
1343  * Using the given attr, add the given char at the cursor.
1344  *
1345  * We return "-2" if the character is "illegal". XXX XXX
1346  *
1347  * We return "-1" if the cursor is currently unusable.
1348  *
1349  * We queue the given attr/char for display at the current
1350  * cursor location, and advance the cursor to the right,
1351  * marking it as unuable and returning "1" if it leaves
1352  * the screen, and otherwise returning "0".
1353  *
1354  * So when this function, or the following one, return a
1355  * positive value, future calls to either function will
1356  * return negative ones.
1357  */
1358 errr term_addch(TERM_COLOR a, char c)
1359 {
1360     TERM_LEN w = Term->wid;
1361
1362     /* Handle "unusable" cursor */
1363     if (Term->scr->cu)
1364         return -1;
1365
1366     /* Paranoia -- no illegal chars */
1367     if (!c)
1368         return (-2);
1369
1370     /* Queue the given character for display */
1371     term_queue_char(Term->scr->cx, Term->scr->cy, a, c, 0, 0);
1372
1373     /* Advance the cursor */
1374     Term->scr->cx++;
1375
1376     /* Success */
1377     if (Term->scr->cx < w)
1378         return 0;
1379
1380     /* Note "Useless" cursor */
1381     Term->scr->cu = 1;
1382
1383     /* Note "Useless" cursor */
1384     return 1;
1385 }
1386
1387 /*
1388  * Bigtile version of term_addch().
1389  *
1390  * If use_bigtile is FALSE, simply call term_addch() .
1391  *
1392  * Otherwise, queue a pair of attr/char for display at the current
1393  * cursor location, and advance the cursor to the right by two.
1394  */
1395 errr term_add_bigch(TERM_COLOR a, char c)
1396 {
1397     if (!use_bigtile)
1398         return term_addch(a, c);
1399
1400     /* Handle "unusable" cursor */
1401     if (Term->scr->cu)
1402         return -1;
1403
1404     /* Paranoia -- no illegal chars */
1405     if (!c)
1406         return (-2);
1407
1408     /* Queue the given character for display */
1409     term_queue_bigchar(Term->scr->cx, Term->scr->cy, a, c, 0, 0);
1410
1411     /* Advance the cursor */
1412     Term->scr->cx += 2;
1413
1414     /* Success */
1415     if (Term->scr->cx < Term->wid)
1416         return 0;
1417
1418     /* Note "Useless" cursor */
1419     Term->scr->cu = 1;
1420
1421     /* Note "Useless" cursor */
1422     return 1;
1423 }
1424
1425 /*
1426  * At the current location, using an attr, add a string
1427  *
1428  * We also take a length "n", using negative values to imply
1429  * the largest possible value, and then we use the minimum of
1430  * this length and the "actual" length of the string as the
1431  * actual number of characters to attempt to display, never
1432  * displaying more characters than will actually fit, since
1433  * we do NOT attempt to "wrap" the cursor at the screen edge.
1434  *
1435  * We return "-1" if the cursor is currently unusable.
1436  * We return "N" if we were "only" able to write "N" chars,
1437  * even if all of the given characters fit on the screen,
1438  * and mark the cursor as unusable for future attempts.
1439  *
1440  * So when this function, or the preceding one, return a
1441  * positive value, future calls to either function will
1442  * return negative ones.
1443  */
1444 errr term_addstr(int n, TERM_COLOR a, concptr s)
1445 {
1446     int k;
1447     TERM_LEN w = Term->wid;
1448     errr res = 0;
1449
1450     /* Handle "unusable" cursor */
1451     if (Term->scr->cu)
1452         return -1;
1453
1454     /* Obtain maximal length */
1455     k = (n < 0) ? (w + 1) : n;
1456
1457     /* Obtain the usable string length */
1458     for (n = 0; (n < k) && s[n]; n++) /* loop */
1459         ;
1460
1461     /* React to reaching the edge of the screen */
1462     if (Term->scr->cx + n >= w)
1463         res = n = w - Term->scr->cx;
1464
1465     /* Queue the first "n" characters for display */
1466     term_queue_chars(Term->scr->cx, Term->scr->cy, n, a, s);
1467
1468     /* Advance the cursor */
1469     Term->scr->cx += (byte)n;
1470
1471     /* Notice "Useless" cursor */
1472     if (res)
1473         Term->scr->cu = 1;
1474
1475     return res;
1476 }
1477
1478 /*
1479  * Move to a location and, using an attr, add a char
1480  */
1481 errr term_putch(TERM_LEN x, TERM_LEN y, TERM_COLOR a, char c)
1482 {
1483     errr res;
1484
1485     /* Move first */
1486     if ((res = term_gotoxy(x, y)) != 0)
1487         return (res);
1488
1489     /* Then add the char */
1490     if ((res = term_addch(a, c)) != 0)
1491         return (res);
1492
1493     return 0;
1494 }
1495
1496 /*
1497  * Move to a location and, using an attr, add a string
1498  */
1499 errr term_putstr(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, concptr s)
1500 {
1501     errr res;
1502
1503     /* Move first */
1504     if ((res = term_gotoxy(x, y)) != 0)
1505         return (res);
1506
1507     /* Then add the string */
1508     if ((res = term_addstr(n, a, s)) != 0)
1509         return (res);
1510
1511     return 0;
1512 }
1513
1514 /*
1515  * Place cursor at (x,y), and clear the next "n" chars
1516  */
1517 errr term_erase(TERM_LEN x, TERM_LEN y, int n)
1518 {
1519     TERM_LEN w = Term->wid;
1520     /* int h = Term->hgt; */
1521
1522     TERM_LEN x1 = -1;
1523     TERM_LEN x2 = -1;
1524
1525     int na = Term->attr_blank;
1526     int nc = Term->char_blank;
1527
1528     TERM_COLOR *scr_aa;
1529     char *scr_cc;
1530
1531     TERM_COLOR *scr_taa;
1532     char *scr_tcc;
1533
1534     /* Place cursor */
1535     if (term_gotoxy(x, y))
1536         return -1;
1537
1538     /* Force legal size */
1539     if (x + n > w)
1540         n = w - x;
1541
1542     /* Fast access */
1543     scr_aa = Term->scr->a[y];
1544     scr_cc = Term->scr->c[y];
1545
1546     scr_taa = Term->scr->ta[y];
1547     scr_tcc = Term->scr->tc[y];
1548
1549 #ifdef JP
1550     /*
1551      * 全角文字の右半分から文字を表示する場合、
1552      * 重なった文字の左部分を消去。
1553      */
1554     if (n > 0 && (((scr_aa[x] & AF_KANJI2) && !(scr_aa[x] & AF_TILE1)) || (scr_aa[x] & AF_BIGTILE2) == AF_BIGTILE2))
1555 #else
1556     if (n > 0 && (scr_aa[x] & AF_BIGTILE2) == AF_BIGTILE2)
1557 #endif
1558     {
1559         x--;
1560         n++;
1561     }
1562
1563     /* Scan every column */
1564     for (int i = 0; i < n; i++, x++) {
1565         int oa = scr_aa[x];
1566         int oc = scr_cc[x];
1567
1568         /* Ignore "non-changes" */
1569         if ((oa == na) && (oc == nc))
1570             continue;
1571
1572 #ifdef JP
1573         /*
1574          * 全角文字の左半分で表示を終了する場合、
1575          * 重なった文字の右部分を消去。
1576          *
1577          * 2001/04/29 -- Habu
1578          * 行の右端の場合はこの処理をしないように修正。
1579          */
1580         if ((oa & AF_KANJI1) && (i + 1) == n && x != w - 1)
1581             n++;
1582 #endif
1583         /* Save the "literal" information */
1584         scr_aa[x] = (byte)na;
1585         scr_cc[x] = (char)nc;
1586
1587         scr_taa[x] = 0;
1588         scr_tcc[x] = 0;
1589
1590         /* Track minimum changed column */
1591         if (x1 < 0)
1592             x1 = x;
1593
1594         /* Track maximum changed column */
1595         x2 = x;
1596     }
1597
1598     /* Expand the "change area" as needed */
1599     if (x1 >= 0) {
1600         /* Check for new min/max row info */
1601         if (y < Term->y1)
1602             Term->y1 = (byte)y;
1603         if (y > Term->y2)
1604             Term->y2 = (byte)y;
1605
1606         /* Check for new min/max col info in this row */
1607         if (x1 < Term->x1[y])
1608             Term->x1[y] = (byte)x1;
1609         if (x2 > Term->x2[y])
1610             Term->x2[y] = (byte)x2;
1611     }
1612
1613     return 0;
1614 }
1615
1616 /*
1617  * Clear the entire window, and move to the top left corner
1618  *
1619  * Note the use of the special "total_erase" code
1620  */
1621 errr term_clear(void)
1622 {
1623     TERM_LEN w = Term->wid;
1624     TERM_LEN h = Term->hgt;
1625
1626     TERM_COLOR na = Term->attr_blank;
1627     char nc = Term->char_blank;
1628
1629     /* Cursor usable */
1630     Term->scr->cu = 0;
1631
1632     /* Cursor to the top left */
1633     Term->scr->cx = Term->scr->cy = 0;
1634
1635     /* Wipe each row */
1636     for (TERM_LEN y = 0; y < h; y++) {
1637         TERM_COLOR *scr_aa = Term->scr->a[y];
1638         char *scr_cc = Term->scr->c[y];
1639
1640         TERM_COLOR *scr_taa = Term->scr->ta[y];
1641         char *scr_tcc = Term->scr->tc[y];
1642
1643         /* Wipe each column */
1644         for (TERM_LEN x = 0; x < w; x++) {
1645             scr_aa[x] = na;
1646             scr_cc[x] = nc;
1647
1648             scr_taa[x] = 0;
1649             scr_tcc[x] = 0;
1650         }
1651
1652         /* This row has changed */
1653         Term->x1[y] = 0;
1654         Term->x2[y] = w - 1;
1655     }
1656
1657     /* Every row has changed */
1658     Term->y1 = 0;
1659     Term->y2 = h - 1;
1660
1661     /* Force "total erase" */
1662     Term->total_erase = TRUE;
1663     return 0;
1664 }
1665
1666 /*
1667  * Redraw (and refresh) the whole window.
1668  */
1669 errr term_redraw(void)
1670 {
1671     /* Force "total erase" */
1672     Term->total_erase = TRUE;
1673     term_fresh();
1674     return 0;
1675 }
1676
1677 /*
1678  * Redraw part of a window.
1679  */
1680 errr term_redraw_section(TERM_LEN x1, TERM_LEN y1, TERM_LEN x2, TERM_LEN y2)
1681 {
1682     char *g_ptr;
1683
1684     /* Bounds checking */
1685     if (y2 >= Term->hgt)
1686         y2 = Term->hgt - 1;
1687     if (x2 >= Term->wid)
1688         x2 = Term->wid - 1;
1689     if (y1 < 0)
1690         y1 = 0;
1691     if (x1 < 0)
1692         x1 = 0;
1693
1694     /* Set y limits */
1695     Term->y1 = (byte)y1;
1696     Term->y2 = (byte)y2;
1697
1698     /* Set the x limits */
1699     for (int i = Term->y1; i <= Term->y2; i++) {
1700 #ifdef JP
1701         int x1j = x1;
1702         int x2j = x2;
1703
1704         if (x1j > 0) {
1705             if (Term->scr->a[i][x1j] & AF_KANJI2)
1706                 x1j--;
1707         }
1708
1709         if (x2j < Term->wid - 1) {
1710             if (Term->scr->a[i][x2j] & AF_KANJI1)
1711                 x2j++;
1712         }
1713
1714         Term->x1[i] = (byte)x1j;
1715         Term->x2[i] = (byte)x2j;
1716
1717         g_ptr = Term->old->c[i];
1718
1719         /* Clear the section so it is redrawn */
1720         for (int j = x1j; j <= x2j; j++) {
1721             /* Hack - set the old character to "none" */
1722             g_ptr[j] = 0;
1723         }
1724 #else
1725         Term->x1[i] = x1;
1726         Term->x2[i] = x2;
1727
1728         g_ptr = Term->old->c[i];
1729
1730         /* Clear the section so it is redrawn */
1731         for (int j = x1; j <= x2; j++) {
1732             /* Hack - set the old character to "none" */
1733             g_ptr[j] = 0;
1734         }
1735 #endif
1736     }
1737
1738     term_fresh();
1739     return 0;
1740 }
1741
1742 /*** Access routines ***/
1743
1744 /*
1745  * Extract the cursor visibility
1746  */
1747 errr term_get_cursor(int *v)
1748 {
1749     /* Extract visibility */
1750     (*v) = Term->scr->cv;
1751     return 0;
1752 }
1753
1754 /*
1755  * Extract the current window size
1756  */
1757 errr term_get_size(TERM_LEN *w, TERM_LEN *h)
1758 {
1759     /* Access the cursor */
1760     (*w) = Term->wid;
1761     (*h) = Term->hgt;
1762     return 0;
1763 }
1764
1765 /*
1766  * Extract the current cursor location
1767  */
1768 errr term_locate(TERM_LEN *x, TERM_LEN *y)
1769 {
1770     /* Access the cursor */
1771     (*x) = Term->scr->cx;
1772     (*y) = Term->scr->cy;
1773
1774     /* Warn about "useless" cursor */
1775     if (Term->scr->cu)
1776         return 1;
1777
1778     return 0;
1779 }
1780
1781 /*
1782  * At a given location, determine the "current" attr and char
1783  * Note that this refers to what will be on the window after the
1784  * next call to "term_fresh()".  It may or may not already be there.
1785  */
1786 errr term_what(TERM_LEN x, TERM_LEN y, TERM_COLOR *a, char *c)
1787 {
1788     TERM_LEN w = Term->wid;
1789     TERM_LEN h = Term->hgt;
1790
1791     if ((x < 0) || (x >= w))
1792         return -1;
1793     if ((y < 0) || (y >= h))
1794         return -1;
1795
1796     /* Direct access */
1797     (*a) = Term->scr->a[y][x];
1798     (*c) = Term->scr->c[y][x];
1799     return 0;
1800 }
1801
1802 /*** Input routines ***/
1803
1804 /*
1805  * Flush and forget the input
1806  */
1807 errr term_flush(void)
1808 {
1809     /* Flush all events */
1810     term_xtra(TERM_XTRA_FLUSH, 0);
1811
1812     /* Forget all keypresses */
1813     Term->key_head = Term->key_tail = 0;
1814     return 0;
1815 }
1816
1817 /*
1818  * Add a keypress to the FRONT of the "queue"
1819  */
1820 errr term_key_push(int k)
1821 {
1822     /* Refuse to enqueue non-keys */
1823     if (!k)
1824         return -1;
1825
1826     /* Overflow may induce circular queue */
1827     if (Term->key_tail == 0)
1828         Term->key_tail = Term->key_size;
1829
1830     /* Back up, Store the char */
1831     Term->key_queue[--Term->key_tail] = (char)k;
1832
1833     if (Term->key_head != Term->key_tail)
1834         return 0;
1835
1836     return 1;
1837 }
1838
1839 /*
1840  * Check for a pending keypress on the key queue.
1841  *
1842  * Store the keypress, if any, in "ch", and return "0".
1843  * Otherwise store "zero" in "ch", and return "1".
1844  *
1845  * Wait for a keypress if "wait" is true.
1846  *
1847  * Remove the keypress if "take" is true.
1848  */
1849 errr term_inkey(char *ch, bool wait, bool take)
1850 {
1851     /* Assume no key */
1852     (*ch) = '\0';
1853
1854     /* get bored */
1855     if (!Term->never_bored) {
1856         /* Process random events */
1857         term_xtra(TERM_XTRA_BORED, 0);
1858     }
1859
1860     /* Wait */
1861     if (wait) {
1862         /* Process pending events while necessary */
1863         while (Term->key_head == Term->key_tail) {
1864             /* Process events (wait for one) */
1865             term_xtra(TERM_XTRA_EVENT, TRUE);
1866         }
1867     }
1868
1869     /* Do not Wait */
1870     else {
1871         /* Process pending events if necessary */
1872         if (Term->key_head == Term->key_tail) {
1873             /* Process events (do not wait) */
1874             term_xtra(TERM_XTRA_EVENT, FALSE);
1875         }
1876     }
1877
1878     /* No keys are ready */
1879     if (Term->key_head == Term->key_tail)
1880         return 1;
1881
1882     /* Extract the next keypress */
1883     (*ch) = Term->key_queue[Term->key_tail];
1884
1885     /* If requested, advance the queue, wrap around if necessary */
1886     if (take && (++Term->key_tail == Term->key_size))
1887         Term->key_tail = 0;
1888
1889     return 0;
1890 }
1891
1892 /*** Extra routines ***/
1893
1894 /*
1895  * Save the "requested" screen into the "memorized" screen
1896  *
1897  * Every "term_save()" should match exactly one "term_load()"
1898  */
1899 errr term_save(void)
1900 {
1901     TERM_LEN w = Term->wid;
1902     TERM_LEN h = Term->hgt;
1903
1904     /* Create */
1905     if (!Term->mem) {
1906         /* Allocate window */
1907         MAKE(Term->mem, term_win);
1908
1909         /* Initialize window */
1910         term_win_init(Term->mem, w, h);
1911     }
1912
1913     /* Grab */
1914     term_win_copy(Term->mem, Term->scr, w, h);
1915     return 0;
1916 }
1917
1918 /*
1919  * Restore the "requested" contents (see above).
1920  *
1921  * Every "term_save()" should match exactly one "term_load()"
1922  */
1923 errr term_load(void)
1924 {
1925     TERM_LEN w = Term->wid;
1926     TERM_LEN h = Term->hgt;
1927
1928     /* Create */
1929     if (!Term->mem) {
1930         /* Allocate window */
1931         MAKE(Term->mem, term_win);
1932
1933         /* Initialize window */
1934         term_win_init(Term->mem, w, h);
1935     }
1936
1937     /* Load */
1938     term_win_copy(Term->scr, Term->mem, w, h);
1939
1940     /* Assume change */
1941     for (TERM_LEN y = 0; y < h; y++) {
1942         /* Assume change */
1943         Term->x1[y] = 0;
1944         Term->x2[y] = w - 1;
1945     }
1946
1947     /* Assume change */
1948     Term->y1 = 0;
1949     Term->y2 = h - 1;
1950     return 0;
1951 }
1952
1953 /*
1954  * Exchange the "requested" screen with the "tmp" screen
1955  */
1956 errr term_exchange(void)
1957 {
1958     TERM_LEN w = Term->wid;
1959     TERM_LEN h = Term->hgt;
1960
1961     term_win *exchanger;
1962
1963     /* Create */
1964     if (!Term->tmp) {
1965         /* Allocate window */
1966         MAKE(Term->tmp, term_win);
1967
1968         /* Initialize window */
1969         term_win_init(Term->tmp, w, h);
1970     }
1971
1972     /* Swap */
1973     exchanger = Term->scr;
1974     Term->scr = Term->tmp;
1975     Term->tmp = exchanger;
1976
1977     /* Assume change */
1978     for (TERM_LEN y = 0; y < h; y++) {
1979         /* Assume change */
1980         Term->x1[y] = 0;
1981         Term->x2[y] = w - 1;
1982     }
1983
1984     /* Assume change */
1985     Term->y1 = 0;
1986     Term->y2 = h - 1;
1987     return 0;
1988 }
1989
1990 /*
1991  * React to a new physical window size.
1992  */
1993 errr term_resize(TERM_LEN w, TERM_LEN h)
1994 {
1995     TERM_LEN wid, hgt;
1996
1997     TERM_LEN *hold_x1;
1998     TERM_LEN *hold_x2;
1999
2000     term_win *hold_old;
2001     term_win *hold_scr;
2002     term_win *hold_mem;
2003     term_win *hold_tmp;
2004
2005     /* Resizing is forbidden */
2006     if (Term->fixed_shape)
2007         return -1;
2008
2009     /* Ignore illegal changes */
2010     if ((w < 1) || (h < 1))
2011         return -1;
2012
2013     /* Ignore non-changes */
2014     if ((Term->wid == w) && (Term->hgt == h) && (arg_bigtile == use_bigtile))
2015         return 1;
2016
2017     use_bigtile = arg_bigtile;
2018
2019     /* Minimum dimensions */
2020     wid = MIN(Term->wid, w);
2021     hgt = MIN(Term->hgt, h);
2022
2023     /* Save scanners */
2024     hold_x1 = Term->x1;
2025     hold_x2 = Term->x2;
2026
2027     /* Save old window */
2028     hold_old = Term->old;
2029
2030     /* Save old window */
2031     hold_scr = Term->scr;
2032
2033     /* Save old window */
2034     hold_mem = Term->mem;
2035
2036     /* Save old window */
2037     hold_tmp = Term->tmp;
2038
2039     /* Create new scanners */
2040     C_MAKE(Term->x1, h, TERM_LEN);
2041     C_MAKE(Term->x2, h, TERM_LEN);
2042
2043     /* Create new window */
2044     MAKE(Term->old, term_win);
2045
2046     /* Initialize new window */
2047     term_win_init(Term->old, w, h);
2048
2049     /* Save the contents */
2050     term_win_copy(Term->old, hold_old, wid, hgt);
2051
2052     /* Create new window */
2053     MAKE(Term->scr, term_win);
2054
2055     /* Initialize new window */
2056     term_win_init(Term->scr, w, h);
2057
2058     /* Save the contents */
2059     term_win_copy(Term->scr, hold_scr, wid, hgt);
2060
2061     /* If needed */
2062     if (hold_mem) {
2063         /* Create new window */
2064         MAKE(Term->mem, term_win);
2065
2066         /* Initialize new window */
2067         term_win_init(Term->mem, w, h);
2068
2069         /* Save the contents */
2070         term_win_copy(Term->mem, hold_mem, wid, hgt);
2071     }
2072
2073     /* If needed */
2074     if (hold_tmp) {
2075         /* Create new window */
2076         MAKE(Term->tmp, term_win);
2077
2078         /* Initialize new window */
2079         term_win_init(Term->tmp, w, h);
2080
2081         /* Save the contents */
2082         term_win_copy(Term->tmp, hold_tmp, wid, hgt);
2083     }
2084
2085     /* Free some arrays */
2086     C_KILL(hold_x1, Term->hgt, TERM_LEN);
2087     C_KILL(hold_x2, Term->hgt, TERM_LEN);
2088
2089     /* Nuke */
2090     term_win_nuke(hold_old, Term->wid, Term->hgt);
2091
2092     /* Kill */
2093     KILL(hold_old, term_win);
2094
2095     /* Illegal cursor */
2096     if (Term->old->cx >= w)
2097         Term->old->cu = 1;
2098     if (Term->old->cy >= h)
2099         Term->old->cu = 1;
2100
2101     /* Nuke */
2102     term_win_nuke(hold_scr, Term->wid, Term->hgt);
2103
2104     /* Kill */
2105     KILL(hold_scr, term_win);
2106
2107     /* Illegal cursor */
2108     if (Term->scr->cx >= w)
2109         Term->scr->cu = 1;
2110     if (Term->scr->cy >= h)
2111         Term->scr->cu = 1;
2112
2113     /* If needed */
2114     if (hold_mem) {
2115         /* Nuke */
2116         term_win_nuke(hold_mem, Term->wid, Term->hgt);
2117
2118         /* Kill */
2119         KILL(hold_mem, term_win);
2120
2121         /* Illegal cursor */
2122         if (Term->mem->cx >= w)
2123             Term->mem->cu = 1;
2124         if (Term->mem->cy >= h)
2125             Term->mem->cu = 1;
2126     }
2127
2128     /* If needed */
2129     if (hold_tmp) {
2130         /* Nuke */
2131         term_win_nuke(hold_tmp, Term->wid, Term->hgt);
2132
2133         /* Kill */
2134         KILL(hold_tmp, term_win);
2135
2136         /* Illegal cursor */
2137         if (Term->tmp->cx >= w)
2138             Term->tmp->cu = 1;
2139         if (Term->tmp->cy >= h)
2140             Term->tmp->cu = 1;
2141     }
2142
2143     /* Save new size */
2144     Term->wid = w;
2145     Term->hgt = h;
2146
2147     /* Force "total erase" */
2148     Term->total_erase = TRUE;
2149
2150     /* Assume change */
2151     for (int i = 0; i < h; i++) {
2152         /* Assume change */
2153         Term->x1[i] = 0;
2154         Term->x2[i] = w - 1;
2155     }
2156
2157     /* Assume change */
2158     Term->y1 = 0;
2159     Term->y2 = h - 1;
2160
2161     /* Execute the "resize_hook" hook, if available */
2162     if (Term->resize_hook)
2163         Term->resize_hook();
2164
2165     return 0;
2166 }
2167
2168 /*
2169  * Activate a new Term (and deactivate the current Term)
2170  *
2171  * This function is extremely important, and also somewhat bizarre.
2172  * It is the only function that should "modify" the value of "Term".
2173  *
2174  * To "create" a valid "term", one should do "term_init(t)", then
2175  * set the various flags and hooks, and then do "term_activate(t)".
2176  */
2177 errr term_activate(term_type *t)
2178 {
2179     /* already done */
2180     if (Term == t)
2181         return 1;
2182
2183     /* Deactivate the old Term */
2184     if (Term)
2185         term_xtra(TERM_XTRA_LEVEL, 0);
2186
2187     /* Call the special "init" hook */
2188     if (t && !t->active_flag) {
2189         /* Call the "init" hook */
2190         if (t->init_hook)
2191             (*t->init_hook)(t);
2192
2193         /* Remember */
2194         t->active_flag = TRUE;
2195
2196         /* Assume mapped */
2197         t->mapped_flag = TRUE;
2198     }
2199
2200     /* Remember the Term */
2201     Term = t;
2202
2203     /* Activate the new Term */
2204     if (Term)
2205         term_xtra(TERM_XTRA_LEVEL, 1);
2206
2207     return 0;
2208 }
2209
2210 /*
2211  * Initialize a term, using a window of the given size.
2212  * Also prepare the "input queue" for "k" keypresses
2213  * By default, the cursor starts out "invisible"
2214  * By default, we "erase" using "black spaces"
2215  */
2216 errr term_init(term_type *t, TERM_LEN w, TERM_LEN h, int k)
2217 {
2218     /* Wipe it */
2219     (void)WIPE(t, term_type);
2220
2221     /* Prepare the input queue */
2222     t->key_head = t->key_tail = 0;
2223
2224     /* Determine the input queue size */
2225     t->key_size = (u16b)k;
2226
2227     /* Allocate the input queue */
2228     C_MAKE(t->key_queue, t->key_size, char);
2229
2230     /* Save the size */
2231     t->wid = w;
2232     t->hgt = h;
2233
2234     /* Allocate change arrays */
2235     C_MAKE(t->x1, h, TERM_LEN);
2236     C_MAKE(t->x2, h, TERM_LEN);
2237
2238     /* Allocate "displayed" */
2239     MAKE(t->old, term_win);
2240
2241     /* Initialize "displayed" */
2242     term_win_init(t->old, w, h);
2243
2244     /* Allocate "requested" */
2245     MAKE(t->scr, term_win);
2246
2247     /* Initialize "requested" */
2248     term_win_init(t->scr, w, h);
2249
2250     /* Assume change */
2251     for (TERM_LEN y = 0; y < h; y++) {
2252         /* Assume change */
2253         t->x1[y] = 0;
2254         t->x2[y] = w - 1;
2255     }
2256
2257     /* Assume change */
2258     t->y1 = 0;
2259     t->y2 = h - 1;
2260
2261     /* Force "total erase" */
2262     t->total_erase = TRUE;
2263
2264     /* Default "blank" */
2265     t->attr_blank = 0;
2266     t->char_blank = ' ';
2267
2268     /* Prepare "fake" hooks to prevent core dumps */
2269     t->curs_hook = term_curs_hack;
2270     t->bigcurs_hook = term_bigcurs_hack;
2271     t->wipe_hook = term_wipe_hack;
2272     t->text_hook = term_text_hack;
2273     t->pict_hook = term_pict_hack;
2274     return 0;
2275 }
2276
2277 #ifdef JP
2278 /*
2279  * Move to a location and, using an attr, add a string vertically
2280  */
2281 errr term_putstr_v(TERM_LEN x, TERM_LEN y, int n, byte a, concptr s)
2282 {
2283     errr res;
2284     int y0 = y;
2285
2286     for (int i = 0; i < n && s[i] != 0; i++) {
2287         /* Move first */
2288         if ((res = term_gotoxy(x, y0)) != 0)
2289             return (res);
2290
2291         if (iskanji(s[i])) {
2292             if ((res = term_addstr(2, a, &s[i])) != 0)
2293                 return (res);
2294             i++;
2295             y0++;
2296             if (s[i] == 0)
2297                 break;
2298         } else {
2299             if ((res = term_addstr(1, a, &s[i])) != 0)
2300                 return (res);
2301             y0++;
2302         }
2303     }
2304
2305     return 0;
2306 }
2307 #endif
2308
2309 #ifndef WINDOWS
2310 errr term_nuke(term_type *t)
2311 {
2312     TERM_LEN w = t->wid;
2313     TERM_LEN h = t->hgt;
2314     if (t->active_flag) {
2315         if (t->nuke_hook)
2316             (*t->nuke_hook)(t);
2317
2318         t->active_flag = FALSE;
2319         t->mapped_flag = FALSE;
2320     }
2321
2322     term_win_nuke(t->old, w, h);
2323     KILL(t->old, term_win);
2324     term_win_nuke(t->scr, w, h);
2325     KILL(t->scr, term_win);
2326     if (t->mem) {
2327         term_win_nuke(t->mem, w, h);
2328         KILL(t->mem, term_win);
2329     }
2330
2331     if (t->tmp) {
2332         term_win_nuke(t->tmp, w, h);
2333         KILL(t->tmp, term_win);
2334     }
2335
2336     C_KILL(t->x1, h, TERM_LEN);
2337     C_KILL(t->x2, h, TERM_LEN);
2338     C_KILL(t->key_queue, t->key_size, char);
2339     return 0;
2340 }
2341 #endif