]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - backgammon/common_source/fancy.c
e4734ca1e33846edff73bebd517bd4b7eb651c7f
[bsdgames-darwin.git] / backgammon / common_source / fancy.c
1 /* $NetBSD: fancy.c,v 1.5 1997/10/10 08:59:45 lukem Exp $ */
2
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)fancy.c 8.1 (Berkeley) 5/31/93";
40 #else
41 __RCSID("$NetBSD: fancy.c,v 1.5 1997/10/10 08:59:45 lukem Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include "back.h"
46
47 int tgetent __P((char *, char *));
48 int tgetnum __P((char *));
49 char *tgoto __P((char *, int, int));
50 char *tgetstr __P((char *, char **));
51 void tputs __P((char *, int, void (*outc) __P((int))));
52
53 char PC; /* padding character */
54 char *BC; /* backspace sequence */
55 char *CD; /* clear to end of screen sequence */
56 char *CE; /* clear to end of line sequence */
57 char *CL; /* clear screen sequence */
58 char *CM; /* cursor movement instructions */
59 char *HO; /* home cursor sequence */
60 char *MC; /* column cursor movement map */
61 char *ML; /* row cursor movement map */
62 char *ND; /* forward cursor sequence */
63 char *UP; /* up cursor sequence */
64
65 int lHO; /* length of HO */
66 int lBC; /* length of BC */
67 int lND; /* length of ND */
68 int lUP; /* length of UP */
69 int CO; /* number of columns */
70 int LI; /* number of lines */
71 int *linect; /* array of lengths of lines on screen (the
72 * actual screen is not stored) */
73
74 /* two letter codes */
75 char tcap[] = "bccdceclcmhomcmlndup";
76 /* corresponding strings */
77 char **tstr[] = {&BC, &CD, &CE, &CL, &CM, &HO, &MC, &ML, &ND, &UP};
78
79 int buffnum; /* pointer to output buffer */
80
81 char tbuf[1024]; /* buffer for decoded termcap entries */
82
83 int oldb[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
84
85 int oldr;
86 int oldw;
87 /* "real" cursor positions, so it knows when to reposition. These are -1 if
88 * curr and curc are accurate */
89 int realr;
90 int realc;
91
92 void
93 fboard()
94 {
95 int i, j, l;
96
97 curmove(0, 0); /* do top line */
98 for (i = 0; i < 53; i++)
99 fancyc('_');
100
101 curmove(15, 0); /* do botttom line */
102 for (i = 0; i < 53; i++)
103 fancyc('_');
104
105 l = 1; /* do vertical lines */
106 for (i = 52; i > -1; i -= 28) {
107 curmove((l == 1 ? 1 : 15), i);
108 fancyc('|');
109 for (j = 0; j < 14; j++) {
110 curmove(curr + l, curc - 1);
111 fancyc('|');
112 }
113 if (i == 24)
114 i += 32;
115 l = -l; /* alternate directions */
116 }
117
118 curmove(2, 1); /* label positions 13-18 */
119 for (i = 13; i < 18; i++) {
120 fancyc('1');
121 fancyc((i % 10) + '0');
122 curmove(curr, curc + 2);
123 }
124 fancyc('1');
125 fancyc('8');
126
127 curmove(2, 29); /* label positions 19-24 */
128 fancyc('1');
129 fancyc('9');
130 for (i = 20; i < 25; i++) {
131 curmove(curr, curc + 2);
132 fancyc('2');
133 fancyc((i % 10) + '0');
134 }
135
136 curmove(14, 1); /* label positions 12-7 */
137 fancyc('1');
138 fancyc('2');
139 for (i = 11; i > 6; i--) {
140 curmove(curr, curc + 2);
141 fancyc(i > 9 ? '1' : ' ');
142 fancyc((i % 10) + '0');
143 }
144
145 curmove(14, 30); /* label positions 6-1 */
146 fancyc('6');
147 for (i = 5; i > 0; i--) {
148 curmove(curr, curc + 3);
149 fancyc(i + '0');
150 }
151
152 for (i = 12; i > 6; i--)/* print positions 12-7 */
153 if (board[i])
154 bsect(board[i], 13, 1 + 4 * (12 - i), -1);
155
156 if (board[0]) /* print red men on bar */
157 bsect(board[0], 13, 25, -1);
158
159 for (i = 6; i > 0; i--) /* print positions 6-1 */
160 if (board[i])
161 bsect(board[i], 13, 29 + 4 * (6 - i), -1);
162
163 l = (off[1] < 0 ? off[1] + 15 : off[1]); /* print white's home */
164 bsect(l, 3, 54, 1);
165
166 curmove(8, 25); /* print the word BAR */
167 fancyc('B');
168 fancyc('A');
169 fancyc('R');
170
171 for (i = 13; i < 19; i++) /* print positions 13-18 */
172 if (board[i])
173 bsect(board[i], 3, 1 + 4 * (i - 13), 1);
174
175 if (board[25]) /* print white's men on bar */
176 bsect(board[25], 3, 25, 1);
177
178 for (i = 19; i < 25; i++) /* print positions 19-24 */
179 if (board[i])
180 bsect(board[i], 3, 29 + 4 * (i - 19), 1);
181
182 l = (off[0] < 0 ? off[0] + 15 : off[0]); /* print red's home */
183 bsect(-l, 13, 54, -1);
184
185 for (i = 0; i < 26; i++)/* save board position for refresh later */
186 oldb[i] = board[i];
187 oldr = (off[1] < 0 ? off[1] + 15 : off[1]);
188 oldw = -(off[0] < 0 ? off[0] + 15 : off[0]);
189 }
190 /*
191 * bsect (b,rpos,cpos,cnext)
192 * Print the contents of a board position. "b" has the value of the
193 * position, "rpos" is the row to start printing, "cpos" is the column to
194 * start printing, and "cnext" is positive if the position starts at the top
195 * and negative if it starts at the bottom. The value of "cpos" is checked
196 * to see if the position is a player's home, since those are printed
197 * differently.
198 */
199 void
200 bsect(b, rpos, cpos, cnext)
201 int b; /* contents of position */
202 int rpos; /* row of position */
203 int cpos; /* column of position */
204 int cnext; /* direction of position */
205 {
206 int j; /* index */
207 int n; /* number of men on position */
208 int bct; /* counter */
209 int k; /* index */
210 char pc; /* color of men on position */
211
212 bct = 0;
213 n = abs(b); /* initialize n and pc */
214 pc = (b > 0 ? 'r' : 'w');
215
216 if (n < 6 && cpos < 54) /* position cursor at start */
217 curmove(rpos, cpos + 1);
218 else
219 curmove(rpos, cpos);
220
221 for (j = 0; j < 5; j++) { /* print position row by row */
222
223 for (k = 0; k < 15; k += 5) /* print men */
224 if (n > j + k)
225 fancyc(pc);
226
227 if (j < 4) { /* figure how far to back up for next row */
228 if (n < 6) { /* stop if none left */
229 if (j + 1 == n)
230 break;
231 bct = 1; /* single column */
232 } else {
233 if (n < 11) { /* two columns */
234 if (cpos == 54) { /* home pos */
235 if (j + 5 >= n)
236 bct = 1;
237 else
238 bct = 2;
239 }
240 if (cpos < 54) { /* not home */
241 if (j + 6 >= n)
242 bct = 1;
243 else
244 bct = 2;
245 }
246 } else { /* three columns */
247 if (j + 10 >= n)
248 bct = 2;
249 else
250 bct = 3;
251 }
252 }
253 curmove(curr + cnext, curc - bct); /* reposition cursor */
254 }
255 }
256 }
257
258 void
259 refresh()
260 {
261 int i, r, c;
262
263 r = curr; /* save current position */
264 c = curc;
265
266 for (i = 12; i > 6; i--)/* fix positions 12-7 */
267 if (board[i] != oldb[i]) {
268 fixpos(oldb[i], board[i], 13, 1 + (12 - i) * 4, -1);
269 oldb[i] = board[i];
270 }
271 if (board[0] != oldb[0]) { /* fix red men on bar */
272 fixpos(oldb[0], board[0], 13, 25, -1);
273 oldb[0] = board[0];
274 }
275 for (i = 6; i > 0; i--) /* fix positions 6-1 */
276 if (board[i] != oldb[i]) {
277 fixpos(oldb[i], board[i], 13, 29 + (6 - i) * 4, -1);
278 oldb[i] = board[i];
279 }
280 i = -(off[0] < 0 ? off[0] + 15 : off[0]); /* fix white's home */
281 if (oldw != i) {
282 fixpos(oldw, i, 13, 54, -1);
283 oldw = i;
284 }
285 for (i = 13; i < 19; i++) /* fix positions 13-18 */
286 if (board[i] != oldb[i]) {
287 fixpos(oldb[i], board[i], 3, 1 + (i - 13) * 4, 1);
288 oldb[i] = board[i];
289 }
290 if (board[25] != oldb[25]) { /* fix white men on bar */
291 fixpos(oldb[25], board[25], 3, 25, 1);
292 oldb[25] = board[25];
293 }
294 for (i = 19; i < 25; i++) /* fix positions 19-24 */
295 if (board[i] != oldb[i]) {
296 fixpos(oldb[i], board[i], 3, 29 + (i - 19) * 4, 1);
297 oldb[i] = board[i];
298 }
299 i = (off[1] < 0 ? off[1] + 15 : off[1]); /* fix red's home */
300 if (oldr != i) {
301 fixpos(oldr, i, 3, 54, 1);
302 oldr = i;
303 }
304 curmove(r, c); /* return to saved position */
305 newpos();
306 buflush();
307 }
308
309 void
310 fixpos(old, new, r, c, inc)
311 int old, new, r, c, inc;
312 {
313 int o, n, nv;
314 int ov, nc;
315 char col;
316
317 nc = 0;
318 if (old * new >= 0) {
319 ov = abs(old);
320 nv = abs(new);
321 col = (old + new > 0 ? 'r' : 'w');
322 o = (ov - 1) / 5;
323 n = (nv - 1) / 5;
324 if (o == n) {
325 if (o == 2)
326 nc = c + 2;
327 if (o == 1)
328 nc = c < 54 ? c : c + 1;
329 if (o == 0)
330 nc = c < 54 ? c + 1 : c;
331 if (ov > nv)
332 fixcol(r + inc * (nv - n * 5), nc, abs(ov - nv), ' ', inc);
333 else
334 fixcol(r + inc * (ov - o * 5), nc, abs(ov - nv), col, inc);
335 return;
336 } else {
337 if (c < 54) {
338 if (o + n == 1) {
339 if (n) {
340 fixcol(r, c, abs(nv - 5), col, inc);
341 if (ov != 5)
342 fixcol(r + inc * ov, c + 1,
343 abs(ov - 5), col, inc);
344 } else {
345 fixcol(r, c, abs(ov - 5), ' ', inc);
346 if (nv != 5)
347 fixcol(r + inc * nv, c + 1,
348 abs(nv - 5), ' ', inc);
349 }
350 return;
351 }
352 if (n == 2) {
353 if (ov != 10)
354 fixcol(r + inc * (ov - 5), c,
355 abs(ov - 10), col, inc);
356 fixcol(r, c + 2, abs(nv - 10), col, inc);
357 } else {
358 if (nv != 10)
359 fixcol(r + inc * (nv - 5), c,
360 abs(nv - 10), ' ', inc);
361 fixcol(r, c + 2, abs(ov - 10), ' ', inc);
362 }
363 return;
364 }
365 if (n > o) {
366 fixcol(r + inc * (ov % 5), c + o, abs(5 * n - ov), col, inc);
367 if (nv != 5 * n)
368 fixcol(r, c + n, abs(5 * n - nv), col, inc);
369 } else {
370 fixcol(r + inc * (nv % 5), c + n, abs(5 * n - nv), ' ', inc);
371 if (ov != 5 * o)
372 fixcol(r, c + o, abs(5 * o - ov), ' ', inc);
373 }
374 return;
375 }
376 }
377 nv = abs(new);
378 fixcol(r, c + 1, nv, new > 0 ? 'r' : 'w', inc);
379 if (abs(old) <= abs(new))
380 return;
381 fixcol(r + inc * new, c + 1, abs(old + new), ' ', inc);
382 }
383
384 void
385 fixcol(r, c, l, ch, inc)
386 int l, ch, r, c, inc;
387 {
388 int i;
389
390 curmove(r, c);
391 fancyc(ch);
392 for (i = 1; i < l; i++) {
393 curmove(curr + inc, curc - 1);
394 fancyc(ch);
395 }
396 }
397
398 void
399 curmove(r, c)
400 int r, c;
401 {
402 if (curr == r && curc == c)
403 return;
404 if (realr == -1) {
405 realr = curr;
406 realc = curc;
407 }
408 curr = r;
409 curc = c;
410 }
411
412 void
413 newpos()
414 {
415 int r; /* destination row */
416 int c; /* destination column */
417 int mode = -1; /* mode of movement */
418
419 int count = 1000; /* character count */
420 int i; /* index */
421 int n; /* temporary variable */
422 char *m; /* string containing CM movement */
423
424
425 m = NULL;
426 if (realr == -1) /* see if already there */
427 return;
428
429 r = curr; /* set current and dest. positions */
430 c = curc;
431 curr = realr;
432 curc = realc;
433
434 /* double check position */
435 if (curr == r && curc == c) {
436 realr = realc = -1;
437 return;
438 }
439 if (CM) { /* try CM to get there */
440 mode = 0;
441 m = (char *) tgoto(CM, c, r);
442 count = strlen(m);
443 }
444 /* try HO and local movement */
445 if (HO && (n = r + c * lND + lHO) < count) {
446 mode = 1;
447 count = n;
448 }
449 /* try various LF combinations */
450 if (r >= curr) {
451 /* CR, LF, and ND */
452 if ((n = (r - curr) + c * lND + 1) < count) {
453 mode = 2;
454 count = n;
455 }
456 /* LF, ND */
457 if (c >= curc && (n = (r - curr) + (c - curc) * lND) < count) {
458 mode = 3;
459 count = n;
460 }
461 /* LF, BS */
462 if (c < curc && (n = (r - curr) + (curc - c) * lBC) < count) {
463 mode = 4;
464 count = n;
465 }
466 }
467 /* try corresponding UP combinations */
468 if (r < curr) {
469 /* CR, UP, and ND */
470 if ((n = (curr - r) * lUP + c * lND + 1) < count) {
471 mode = 5;
472 count = n;
473 }
474 /* UP and ND */
475 if (c >= curc && (n = (curr - r) * lUP + (c - curc) * lND) < count) {
476 mode = 6;
477 count = n;
478 }
479 /* UP and BS */
480 if (c < curc && (n = (curr - r) * lUP + (curc - c) * lBC) < count) {
481 mode = 7;
482 count = n;
483 }
484 }
485 /* space over */
486 if (curr == r && c > curc && linect[r] < curc && c - curc < count)
487 mode = 8;
488
489 switch (mode) {
490
491 case -1: /* error! */
492 write(2, "\r\nInternal cursor error.\r\n", 26);
493 getout(0);
494
495 /* direct cursor motion */
496 case 0:
497 tputs(m, abs(curr - r), addbuf);
498 break;
499
500 /* relative to "home" */
501 case 1:
502 tputs(HO, r, addbuf);
503 for (i = 0; i < r; i++)
504 addbuf('\012');
505 for (i = 0; i < c; i++)
506 tputs(ND, 1, addbuf);
507 break;
508
509 /* CR and down and over */
510 case 2:
511 addbuf('\015');
512 for (i = 0; i < r - curr; i++)
513 addbuf('\012');
514 for (i = 0; i < c; i++)
515 tputs(ND, 1, addbuf);
516 break;
517
518 /* down and over */
519 case 3:
520 for (i = 0; i < r - curr; i++)
521 addbuf('\012');
522 for (i = 0; i < c - curc; i++)
523 tputs(ND, 1, addbuf);
524 break;
525
526 /* down and back */
527 case 4:
528 for (i = 0; i < r - curr; i++)
529 addbuf('\012');
530 for (i = 0; i < curc - c; i++)
531 addbuf('\010');
532 break;
533
534 /* CR and up and over */
535 case 5:
536 addbuf('\015');
537 for (i = 0; i < curr - r; i++)
538 tputs(UP, 1, addbuf);
539 for (i = 0; i < c; i++)
540 tputs(ND, 1, addbuf);
541 break;
542
543 /* up and over */
544 case 6:
545 for (i = 0; i < curr - r; i++)
546 tputs(UP, 1, addbuf);
547 for (i = 0; i < c - curc; i++)
548 tputs(ND, 1, addbuf);
549 break;
550
551 /* up and back */
552 case 7:
553 for (i = 0; i < curr - r; i++)
554 tputs(UP, 1, addbuf);
555 for (i = 0; i < curc - c; i++) {
556 if (BC)
557 tputs(BC, 1, addbuf);
558 else
559 addbuf('\010');
560 }
561 break;
562
563 /* safe space */
564 case 8:
565 for (i = 0; i < c - curc; i++)
566 addbuf(' ');
567 }
568
569 /* fix positions */
570 curr = r;
571 curc = c;
572 realr = -1;
573 realc = -1;
574 }
575
576 void
577 clear()
578 {
579 int i;
580
581 /* double space if can't clear */
582 if (CL == 0) {
583 writel("\n\n");
584 return;
585 }
586 curr = curc = 0; /* fix position markers */
587 realr = realc = -1;
588 for (i = 0; i < 24; i++)/* clear line counts */
589 linect[i] = -1;
590 buffnum = -1; /* ignore leftover buffer contents */
591 tputs(CL, CO, addbuf); /* put CL in buffer */
592 }
593
594 void
595 tos()
596 { /* home cursor */
597 curmove(0, 0);
598 }
599
600
601 void
602 fancyc(c)
603 char c; /* character to output */
604 {
605 int sp; /* counts spaces in a tab */
606
607 if (c == '\007') { /* bells go in blindly */
608 addbuf(c);
609 return;
610 }
611 /* process tabs, use spaces if the the tab should be erasing things,
612 * otherwise use cursor movement routines. Note this does not use
613 * hardware tabs at all. */
614 if (c == '\t') {
615 sp = (curc + 8) & (~7); /* compute spaces */
616 /* check line length */
617 if (linect[curr] >= curc || sp < 4) {
618 for (; sp > curc; sp--)
619 addbuf(' ');
620 curc = sp; /* fix curc */
621 } else
622 curmove(curr, sp);
623 return;
624 }
625 /* do newline be calling newline */
626 if (c == '\n') {
627 newline();
628 return;
629 }
630 /* ignore any other control chars */
631 if (c < ' ')
632 return;
633
634 /* if an erasing space or non-space, just add it to buffer. Otherwise
635 * use cursor movement routine, so that multiple spaces will be
636 * grouped together */
637 if (c > ' ' || linect[curr] >= curc) {
638 newpos(); /* make sure position correct */
639 addbuf(c); /* add character to buffer */
640 /* fix line length */
641 if (c == ' ' && linect[curr] == curc)
642 linect[curr]--;
643 else
644 if (linect[curr] < curc)
645 linect[curr] = curc;
646 curc++; /* fix curc */
647 } else
648 /* use cursor movement routine */
649 curmove(curr, curc + 1);
650 }
651
652 void
653 clend()
654 {
655 int i;
656
657 if (CD) {
658 tputs(CD, CO - curr, addbuf);
659 for (i = curr; i < LI; i++)
660 linect[i] = -1;
661 return;
662 }
663 curmove(i = curr, 0);
664 cline();
665 while (curr < LI - 1) {
666 curmove(curr + 1, 0);
667 if (linect[curr] > -1)
668 cline();
669 }
670 curmove(i, 0);
671 }
672
673 void
674 cline()
675 {
676 int c;
677
678 if (curc > linect[curr])
679 return;
680 newpos();
681 if (CE) {
682 tputs(CE, 1, addbuf);
683 linect[curr] = curc - 1;
684 } else {
685 c = curc - 1;
686 while (linect[curr] > c) {
687 addbuf(' ');
688 curc++;
689 linect[curr]--;
690 }
691 curmove(curr, c + 1);
692 }
693 }
694
695 void
696 newline()
697 {
698 cline();
699 if (curr == LI - 1)
700 curmove(begscr, 0);
701 else
702 curmove(curr + 1, 0);
703 }
704
705 int
706 getcaps(s)
707 char *s;
708 {
709 char *code; /* two letter code */
710 char ***cap; /* pointer to cap string */
711 char *bufp; /* pointer to cap buffer */
712 char tentry[1024]; /* temporary uncoded caps buffer */
713
714 tgetent(tentry, s); /* get uncoded termcap entry */
715
716 LI = tgetnum("li"); /* get number of lines */
717 if (LI == -1)
718 LI = 12;
719 CO = tgetnum("co"); /* get number of columns */
720 if (CO == -1)
721 CO = 65;
722
723 bufp = tbuf; /* get padding character */
724 tgetstr("pc", &bufp);
725 if (bufp != tbuf)
726 PC = *tbuf;
727 else
728 PC = 0;
729
730 bufp = tbuf; /* get string entries */
731 cap = tstr;
732 for (code = tcap; *code; code += 2)
733 **cap++ = (char *) tgetstr(code, &bufp);
734
735 /* get pertinent lengths */
736 if (HO)
737 lHO = strlen(HO);
738 if (BC)
739 lBC = strlen(BC);
740 else
741 lBC = 1;
742 if (UP)
743 lUP = strlen(UP);
744 if (ND)
745 lND = strlen(ND);
746 if (LI < 24 || CO < 72 || !(CL && UP && ND))
747 return (0);
748 linect = (int *) calloc(LI + 1, sizeof(int));
749 return (1);
750 }