OSDN Git Service

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