1 /* Tetrinet for Linux, by Andrew Church <achurch@achurch.org>
2 * This program is public domain.
4 * Text terminal I/O routines.
7 #define _GNU_SOURCE /* strsignal() - FIXME!!! --pasky */
22 /*************************************************************************/
24 #define MY_HLINE (fancy ? ACS_HLINE : '-')
25 #define MY_VLINE (fancy ? ACS_VLINE : '|')
26 #define MY_ULCORNER (fancy ? ACS_ULCORNER : '+')
27 #define MY_URCORNER (fancy ? ACS_URCORNER : '+')
28 #define MY_LLCORNER (fancy ? ACS_LLCORNER : '+')
29 #define MY_LRCORNER (fancy ? ACS_LRCORNER : '+')
31 #define MY_HLINE2 (fancy ? (ACS_HLINE | A_BOLD) : '=')
32 #define MY_BOLD (fancy ? A_BOLD : 0)
34 /*************************************************************************/
35 /******************************* Input stuff *****************************/
36 /*************************************************************************/
38 /* Return either an ASCII code 0-255, a K_* value, or -1 if server input is
39 * waiting. Return -2 if we run out of time with no input.
42 static int wait_for_input(int msec
)
47 static int escape
= 0;
51 FD_SET(server_sock
, &fds
);
52 tv
.tv_sec
= msec
/1000;
53 tv
.tv_usec
= (msec
*1000) % 1000000;
54 while (select(server_sock
+1, &fds
, NULL
, NULL
, msec
<0 ? NULL
: &tv
) < 0) {
56 perror("Warning: select() failed");
58 if (FD_ISSET(0, &fds
)) {
60 if (!escape
&& c
== 27) { /* Escape */
62 c
= wait_for_input(1000);
71 else if (c
== KEY_DOWN
)
73 else if (c
== KEY_LEFT
)
75 else if (c
== KEY_RIGHT
)
77 else if (c
== KEY_F(1) || c
== ('1'|0x80) || (escape
&& c
== '1'))
79 else if (c
== KEY_F(2) || c
== ('2'|0x80) || (escape
&& c
== '2'))
81 else if (c
== KEY_F(3) || c
== ('3'|0x80) || (escape
&& c
== '3'))
83 else if (c
== KEY_F(4) || c
== ('4'|0x80) || (escape
&& c
== '4'))
85 else if (c
== KEY_F(5) || c
== ('5'|0x80) || (escape
&& c
== '5'))
87 else if (c
== KEY_F(6) || c
== ('6'|0x80) || (escape
&& c
== '6'))
89 else if (c
== KEY_F(7) || c
== ('7'|0x80) || (escape
&& c
== '7'))
91 else if (c
== KEY_F(8) || c
== ('8'|0x80) || (escape
&& c
== '8'))
93 else if (c
== KEY_F(9) || c
== ('9'|0x80) || (escape
&& c
== '9'))
95 else if (c
== KEY_F(10) || c
== ('0'|0x80) || (escape
&& c
== '0'))
97 else if (c
== KEY_F(11))
99 else if (c
== KEY_F(12))
101 else if (c
== KEY_BACKSPACE
)
103 else if (c
>= 0x0100)
105 else if (c
== 7) /* ^G */
106 return 27; /* Escape */
109 } /* if (FD_ISSET(0, &fds)) */
110 else if (FD_ISSET(server_sock
, &fds
))
113 return -2; /* out of time */
116 /*************************************************************************/
117 /****************************** Output stuff *****************************/
118 /*************************************************************************/
120 /* Size of the screen */
121 static int scrwidth
, scrheight
;
123 /* Is color available? */
124 static int has_color
;
126 /*************************************************************************/
131 int x
, y
, width
, height
;
133 WINDOW
*win
; /* NULL if not currently displayed */
137 static TextBuffer plinebuf
, gmsgbuf
, attdefbuf
;
139 /*************************************************************************/
141 /* Window for typing in-game text, and its coordinates: */
143 static WINDOW
*gmsg_inputwin
;
144 static int gmsg_inputpos
, gmsg_inputheight
;
146 /*************************************************************************/
147 /*************************************************************************/
149 /* Clean up the screen on exit. */
151 static void screen_cleanup()
153 wmove(stdscr
, scrheight
-1, 0);
159 /*************************************************************************/
161 /* Little signal handler that just does an exit(1) (thereby getting our
162 * cleanup routine called), except for TSTP, which does a clean suspend.
165 static void (*old_tstp
)(int sig
);
167 static void sighandler(int sig
)
169 if (sig
!= SIGTSTP
) {
172 fprintf(stderr
, "%s\n", strsignal(sig
));
176 signal(SIGTSTP
, old_tstp
);
179 signal(SIGTSTP
, sighandler
);
182 /*************************************************************************/
183 /*************************************************************************/
185 #define MAXCOLORS 256
187 static int colors
[MAXCOLORS
][2] = { {-1,-1} };
189 /* Return a color attribute value. */
191 static long getcolor(int fg
, int bg
)
195 if (colors
[0][0] < 0) {
197 memset(colors
, -1, sizeof(colors
));
198 colors
[0][0] = COLOR_WHITE
;
199 colors
[0][1] = COLOR_BLACK
;
201 if (fg
== COLOR_WHITE
&& bg
== COLOR_BLACK
)
202 return COLOR_PAIR(0);
203 for (i
= 1; i
< MAXCOLORS
; i
++) {
204 if (colors
[i
][0] == fg
&& colors
[i
][1] == bg
)
205 return COLOR_PAIR(i
);
207 for (i
= 1; i
< MAXCOLORS
; i
++) {
208 if (colors
[i
][0] < 0) {
209 if (init_pair(i
, fg
, bg
) == ERR
)
213 return COLOR_PAIR(i
);
219 /*************************************************************************/
220 /*************************************************************************/
222 /* Set up the screen stuff. */
224 static void screen_setup(void)
226 /* Avoid messy keyfield signals while we're setting up */
227 signal(SIGINT
, SIG_IGN
);
228 signal(SIGQUIT
, SIG_IGN
);
229 signal(SIGTSTP
, SIG_IGN
);
234 nodelay(stdscr
, TRUE
);
235 keypad(stdscr
, TRUE
);
236 leaveok(stdscr
, TRUE
);
237 if ((has_color
= has_colors()))
239 getmaxyx(stdscr
, scrheight
, scrwidth
);
240 scrwidth
--; /* Don't draw in last column--this can cause scroll */
242 /* Cancel all this when we exit. */
243 atexit(screen_cleanup
);
245 /* Catch signals so we can exit cleanly. */
246 signal(SIGINT
, sighandler
);
247 signal(SIGQUIT
, sighandler
);
248 signal(SIGTERM
, sighandler
);
249 signal(SIGHUP
, sighandler
);
250 signal(SIGSEGV
, sighandler
);
251 signal(SIGABRT
, sighandler
);
252 signal(SIGIOT
, sighandler
);
253 signal(SIGTRAP
, sighandler
);
254 signal(SIGBUS
, sighandler
);
255 signal(SIGFPE
, sighandler
);
256 signal(SIGUSR1
, sighandler
);
257 signal(SIGUSR2
, sighandler
);
258 signal(SIGALRM
, sighandler
);
260 signal(SIGSTKFLT
, sighandler
);
262 signal(SIGTSTP
, sighandler
);
263 signal(SIGXCPU
, sighandler
);
264 signal(SIGXFSZ
, sighandler
);
265 signal(SIGVTALRM
, sighandler
);
267 /* Broken pipes don't want to bother us at all. */
268 signal(SIGPIPE
, SIG_IGN
);
271 /*************************************************************************/
273 /* Redraw everything on the screen. */
275 static void screen_refresh(void)
278 touchline(stdscr
, gmsg_inputpos
, gmsg_inputheight
);
280 touchline(stdscr
, plinebuf
.y
, plinebuf
.height
);
282 touchline(stdscr
, gmsgbuf
.y
, gmsgbuf
.height
);
284 touchline(stdscr
, attdefbuf
.y
, attdefbuf
.height
);
285 wnoutrefresh(stdscr
);
289 /*************************************************************************/
291 /* Like screen_refresh(), but clear the screen first. */
293 static void screen_redraw(void)
295 clearok(stdscr
, TRUE
);
299 /*************************************************************************/
300 /************************* Text buffer routines **************************/
301 /*************************************************************************/
303 /* Put a line of text in a text buffer. */
305 static void outline(TextBuffer
*buf
, const char *s
)
307 if (buf
->line
== buf
->height
) {
310 memmove(buf
->text
, buf
->text
+1, (buf
->height
-1) * sizeof(char *));
314 mvwaddstr(buf
->win
, buf
->line
, 0, s
);
315 if (s
!= buf
->text
[buf
->line
]) /* check for restoring display */
316 buf
->text
[buf
->line
] = strdup(s
);
320 static void draw_text(int bufnum
, const char *s
)
322 char str
[1024]; /* hopefully scrwidth < 1024 */
329 case BUFFER_PLINE
: buf
= &plinebuf
; break;
330 case BUFFER_GMSG
: buf
= &gmsgbuf
; break;
331 case BUFFER_ATTDEF
: buf
= &attdefbuf
; break;
338 attrset(getcolor(COLOR_WHITE
, COLOR_BLACK
));
340 while (*s
&& isspace(*s
))
342 while (strlen(s
) > buf
->width
- indent
) {
343 t
= s
+ buf
->width
- indent
;
344 while (t
>= s
&& !isspace(*t
))
346 while (t
>= s
&& isspace(*t
))
350 t
= s
+ buf
->width
- indent
;
352 sprintf(str
, "%*s", indent
, "");
353 strncpy(str
+indent
, s
, t
-s
);
362 sprintf(str
, "%*s", indent
, "");
363 strcpy(str
+indent
, s
);
371 /*************************************************************************/
373 /* Clear the contents of a text buffer. */
375 static void clear_text(int bufnum
)
381 case BUFFER_PLINE
: buf
= &plinebuf
; break;
382 case BUFFER_GMSG
: buf
= &gmsgbuf
; break;
383 case BUFFER_ATTDEF
: buf
= &attdefbuf
; break;
387 for (i
= 0; i
< buf
->height
; i
++) {
401 /*************************************************************************/
403 /* Restore the contents of the given text buffer. */
405 static void restore_text(TextBuffer
*buf
)
408 while (buf
->line
< buf
->height
&& buf
->text
[buf
->line
])
409 outline(buf
, buf
->text
[buf
->line
]);
412 /*************************************************************************/
414 /* Open a window for the given text buffer. */
416 static void open_textwin(TextBuffer
*buf
)
418 if (buf
->height
<= 0 || buf
->width
<= 0) {
420 move(scrheight
-1, 0);
421 snprintf(str
, sizeof(str
), "ERROR: bad textwin size (%d,%d)",
422 buf
->width
, buf
->height
);
427 buf
->win
= subwin(stdscr
, buf
->height
, buf
->width
, buf
->y
, buf
->x
);
428 scrollok(buf
->win
, TRUE
);
431 buf
->text
= calloc(buf
->height
, sizeof(char *));
436 /*************************************************************************/
438 /* Close the window for the given text buffer, if it's open. */
440 static void close_textwin(TextBuffer
*buf
)
448 /*************************************************************************/
449 /************************ Field drawing routines *************************/
450 /*************************************************************************/
452 /* Are we on a wide screen (>=92 columns)? */
453 static int wide_screen
= 0;
455 /* Field display X/Y coordinates. */
456 static const int own_coord
[2] = {0,0};
457 static int other_coord
[5][2] = /* Recomputed based on screen width */
458 { {30,0}, {47,0}, {64,0}, {47,24}, {64,24} };
460 /* Position of the status window. */
461 static const int status_coord
[2] = {28,25};
462 static const int next_coord
[2] = {40,24};
463 static const int alt_status_coord
[2] = {28,2};
464 static const int alt_next_coord
[2] = {29,8};
466 /* Position of the attacks/defenses window. */
467 static const int attdef_coord
[2] = {28,28};
468 static const int alt_attdef_coord
[2] = {28,24};
470 /* Position of the text window. X coordinate is ignored. */
471 static const int field_text_coord
[2] = {0,47};
473 /* Information for drawing blocks. Color attributes are added to blocks in
474 * the setup_fields() routine. */
475 static int tile_chars
[15] =
476 { ' ','#','#','#','#','#','a','c','n','r','s','b','g','q','o' };
478 /* Are we redrawing the entire display? */
479 static int field_redraw
= 0;
481 /*************************************************************************/
482 /*************************************************************************/
484 /* Set up the field display. */
486 static void draw_own_field(void);
487 static void draw_other_field(int player
);
488 static void draw_status(void);
489 static void draw_specials(void);
490 static void draw_gmsg_input(const char *s
, int pos
);
492 static void setup_fields(void)
494 int i
, j
, x
, y
, base
, delta
, attdefbot
;
497 if (!(tile_chars
[0] & A_ATTRIBUTES
)) {
498 for (i
= 1; i
< 15; i
++)
499 tile_chars
[i
] |= A_BOLD
;
500 tile_chars
[1] |= getcolor(COLOR_BLUE
, COLOR_BLACK
);
501 tile_chars
[2] |= getcolor(COLOR_YELLOW
, COLOR_BLACK
);
502 tile_chars
[3] |= getcolor(COLOR_GREEN
, COLOR_BLACK
);
503 tile_chars
[4] |= getcolor(COLOR_MAGENTA
, COLOR_BLACK
);
504 tile_chars
[5] |= getcolor(COLOR_RED
, COLOR_BLACK
);
508 leaveok(stdscr
, TRUE
);
509 close_textwin(&plinebuf
);
511 attrset(getcolor(COLOR_WHITE
,COLOR_BLACK
));
513 if (scrwidth
>= 92) {
519 delta
= (scrwidth
- base
) / 3;
520 base
+= 2 + (delta
- (FIELD_WIDTH
+5)) / 2;
521 other_coord
[0][0] = base
;
522 other_coord
[1][0] = base
+ delta
;
523 other_coord
[2][0] = base
+ delta
*2;
524 other_coord
[3][0] = base
+ delta
;
525 other_coord
[4][0] = base
+ delta
*2;
527 attdefbot
= field_text_coord
[1] - 1;
528 if (scrheight
- field_text_coord
[1] > 3) {
529 move(field_text_coord
[1], 0);
530 hline(MY_HLINE2
, scrwidth
);
532 if (scrheight
- field_text_coord
[1] > 5) {
533 move(scrheight
-2, 0);
534 hline(MY_HLINE2
, scrwidth
);
536 move(scrheight
-1, 0);
537 addstr("F1=Show Fields F2=Partyline F3=Winlist");
538 move(scrheight
-1, scrwidth
-8);
541 gmsgbuf
.y
= field_text_coord
[1]+1;
542 gmsgbuf
.height
= scrheight
- field_text_coord
[1] - 3;
544 gmsgbuf
.y
= field_text_coord
[1]+1;
545 gmsgbuf
.height
= scrheight
- field_text_coord
[1] - 1;
548 gmsgbuf
.y
= field_text_coord
[1];
549 gmsgbuf
.height
= scrheight
- field_text_coord
[1];
551 gmsgbuf
.x
= field_text_coord
[0];
552 gmsgbuf
.width
= scrwidth
;
553 open_textwin(&gmsgbuf
);
557 sprintf(buf
, "%d", my_playernum
);
558 mvaddstr(y
, x
+FIELD_WIDTH
*2+2, buf
);
559 for (i
= 2; i
< FIELD_HEIGHT
*2 && players
[my_playernum
-1][i
-2]; i
++)
560 mvaddch(y
+i
, x
+FIELD_WIDTH
*2+2, players
[my_playernum
-1][i
-2]);
562 vline(MY_VLINE
, FIELD_HEIGHT
*2);
563 move(y
, x
+FIELD_WIDTH
*2+1);
564 vline(MY_VLINE
, FIELD_HEIGHT
*2);
565 move(y
+FIELD_HEIGHT
*2, x
);
567 hline(MY_HLINE
, FIELD_WIDTH
*2);
568 move(y
+FIELD_HEIGHT
*2, x
+FIELD_WIDTH
*2+1);
570 mvaddstr(y
+FIELD_HEIGHT
*2+2, x
, "Specials:");
574 for (j
= 0; j
< 5; j
++) {
575 x
= other_coord
[j
][0];
576 y
= other_coord
[j
][1];
578 vline(MY_VLINE
, FIELD_HEIGHT
);
579 move(y
, x
+FIELD_WIDTH
+1);
580 vline(MY_VLINE
, FIELD_HEIGHT
);
581 move(y
+FIELD_HEIGHT
, x
);
583 hline(MY_HLINE
, FIELD_WIDTH
);
584 move(y
+FIELD_HEIGHT
, x
+FIELD_WIDTH
+1);
586 if (j
+1 >= my_playernum
) {
587 sprintf(buf
, "%d", j
+2);
588 mvaddstr(y
, x
+FIELD_WIDTH
+2, buf
);
590 for (i
= 0; i
< FIELD_HEIGHT
-2 && players
[j
+1][i
]; i
++)
591 mvaddch(y
+i
+2, x
+FIELD_WIDTH
+2, players
[j
+1][i
]);
593 draw_other_field(j
+2);
595 sprintf(buf
, "%d", j
+1);
596 mvaddstr(y
, x
+FIELD_WIDTH
+2, buf
);
598 for (i
= 0; i
< FIELD_HEIGHT
-2 && players
[j
][i
]; i
++)
599 mvaddch(y
+i
+2, x
+FIELD_WIDTH
+2, players
[j
][i
]);
601 draw_other_field(j
+1);
606 x
= alt_status_coord
[0];
607 y
= alt_status_coord
[1];
608 mvaddstr(y
, x
, "Lines:");
609 mvaddstr(y
+1, x
, "Level:");
610 x
= alt_next_coord
[0];
611 y
= alt_next_coord
[1];
612 mvaddstr(y
-2, x
-1, "Next piece:");
616 mvaddch(y
-1, x
+8, MY_URCORNER
);
624 mvaddch(y
+8, x
+8, MY_LRCORNER
);
628 mvaddstr(y
-1, x
, "Next piece:");
629 mvaddstr(y
, x
, "Lines:");
630 mvaddstr(y
+1, x
, "Level:");
635 attdefbuf
.x
= wide_screen
? alt_attdef_coord
[0] : attdef_coord
[0];
636 attdefbuf
.y
= wide_screen
? alt_attdef_coord
[1] : attdef_coord
[1];
637 attdefbuf
.width
= (other_coord
[3][0]-1) - attdefbuf
.x
;
638 attdefbuf
.height
= (attdefbot
+1) - attdefbuf
.y
;
639 open_textwin(&attdefbuf
);
642 delwin(gmsg_inputwin
);
643 gmsg_inputwin
= NULL
;
644 draw_gmsg_input(NULL
, -1);
651 /*************************************************************************/
653 /* Display the player's own field. */
655 static void draw_own_field(void)
658 Field
*f
= &fields
[my_playernum
-1];
659 int shadow
[4] = { -1, -1, -1, -1 };
661 if (dispmode
!= MODE_FIELDS
)
664 /* XXX: Code duplication with tetris.c:draw_piece(). --pasky */
665 if (playing_game
&& cast_shadow
) {
666 int y
= current_y
- piecedata
[current_piece
][current_rotation
].hot_y
;
667 char *shape
= (char *) piecedata
[current_piece
][current_rotation
].shape
;
670 for (j
= 0; j
< 4; j
++) {
675 for (i
= 0; i
< 4; i
++) {
684 for (y
= 0; y
< 22; y
++) {
685 for (x
= 0; x
< 12; x
++) {
686 int c
= tile_chars
[(int) (*f
)[y
][x
]];
688 if (playing_game
&& cast_shadow
) {
689 PieceData
*piece
= &piecedata
[current_piece
][current_rotation
];
690 int piece_x
= current_x
- piece
->hot_x
;
692 if (x
>= piece_x
&& x
<= piece_x
+ 3
693 && shadow
[(x
- piece_x
)] >= 0
694 && shadow
[(x
- piece_x
)] < y
695 && ((c
& 0x7f) == ' ')) {
696 c
= (c
& (~0x7f)) | '.'
697 | getcolor(COLOR_BLACK
, COLOR_BLACK
) | A_BOLD
;
701 mvaddch(y0
+y
*2, x0
+x
*2, c
);
703 mvaddch(y0
+y
*2+1, x0
+x
*2, c
);
708 delwin(gmsg_inputwin
);
709 gmsg_inputwin
= NULL
;
710 draw_gmsg_input(NULL
, -1);
716 /*************************************************************************/
718 /* Display another player's field. */
720 static void draw_other_field(int player
)
725 if (dispmode
!= MODE_FIELDS
)
727 f
= &fields
[player
-1];
728 if (player
> my_playernum
)
731 x0
= other_coord
[player
][0]+1;
732 y0
= other_coord
[player
][1];
733 for (y
= 0; y
< 22; y
++) {
735 for (x
= 0; x
< 12; x
++) {
736 addch(tile_chars
[(int) (*f
)[y
][x
]]);
740 delwin(gmsg_inputwin
);
741 gmsg_inputwin
= NULL
;
742 draw_gmsg_input(NULL
, -1);
748 /*************************************************************************/
750 /* Display the current game status (level, lines, next piece). */
752 static void draw_status(void)
755 char buf
[32], shape
[4][4];
757 x
= wide_screen
? alt_status_coord
[0] : status_coord
[0];
758 y
= wide_screen
? alt_status_coord
[1] : status_coord
[1];
759 sprintf(buf
, "%d", lines
>99999 ? 99999 : lines
);
760 mvaddstr(y
, x
+7, buf
);
761 sprintf(buf
, "%d", levels
[my_playernum
]);
762 mvaddstr(y
+1, x
+7, buf
);
763 x
= wide_screen
? alt_next_coord
[0] : next_coord
[0];
764 y
= wide_screen
? alt_next_coord
[1] : next_coord
[1];
765 if (get_shape(next_piece
, 0, shape
) == 0) {
766 for (j
= 0; j
< 4; j
++) {
769 for (i
= 0; i
< 4; i
++) {
772 addch(tile_chars
[(int) shape
[j
][i
]]);
773 addch(tile_chars
[(int) shape
[j
][i
]]);
774 move(y
+j
*2+1, x
+i
*2);
775 addch(tile_chars
[(int) shape
[j
][i
]]);
776 addch(tile_chars
[(int) shape
[j
][i
]]);
778 addch(tile_chars
[(int) shape
[j
][i
]]);
784 /*************************************************************************/
786 /* Display the special inventory and description of the current special. */
788 static const char *descs
[] = {
793 "Clear Random Blocks ",
795 "Clear Special Blocks",
801 static void draw_specials(void)
805 if (dispmode
!= MODE_FIELDS
)
809 mvaddstr(y
, x
, descs
[specials
[0]+1]);
812 while (i
< special_capacity
&& specials
[i
] >= 0 && x
< attdef_coord
[0]-1) {
813 addch(tile_chars
[specials
[i
]+6]);
817 while (x
< attdef_coord
[0]-1) {
818 addch(tile_chars
[0]);
825 /*************************************************************************/
827 /* Display an attack/defense message. */
829 static const char *msgs
[][2] = {
830 { "cs1", "1 Line Added to All" },
831 { "cs2", "2 Lines Added to All" },
832 { "cs4", "4 Lines Added to All" },
834 { "c", "Clear Line" },
835 { "n", "Nuke Field" },
836 { "r", "Clear Random Blocks" },
837 { "s", "Switch Fields" },
838 { "b", "Clear Special Blocks" },
839 { "g", "Block Gravity" },
840 { "q", "Blockquake" },
841 { "o", "Block Bomb" },
845 static void draw_attdef(const char *type
, int from
, int to
)
850 width
= other_coord
[4][0] - attdef_coord
[0] - 1;
851 for (i
= 0; msgs
[i
][0]; i
++) {
852 if (strcmp(type
, msgs
[i
][0]) == 0)
857 strcpy(buf
, msgs
[i
][1]);
859 sprintf(buf
+strlen(buf
), " on %s", players
[to
-1]);
861 sprintf(buf
+strlen(buf
), " by Server");
863 sprintf(buf
+strlen(buf
), " by %s", players
[from
-1]);
864 draw_text(BUFFER_ATTDEF
, buf
);
867 /*************************************************************************/
869 /* Display the in-game text window. */
871 static void draw_gmsg_input(const char *s
, int pos
)
873 static int start
= 0; /* Start of displayed part of input line */
874 static const char *last_s
;
886 attrset(getcolor(COLOR_WHITE
,COLOR_BLACK
));
888 if (!gmsg_inputwin
) {
889 gmsg_inputpos
= scrheight
/2 - 1;
890 gmsg_inputheight
= 3;
892 subwin(stdscr
, gmsg_inputheight
, scrwidth
, gmsg_inputpos
, 0);
893 werase(gmsg_inputwin
);
894 leaveok(gmsg_inputwin
, FALSE
);
895 leaveok(stdscr
, FALSE
);
896 mvwaddstr(gmsg_inputwin
, 1, 0, "Text>");
899 if (strlen(s
) < scrwidth
-7) {
901 mvwaddstr(gmsg_inputwin
, 1, 6, s
);
902 wmove(gmsg_inputwin
, 1, 6+strlen(s
));
903 move(gmsg_inputpos
+1, 6+strlen(s
));
904 wclrtoeol(gmsg_inputwin
);
905 wmove(gmsg_inputwin
, 1, 6+pos
);
906 move(gmsg_inputpos
+1, 6+pos
);
912 } else if (pos
> start
+ scrwidth
-15) {
913 start
= pos
- (scrwidth
-15);
914 if (start
> strlen(s
) - (scrwidth
-7))
915 start
= strlen(s
) - (scrwidth
-7);
917 mvwaddnstr(gmsg_inputwin
, 1, 6, s
+start
, scrwidth
-6);
918 wmove(gmsg_inputwin
, 1, 6 + (pos
-start
));
919 move(gmsg_inputpos
+1, 6 + (pos
-start
));
924 /*************************************************************************/
926 /* Clear the in-game text window. */
928 static void clear_gmsg_input(void)
931 delwin(gmsg_inputwin
);
932 gmsg_inputwin
= NULL
;
933 leaveok(stdscr
, TRUE
);
934 touchline(stdscr
, gmsg_inputpos
, gmsg_inputheight
);
940 /*************************************************************************/
941 /*************************** Partyline display ***************************/
942 /*************************************************************************/
944 static void setup_partyline(void)
946 close_textwin(&gmsgbuf
);
947 close_textwin(&attdefbuf
);
950 attrset(getcolor(COLOR_WHITE
,COLOR_BLACK
));
952 plinebuf
.x
= plinebuf
.y
= 0;
953 plinebuf
.width
= scrwidth
;
954 plinebuf
.height
= scrheight
-4;
955 open_textwin(&plinebuf
);
957 move(scrheight
-4, 0);
958 hline(MY_HLINE
, scrwidth
);
959 move(scrheight
-3, 0);
962 move(scrheight
-2, 0);
963 hline(MY_HLINE2
, scrwidth
);
965 move(scrheight
-1, 0);
966 addstr("F1=Show Fields F2=Partyline F3=Winlist");
967 move(scrheight
-1, scrwidth
-8);
971 move(scrheight
-3, 2);
972 leaveok(stdscr
, FALSE
);
976 /*************************************************************************/
978 static void draw_partyline_input(const char *s
, int pos
)
980 static int start
= 0; /* Start of displayed part of input line */
982 attrset(getcolor(COLOR_WHITE
,COLOR_BLACK
));
983 if (strlen(s
) < scrwidth
-3) {
985 mvaddstr(scrheight
-3, 2, s
);
986 move(scrheight
-3, 2+strlen(s
));
988 move(scrheight
-3, 2+pos
);
994 } else if (pos
> start
+ scrwidth
-11) {
995 start
= pos
- (scrwidth
-11);
996 if (start
> strlen(s
) - (scrwidth
-3))
997 start
= strlen(s
) - (scrwidth
-3);
999 mvaddnstr(scrheight
-3, 2, s
+start
, scrwidth
-2);
1000 move(scrheight
-3, 2 + (pos
-start
));
1005 /*************************************************************************/
1006 /**************************** Winlist display ****************************/
1007 /*************************************************************************/
1009 static void setup_winlist(void)
1014 leaveok(stdscr
, TRUE
);
1015 close_textwin(&plinebuf
);
1017 attrset(getcolor(COLOR_WHITE
,COLOR_BLACK
));
1019 for (i
= 0; i
< MAXWINLIST
&& *winlist
[i
].name
; i
++) {
1020 x
= scrwidth
/2 - strlen(winlist
[i
].name
);
1023 if (winlist
[i
].team
) {
1026 mvaddstr(i
*2, x
-4, "<T>");
1028 mvaddstr(i
*2, x
, winlist
[i
].name
);
1029 snprintf(buf
, sizeof(buf
), "%4d", winlist
[i
].points
);
1030 if (winlist
[i
].games
) {
1031 int avg100
= winlist
[i
].points
*100 / winlist
[i
].games
;
1032 snprintf(buf
+strlen(buf
), sizeof(buf
)-strlen(buf
),
1033 " %d.%02d",avg100
/100, avg100
%100);
1035 x
+= strlen(winlist
[i
].name
) + 2;
1036 if (x
> scrwidth
- strlen(buf
))
1037 x
= scrwidth
- strlen(buf
);
1038 mvaddstr(i
*2, x
, buf
);
1041 move(scrheight
-2, 0);
1042 hline(MY_HLINE2
, scrwidth
);
1044 move(scrheight
-1, 0);
1045 addstr("F1=Show Fields F2=Partyline F3=Winlist");
1046 move(scrheight
-1, scrwidth
-8);
1053 /*************************************************************************/
1054 /************************** Interface declaration ************************/
1055 /*************************************************************************/
1057 Interface tty_interface
= {
1078 draw_partyline_input
,
1083 /*************************************************************************/