1 /* Tetrinet for Linux, by Andrew Church <achurch@achurch.org>
2 * This program is public domain.
4 * Text terminal I/O routines.
20 /*************************************************************************/
22 #define MY_HLINE (fancy ? ACS_HLINE : '-')
23 #define MY_VLINE (fancy ? ACS_VLINE : '|')
24 #define MY_ULCORNER (fancy ? ACS_ULCORNER : '+')
25 #define MY_URCORNER (fancy ? ACS_URCORNER : '+')
26 #define MY_LLCORNER (fancy ? ACS_LLCORNER : '+')
27 #define MY_LRCORNER (fancy ? ACS_LRCORNER : '+')
29 #define MY_HLINE2 (fancy ? (ACS_HLINE | A_BOLD) : '=')
30 #define MY_BOLD (fancy ? A_BOLD : 0)
32 /*************************************************************************/
33 /******************************* Input stuff *****************************/
34 /*************************************************************************/
36 /* Return either an ASCII code 0-255, a K_* value, or -1 if server input is
37 * waiting. Return -2 if we run out of time with no input.
40 static int wait_for_input(int msec
)
48 FD_SET(server_sock
, &fds
);
49 tv
.tv_sec
= msec
/1000;
50 tv
.tv_usec
= (msec
*1000) % 1000000;
51 while (select(server_sock
+1, &fds
, NULL
, NULL
, msec
<0 ? NULL
: &tv
) < 0) {
53 perror("Warning: select() failed");
55 if (FD_ISSET(0, &fds
)) {
59 else if (c
== KEY_DOWN
)
61 else if (c
== KEY_LEFT
)
63 else if (c
== KEY_RIGHT
)
65 else if (c
== KEY_F(1))
67 else if (c
== KEY_F(2))
69 else if (c
== KEY_F(3))
71 else if (c
== KEY_F(4))
73 else if (c
== KEY_F(5))
75 else if (c
== KEY_F(6))
77 else if (c
== KEY_F(7))
79 else if (c
== KEY_F(8))
81 else if (c
== KEY_F(9))
83 else if (c
== KEY_F(10))
85 else if (c
== KEY_F(11))
87 else if (c
== KEY_F(12))
89 else if (c
== KEY_BACKSPACE
)
93 else if (c
== 7) /* ^G */
94 return 27; /* Escape */
97 } /* if (FD_ISSET(0, &fds)) */
98 else if (FD_ISSET(server_sock
, &fds
))
101 return -2; /* out of time */
104 /*************************************************************************/
105 /****************************** Output stuff *****************************/
106 /*************************************************************************/
108 /* Size of the screen */
109 static int scrwidth
, scrheight
;
111 /* Is color available? */
112 static int has_color
;
114 /*************************************************************************/
119 int x
, y
, width
, height
;
121 WINDOW
*win
; /* NULL if not currently displayed */
125 static TextBuffer plinebuf
, gmsgbuf
, attdefbuf
;
127 /*************************************************************************/
129 /* Window for typing in-game text, and its coordinates: */
131 static WINDOW
*gmsg_inputwin
;
132 static int gmsg_inputpos
, gmsg_inputheight
;
134 /*************************************************************************/
135 /*************************************************************************/
137 /* Clean up the screen on exit. */
139 static void screen_cleanup()
141 wmove(stdscr
, scrheight
-1, 0);
147 /*************************************************************************/
149 /* Little signal handler that just does an exit(1) (thereby getting our
150 * cleanup routine called), except for TSTP, which does a clean suspend.
153 static void (*old_tstp
)(int sig
);
155 static void sighandler(int sig
)
157 if (sig
!= SIGTSTP
) {
160 fprintf(stderr
, "%s\n", strsignal(sig
));
164 signal(SIGTSTP
, old_tstp
);
167 signal(SIGTSTP
, sighandler
);
170 /*************************************************************************/
171 /*************************************************************************/
173 #define MAXCOLORS 256
175 static int colors
[MAXCOLORS
][2] = { {-1,-1} };
177 /* Return a color attribute value. */
179 static long getcolor(int fg
, int bg
)
183 if (colors
[0][0] < 0) {
185 memset(colors
, -1, sizeof(colors
));
186 colors
[0][0] = COLOR_WHITE
;
187 colors
[0][1] = COLOR_BLACK
;
189 if (fg
== COLOR_WHITE
&& bg
== COLOR_BLACK
)
190 return COLOR_PAIR(0);
191 for (i
= 1; i
< MAXCOLORS
; i
++) {
192 if (colors
[i
][0] == fg
&& colors
[i
][1] == bg
)
193 return COLOR_PAIR(i
);
195 for (i
= 1; i
< MAXCOLORS
; i
++) {
196 if (colors
[i
][0] < 0) {
197 if (init_pair(i
, fg
, bg
) == ERR
)
201 return COLOR_PAIR(i
);
207 /*************************************************************************/
208 /*************************************************************************/
210 /* Set up the screen stuff. */
212 static void screen_setup(void)
214 /* Avoid messy keyfield signals while we're setting up */
215 signal(SIGINT
, SIG_IGN
);
216 signal(SIGQUIT
, SIG_IGN
);
217 signal(SIGTSTP
, SIG_IGN
);
222 nodelay(stdscr
, TRUE
);
223 keypad(stdscr
, TRUE
);
224 leaveok(stdscr
, TRUE
);
225 if ((has_color
= has_colors()))
227 getmaxyx(stdscr
, scrheight
, scrwidth
);
228 scrwidth
--; /* Don't draw in last column--this can cause scroll */
230 /* Cancel all this when we exit. */
231 atexit(screen_cleanup
);
233 /* Catch signals so we can exit cleanly. */
234 signal(SIGINT
, sighandler
);
235 signal(SIGQUIT
, sighandler
);
236 signal(SIGTERM
, sighandler
);
237 signal(SIGHUP
, sighandler
);
238 /* signal(SIGSEGV, sighandler); */
239 signal(SIGABRT
, sighandler
);
240 signal(SIGIOT
, sighandler
);
241 signal(SIGTRAP
, sighandler
);
242 signal(SIGBUS
, sighandler
);
243 signal(SIGFPE
, sighandler
);
244 signal(SIGUSR1
, sighandler
);
245 signal(SIGUSR2
, sighandler
);
246 signal(SIGALRM
, sighandler
);
248 signal(SIGSTKFLT
, sighandler
);
250 signal(SIGTSTP
, sighandler
);
251 signal(SIGXCPU
, sighandler
);
252 signal(SIGXFSZ
, sighandler
);
253 signal(SIGVTALRM
, sighandler
);
255 /* Broken pipes don't want to bother us at all. */
256 signal(SIGPIPE
, SIG_IGN
);
259 /*************************************************************************/
261 /* Redraw everything on the screen. */
263 static void screen_refresh(void)
266 touchline(stdscr
, gmsg_inputpos
, gmsg_inputheight
);
268 touchline(stdscr
, plinebuf
.y
, plinebuf
.height
);
270 touchline(stdscr
, gmsgbuf
.y
, gmsgbuf
.height
);
272 touchline(stdscr
, attdefbuf
.y
, attdefbuf
.height
);
273 wnoutrefresh(stdscr
);
277 /*************************************************************************/
279 /* Like screen_refresh(), but clear the screen first. */
281 static void screen_redraw(void)
283 clearok(stdscr
, TRUE
);
287 /*************************************************************************/
288 /************************* Text buffer routines **************************/
289 /*************************************************************************/
291 /* Put a line of text in a text buffer. */
293 static void outline(TextBuffer
*buf
, const char *s
)
295 if (buf
->line
== buf
->height
) {
298 memmove(buf
->text
, buf
->text
+1, (buf
->height
-1) * sizeof(char *));
302 mvwaddstr(buf
->win
, buf
->line
, 0, s
);
303 if (s
!= buf
->text
[buf
->line
]) /* check for restoring display */
304 buf
->text
[buf
->line
] = strdup(s
);
308 static void draw_text(int bufnum
, const char *s
)
310 char str
[1024]; /* hopefully scrwidth < 1024 */
317 case BUFFER_PLINE
: buf
= &plinebuf
; break;
318 case BUFFER_GMSG
: buf
= &gmsgbuf
; break;
319 case BUFFER_ATTDEF
: buf
= &attdefbuf
; break;
326 attrset(getcolor(COLOR_WHITE
, COLOR_BLACK
));
328 while (*s
&& isspace(*s
))
330 while (strlen(s
) > buf
->width
- indent
) {
331 t
= s
+ buf
->width
- indent
;
332 while (t
>= s
&& !isspace(*t
))
334 while (t
>= s
&& isspace(*t
))
338 t
= s
+ buf
->width
- indent
;
340 sprintf(str
, "%*s", indent
, "");
341 strncpy(str
+indent
, s
, t
-s
);
350 sprintf(str
, "%*s", indent
, "");
351 strcpy(str
+indent
, s
);
359 /*************************************************************************/
361 /* Clear the contents of a text buffer. */
363 static void clear_text(int bufnum
)
369 case BUFFER_PLINE
: buf
= &plinebuf
; break;
370 case BUFFER_GMSG
: buf
= &gmsgbuf
; break;
371 case BUFFER_ATTDEF
: buf
= &attdefbuf
; break;
375 for (i
= 0; i
< buf
->height
; i
++) {
389 /*************************************************************************/
391 /* Restore the contents of the given text buffer. */
393 static void restore_text(TextBuffer
*buf
)
396 while (buf
->line
< buf
->height
&& buf
->text
[buf
->line
])
397 outline(buf
, buf
->text
[buf
->line
]);
400 /*************************************************************************/
402 /* Open a window for the given text buffer. */
404 static void open_textwin(TextBuffer
*buf
)
406 if (buf
->height
<= 0 || buf
->width
<= 0) {
408 move(scrheight
-1, 0);
409 snprintf(str
, sizeof(str
), "ERROR: bad textwin size (%d,%d)",
410 buf
->width
, buf
->height
);
415 buf
->win
= subwin(stdscr
, buf
->height
, buf
->width
, buf
->y
, buf
->x
);
416 scrollok(buf
->win
, TRUE
);
419 buf
->text
= calloc(buf
->height
, sizeof(char *));
424 /*************************************************************************/
426 /* Close the window for the given text buffer, if it's open. */
428 static void close_textwin(TextBuffer
*buf
)
436 /*************************************************************************/
437 /************************ Field drawing routines *************************/
438 /*************************************************************************/
440 /* Are we on a wide screen (>=92 columns)? */
441 static int wide_screen
= 0;
443 /* Field display X/Y coordinates. */
444 static const int own_coord
[2] = {0,0};
445 static int other_coord
[5][2] = /* Recomputed based on screen width */
446 { {30,0}, {47,0}, {64,0}, {47,24}, {64,24} };
448 /* Position of the status window. */
449 static const int status_coord
[2] = {28,25};
450 static const int next_coord
[2] = {40,24};
451 static const int alt_status_coord
[2] = {28,2};
452 static const int alt_next_coord
[2] = {29,8};
454 /* Position of the attacks/defenses window. */
455 static const int attdef_coord
[2] = {28,28};
456 static const int alt_attdef_coord
[2] = {28,24};
458 /* Position of the text window. X coordinate is ignored. */
459 static const int field_text_coord
[2] = {0,47};
461 /* Information for drawing blocks. Color attributes are added to blocks in
462 * the setup_fields() routine. */
463 static int tile_chars
[15] =
464 { ' ','#','#','#','#','#','a','c','n','r','s','b','g','q','o' };
466 static int attdef_size
;
467 static int attdef_line
;
468 static char **attdef_text
;
470 /* Are we redrawing the entire display? */
471 static int field_redraw
= 0;
473 /*************************************************************************/
474 /*************************************************************************/
476 /* Set up the field display. */
478 static void draw_own_field(void);
479 static void draw_other_field(int player
);
480 static void draw_status(void);
481 static void draw_specials(void);
482 static void draw_gmsg_input(const char *s
, int pos
);
484 static void setup_fields(void)
486 int i
, j
, x
, y
, base
, delta
, attdefbot
;
489 if (!(tile_chars
[0] & A_ATTRIBUTES
)) {
490 for (i
= 1; i
< 15; i
++)
491 tile_chars
[i
] |= A_BOLD
;
492 tile_chars
[1] |= getcolor(COLOR_BLUE
, COLOR_BLACK
);
493 tile_chars
[2] |= getcolor(COLOR_YELLOW
, COLOR_BLACK
);
494 tile_chars
[3] |= getcolor(COLOR_GREEN
, COLOR_BLACK
);
495 tile_chars
[4] |= getcolor(COLOR_MAGENTA
, COLOR_BLACK
);
496 tile_chars
[5] |= getcolor(COLOR_RED
, COLOR_BLACK
);
500 leaveok(stdscr
, TRUE
);
501 close_textwin(&plinebuf
);
503 attrset(getcolor(COLOR_WHITE
,COLOR_BLACK
));
505 if (scrwidth
>= 92) {
511 delta
= (scrwidth
- base
) / 3;
512 base
+= 2 + (delta
- (FIELD_WIDTH
+5)) / 2;
513 other_coord
[0][0] = base
;
514 other_coord
[1][0] = base
+ delta
;
515 other_coord
[2][0] = base
+ delta
*2;
516 other_coord
[3][0] = base
+ delta
;
517 other_coord
[4][0] = base
+ delta
*2;
519 attdefbot
= field_text_coord
[1] - 1;
520 if (scrheight
- field_text_coord
[1] > 3) {
521 move(field_text_coord
[1], 0);
522 hline(MY_HLINE2
, scrwidth
);
524 if (scrheight
- field_text_coord
[1] > 5) {
525 move(scrheight
-2, 0);
526 hline(MY_HLINE2
, scrwidth
);
528 move(scrheight
-1, 0);
529 addstr("F1=Show Fields F2=Partyline F3=Winlist");
530 move(scrheight
-1, scrwidth
-8);
533 gmsgbuf
.y
= field_text_coord
[1]+1;
534 gmsgbuf
.height
= scrheight
- field_text_coord
[1] - 3;
536 gmsgbuf
.y
= field_text_coord
[1]+1;
537 gmsgbuf
.height
= scrheight
- field_text_coord
[1] - 1;
540 gmsgbuf
.y
= field_text_coord
[1];
541 gmsgbuf
.height
= scrheight
- field_text_coord
[1];
543 gmsgbuf
.x
= field_text_coord
[0];
544 gmsgbuf
.width
= scrwidth
;
545 open_textwin(&gmsgbuf
);
549 sprintf(buf
, "%d", my_playernum
);
550 mvaddstr(y
, x
+FIELD_WIDTH
*2+2, buf
);
551 for (i
= 2; i
< FIELD_HEIGHT
*2 && players
[my_playernum
-1][i
-2]; i
++)
552 mvaddch(y
+i
, x
+FIELD_WIDTH
*2+2, players
[my_playernum
-1][i
-2]);
554 vline(MY_VLINE
, FIELD_HEIGHT
*2);
555 move(y
, x
+FIELD_WIDTH
*2+1);
556 vline(MY_VLINE
, FIELD_HEIGHT
*2);
557 move(y
+FIELD_HEIGHT
*2, x
);
559 hline(MY_HLINE
, FIELD_WIDTH
*2);
560 move(y
+FIELD_HEIGHT
*2, x
+FIELD_WIDTH
*2+1);
562 mvaddstr(y
+FIELD_HEIGHT
*2+2, x
, "Specials:");
566 for (j
= 0; j
< 5; j
++) {
567 x
= other_coord
[j
][0];
568 y
= other_coord
[j
][1];
570 vline(MY_VLINE
, FIELD_HEIGHT
);
571 move(y
, x
+FIELD_WIDTH
+1);
572 vline(MY_VLINE
, FIELD_HEIGHT
);
573 move(y
+FIELD_HEIGHT
, x
);
575 hline(MY_HLINE
, FIELD_WIDTH
);
576 move(y
+FIELD_HEIGHT
, x
+FIELD_WIDTH
+1);
578 if (j
+1 >= my_playernum
) {
579 sprintf(buf
, "%d", j
+2);
580 mvaddstr(y
, x
+FIELD_WIDTH
+2, buf
);
582 for (i
= 0; i
< FIELD_HEIGHT
-2 && players
[j
+1][i
]; i
++)
583 mvaddch(y
+i
+2, x
+FIELD_WIDTH
+2, players
[j
+1][i
]);
585 draw_other_field(j
+2);
587 sprintf(buf
, "%d", j
+1);
588 mvaddstr(y
, x
+FIELD_WIDTH
+2, buf
);
590 for (i
= 0; i
< FIELD_HEIGHT
-2 && players
[j
][i
]; i
++)
591 mvaddch(y
+i
+2, x
+FIELD_WIDTH
+2, players
[j
][i
]);
593 draw_other_field(j
+1);
598 x
= alt_status_coord
[0];
599 y
= alt_status_coord
[1];
600 mvaddstr(y
, x
, "Lines:");
601 mvaddstr(y
+1, x
, "Level:");
602 x
= alt_next_coord
[0];
603 y
= alt_next_coord
[1];
604 mvaddstr(y
-2, x
-1, "Next piece:");
608 mvaddch(y
-1, x
+8, MY_URCORNER
);
616 mvaddch(y
+8, x
+8, MY_LRCORNER
);
620 mvaddstr(y
-1, x
, "Next piece:");
621 mvaddstr(y
, x
, "Lines:");
622 mvaddstr(y
+1, x
, "Level:");
627 attdefbuf
.x
= wide_screen
? alt_attdef_coord
[0] : attdef_coord
[0];
628 attdefbuf
.y
= wide_screen
? alt_attdef_coord
[1] : attdef_coord
[1];
629 attdefbuf
.width
= (other_coord
[3][0]-1) - attdefbuf
.x
;
630 attdefbuf
.height
= (attdefbot
+1) - attdefbuf
.y
;
631 open_textwin(&attdefbuf
);
634 delwin(gmsg_inputwin
);
635 gmsg_inputwin
= NULL
;
636 draw_gmsg_input(NULL
, -1);
643 /*************************************************************************/
645 /* Display the player's own field. */
647 static void draw_own_field(void)
650 Field
*f
= &fields
[my_playernum
-1];
652 if (dispmode
!= MODE_FIELDS
)
656 for (y
= 0; y
< 22; y
++) {
657 for (x
= 0; x
< 12; x
++) {
658 int c
= tile_chars
[(*f
)[y
][x
]];
659 mvaddch(y0
+y
*2, x0
+x
*2, c
);
661 mvaddch(y0
+y
*2+1, x0
+x
*2, c
);
666 delwin(gmsg_inputwin
);
667 gmsg_inputwin
= NULL
;
668 draw_gmsg_input(NULL
, -1);
674 /*************************************************************************/
676 /* Display another player's field. */
678 static void draw_other_field(int player
)
683 if (dispmode
!= MODE_FIELDS
)
685 f
= &fields
[player
-1];
686 if (player
> my_playernum
)
689 x0
= other_coord
[player
][0]+1;
690 y0
= other_coord
[player
][1];
691 for (y
= 0; y
< 22; y
++) {
693 for (x
= 0; x
< 12; x
++)
694 addch(tile_chars
[(*f
)[y
][x
]]);
697 delwin(gmsg_inputwin
);
698 gmsg_inputwin
= NULL
;
699 draw_gmsg_input(NULL
, -1);
705 /*************************************************************************/
707 /* Display the current game status (level, lines, next piece). */
709 static void draw_status(void)
712 char buf
[32], shape
[4][4];
714 x
= wide_screen
? alt_status_coord
[0] : status_coord
[0];
715 y
= wide_screen
? alt_status_coord
[1] : status_coord
[1];
716 sprintf(buf
, "%d", lines
>99999 ? 99999 : lines
);
717 mvaddstr(y
+1, x
+7, buf
);
718 sprintf(buf
, "%d", levels
[my_playernum
]);
719 mvaddstr(y
+2, x
+7, buf
);
720 x
= wide_screen
? alt_next_coord
[0] : next_coord
[0];
721 y
= wide_screen
? alt_next_coord
[1] : next_coord
[1];
722 if (get_shape(next_piece
, 0, shape
) == 0) {
723 for (j
= 0; j
< 4; j
++) {
726 for (i
= 0; i
< 4; i
++) {
729 addch(tile_chars
[shape
[j
][i
]]);
730 addch(tile_chars
[shape
[j
][i
]]);
731 move(y
+j
*2+1, x
+i
*2);
732 addch(tile_chars
[shape
[j
][i
]]);
733 addch(tile_chars
[shape
[j
][i
]]);
735 addch(tile_chars
[shape
[j
][i
]]);
741 /*************************************************************************/
743 /* Display the special inventory and description of the current special. */
745 static const char *descs
[] = {
750 "Clear Random Blocks ",
752 "Clear Special Blocks",
758 static void draw_specials(void)
762 if (dispmode
!= MODE_FIELDS
)
766 mvaddstr(y
, x
, descs
[specials
[0]+1]);
769 while (i
< special_capacity
&& specials
[i
] >= 0 && x
< attdef_coord
[0]-1) {
770 addch(tile_chars
[specials
[i
]+6]);
774 while (x
< attdef_coord
[0]-1) {
775 addch(tile_chars
[0]);
782 /*************************************************************************/
784 /* Display an attack/defense message. */
786 static const char *msgs
[][2] = {
787 { "cs1", "1 Line Added to All" },
788 { "cs2", "2 Lines Added to All" },
789 { "cs4", "4 Lines Added to All" },
791 { "c", "Clear Line" },
792 { "n", "Nuke Field" },
793 { "r", "Clear Random Blocks" },
794 { "s", "Switch Fields" },
795 { "b", "Clear Special Blocks" },
796 { "g", "Block Gravity" },
797 { "q", "Blockquake" },
798 { "o", "Block Bomb" },
802 static void draw_attdef(const char *type
, int from
, int to
)
807 width
= other_coord
[4][0] - attdef_coord
[0] - 1;
808 for (i
= 0; msgs
[i
][0]; i
++) {
809 if (strcmp(type
, msgs
[i
][0]) == 0)
814 strcpy(buf
, msgs
[i
][1]);
816 sprintf(buf
+strlen(buf
), " on %s", players
[to
-1]);
818 sprintf(buf
+strlen(buf
), " by Server");
820 sprintf(buf
+strlen(buf
), " by %s", players
[from
-1]);
821 draw_text(BUFFER_ATTDEF
, buf
);
824 /*************************************************************************/
826 /* Display the in-game text window. */
828 static void draw_gmsg_input(const char *s
, int pos
)
830 static int start
= 0; /* Start of displayed part of input line */
831 static const char *last_s
;
843 attrset(getcolor(COLOR_WHITE
,COLOR_BLACK
));
845 if (!gmsg_inputwin
) {
846 gmsg_inputpos
= scrheight
/2 - 1;
847 gmsg_inputheight
= 3;
849 subwin(stdscr
, gmsg_inputheight
, scrwidth
, gmsg_inputpos
, 0);
850 werase(gmsg_inputwin
);
851 leaveok(gmsg_inputwin
, FALSE
);
852 leaveok(stdscr
, FALSE
);
853 mvwaddstr(gmsg_inputwin
, 1, 0, "Text>");
856 if (strlen(s
) < scrwidth
-7) {
858 mvwaddstr(gmsg_inputwin
, 1, 6, s
);
859 wmove(gmsg_inputwin
, 1, 6+strlen(s
));
860 move(gmsg_inputpos
+1, 6+strlen(s
));
861 wclrtoeol(gmsg_inputwin
);
862 wmove(gmsg_inputwin
, 1, 6+pos
);
863 move(gmsg_inputpos
+1, 6+pos
);
869 } else if (pos
> start
+ scrwidth
-15) {
870 start
= pos
- (scrwidth
-15);
871 if (start
> strlen(s
) - (scrwidth
-7))
872 start
= strlen(s
) - (scrwidth
-7);
874 mvwaddnstr(gmsg_inputwin
, 1, 6, s
+start
, scrwidth
-6);
875 wmove(gmsg_inputwin
, 1, 6 + (pos
-start
));
876 move(gmsg_inputpos
+1, 6 + (pos
-start
));
881 /*************************************************************************/
883 /* Clear the in-game text window. */
885 static void clear_gmsg_input(void)
888 delwin(gmsg_inputwin
);
889 gmsg_inputwin
= NULL
;
890 leaveok(stdscr
, TRUE
);
891 touchline(stdscr
, gmsg_inputpos
, gmsg_inputheight
);
897 /*************************************************************************/
898 /*************************** Partyline display ***************************/
899 /*************************************************************************/
901 static void setup_partyline(void)
905 close_textwin(&gmsgbuf
);
906 close_textwin(&attdefbuf
);
909 attrset(getcolor(COLOR_WHITE
,COLOR_BLACK
));
911 plinebuf
.x
= plinebuf
.y
= 0;
912 plinebuf
.width
= scrwidth
;
913 plinebuf
.height
= scrheight
-4;
914 open_textwin(&plinebuf
);
916 move(scrheight
-4, 0);
917 hline(MY_HLINE
, scrwidth
);
918 move(scrheight
-3, 0);
921 move(scrheight
-2, 0);
922 hline(MY_HLINE2
, scrwidth
);
924 move(scrheight
-1, 0);
925 addstr("F1=Show Fields F2=Partyline F3=Winlist");
926 move(scrheight
-1, scrwidth
-8);
930 move(scrheight
-3, 2);
931 leaveok(stdscr
, FALSE
);
935 /*************************************************************************/
937 static void draw_partyline_input(const char *s
, int pos
)
939 static int start
= 0; /* Start of displayed part of input line */
941 attrset(getcolor(COLOR_WHITE
,COLOR_BLACK
));
942 if (strlen(s
) < scrwidth
-3) {
944 mvaddstr(scrheight
-3, 2, s
);
945 move(scrheight
-3, 2+strlen(s
));
947 move(scrheight
-3, 2+pos
);
953 } else if (pos
> start
+ scrwidth
-11) {
954 start
= pos
- (scrwidth
-11);
955 if (start
> strlen(s
) - (scrwidth
-3))
956 start
= strlen(s
) - (scrwidth
-3);
958 mvaddnstr(scrheight
-3, 2, s
+start
, scrwidth
-2);
959 move(scrheight
-3, 2 + (pos
-start
));
964 /*************************************************************************/
965 /**************************** Winlist display ****************************/
966 /*************************************************************************/
968 static void setup_winlist(void)
973 leaveok(stdscr
, TRUE
);
974 close_textwin(&plinebuf
);
976 attrset(getcolor(COLOR_WHITE
,COLOR_BLACK
));
978 for (i
= 0; i
< MAXWINLIST
&& *winlist
[i
].name
; i
++) {
979 x
= scrwidth
/2 - strlen(winlist
[i
].name
);
982 if (winlist
[i
].team
) {
985 mvaddstr(i
*2, x
-4, "<T>");
987 mvaddstr(i
*2, x
, winlist
[i
].name
);
988 snprintf(buf
, sizeof(buf
), "%4d", winlist
[i
].points
);
989 if (winlist
[i
].games
) {
990 int avg100
= winlist
[i
].points
*100 / winlist
[i
].games
;
991 snprintf(buf
+strlen(buf
), sizeof(buf
)-strlen(buf
),
992 " %d.%02d",avg100
/100, avg100
%100);
994 x
+= strlen(winlist
[i
].name
) + 2;
995 if (x
> scrwidth
- strlen(buf
))
996 x
= scrwidth
- strlen(buf
);
997 mvaddstr(i
*2, x
, buf
);
1000 move(scrheight
-2, 0);
1001 hline(MY_HLINE2
, scrwidth
);
1003 move(scrheight
-1, 0);
1004 addstr("F1=Show Fields F2=Partyline F3=Winlist");
1005 move(scrheight
-1, scrwidth
-8);
1012 /*************************************************************************/
1013 /************************** Interface declaration ************************/
1014 /*************************************************************************/
1016 Interface xwin_interface
= {
1037 draw_partyline_input
,
1042 /*************************************************************************/