/* virtual terminals - WA */ /* updated Zilanthius 1994 */ #include <std.h> #include <string.h> #include <memory.h> #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <dos.h> #include <pc.h> #include <go32.h> #include "../../config.h" #include "../../patchlevel.h" #include "pcdef.h" #include "c_msdos.h" #include "version.h" #include "color.h" typedef unsigned short CHAR; #define WIDTH 80 #define LINES ScreenRows() #define CONSOLES 10 #define STATUS_LINE (LINES-2) #define PAGE (WIDTH*LINES) #define PAGE0 (WIDTH*(LINES-1)) #define PAGE1 (WIDTH*(LINES-2)) #define PAGE2 (WIDTH*(LINES-3)) #define SHIFT (4*PAGE0) #define BUFFER 25000 #define ANSI_BUFFER 20 #define LINE_BUFFER WIDTH #define HISTORY_BUFFER 2000 #define HISTORY_SHIFT 500 #define TAB_WIDTH 7 #define KBD_QUEUE 256 /* Keyboard Codes */ #define F1 315 #define F10 324 #define PgUp 329 #define PgDn 337 #define CrsrUp 328 #define CrsrDn 336 #define CrsrLt 331 #define CrsrRt 333 #define Home 327 #define End 335 #define AltH 291 #define AltS 287 #define AltE 274 #define AltF 289 #define AltM 306 #define AltX 301 #define AltZ 300 #define DEL 339 #define INS 338 #define SHIFT_TAB 271 #define CTRL_BS 127 #define SPACE 32 #define ESC 27 #define CTRL_M 13 /* cr */ #define CTRL_J 10 /* lf */ #define TAB 9 #define BS 8 #define CTRL_G 7 #define IS_PRINT(X) (X >= 0x20 && X <= 0x7e) #define IS_INT(X) (X >= 0x30 && X <= 0x39) #define ZERO 0x30 #define ANSI_COLON 0x3b #define ANSI_M 0x6d #define ANSI_BRACKET 0x5b #define error(c) { c_errno = (c); return -1; } struct v_con { int echo,connected,ready,x; CHAR buffer[BUFFER+1], *top, *end, *screen; CHAR ansi_buffer[ANSI_BUFFER+1], ansi_ptr; CHAR line_buffer[LINE_BUFFER+1], *line_ptr; CHAR color; } console[CONSOLES]; static unsigned video_address = 0xb8000UL; static int current, hangup; static CHAR bar_attrib; static CHAR scroll; static CHAR kbd_queue[KBD_QUEUE+1]; static CHAR *queue_end = kbd_queue; static CHAR special = 0; static CHAR history_buffer[HISTORY_BUFFER+1]; static CHAR *current_ptr = history_buffer; static CHAR *history_ptr = history_buffer; static CHAR *history_end = history_buffer; /* prototypes */ static void spawn(); static void sys_editor(); static void sys_filemanager(); static void show_help(); static void beep(); static void page(); static void reset_page(); static void scan_kbd(); static CHAR wait_key(); static CHAR poll_key(); static CHAR get_special(); static CHAR any_key(); static CHAR *my_atoi(); static CHAR select_color(); static void init_display(); static void clear_display(); static int scrolling(); static void dsp_crlf(); static void dsp_bs(); static void dsp_tab(); static void status(); static void activate_console(); static void check_inactive(); static int access_console(); void vc_listen(); static int vc_read(); static int vc_write(int,char); int vc_accept(); int vc_select(); static int vc_close(); static void vc_echo(); void vc_init(); void vc_shutdown(); static void init_buffers(); static void close_buffers(); static void shift_buffer(); static void append_buffer(); static void buffer_display(); static void display_screen(); static void clear_line_buffer(); static void append_line_buffer(); static void clear_ansi_buffer(); static void move_ansi_buffer(); static CHAR ansi_type(); static void set_ansi(); static void ansi_color(); static void toggle_video_mode(); /************************************************************************/ /* Bell */ static void beep() { sound(2500); usleep(400); sound(0); } /***********************************************************************/ /* DOS shell escape */ extern char *mud_lib; static void spawn() { int out,x; if (getenv("COMSPEC") == NULL) return; ScreenClear(); ScreenSetCursor(0,0); out = dup(1); /* 'cause stdout is usually redirected to a log file */ dup2(2,1); system(getenv("COMSPEC")); dup2(out,1); close(out); chdir(mud_lib); activate_console(current); } /**********************************************************************/ /* system editor */ static void sys_editor() { if (getenv("MUD_EDITOR") == NULL) return; system(getenv("MUD_EDITOR")); chdir(mud_lib); activate_console(current); } /**************************************************************************/ /* system file manager */ static void sys_filemanager() { if (getenv("MUD_FILEMANAGER") == NULL) return; system(getenv("MUD_FILEMANAGER")); chdir(mud_lib); activate_console(current); } /*************************************************************************/ /* command history */ static int prev_history(); static void walk_history() { CHAR *ptr; ptr = history_buffer + HISTORY_SHIFT; while(*ptr++); current_ptr -= ptr - history_buffer; for(history_ptr = history_buffer; ptr < history_buffer + HISTORY_BUFFER;) { *history_ptr++ = *ptr++; } while(history_ptr < history_buffer + HISTORY_BUFFER) *history_ptr++ = 0; history_ptr = current_ptr; history_end = history_buffer; prev_history(); } static int next_history() { CHAR *ptr; for(ptr = history_ptr;ptr < history_buffer + HISTORY_BUFFER && *ptr++;); if(ptr != history_buffer + HISTORY_BUFFER && *ptr) { history_ptr = ptr; return 1; } return 0; } static int prev_history() { CHAR *ptr; int flag = 1; if((ptr = history_ptr) != history_end) { do { while(ptr > history_end && *--ptr); } while(flag--); if(ptr != history_end) ptr++; if(*ptr) { history_ptr = ptr; return 1; } } return 0; } static void show_history() { int i; CHAR buf[WIDTH]; CHAR *ptr; for(i = 0, ptr = history_ptr; i < WIDTH && *ptr; i++) { if((*ptr & 0xff) == TAB) { do { buf[i++] = SPACE; } while(i < WIDTH && (i & TAB_WIDTH)); } else { buf[i] = *ptr++; } } while(i < WIDTH) buf[i++] = SPACE; buffer_display(buf,WIDTH,PAGE0); } static void clean_history() { CHAR *ptr = history_buffer; CHAR *cmd = history_ptr; CHAR *ptr2; while(ptr < cmd) { while(*ptr++ == *cmd++) { if(!*ptr && !*cmd) { ptr2 = ptr; while(ptr > history_buffer && *--ptr); while(ptr > history_buffer) *--ptr2 = *--ptr; history_end = ptr2; while(ptr2 > history_buffer) *--ptr2 = 0; goto end_clean; } } cmd = history_ptr; while(*ptr++); } end_clean: } static void insert_history() { CHAR *ptr, ch; ptr = history_ptr; reset_page(); if(!*ptr) { beep(); } else { for(;(ch = *ptr & 0xff) && ch != CTRL_J; ptr++) { *queue_end++ = ch; if(queue_end - kbd_queue == KBD_QUEUE) { beep(); beep(); break; } } } } static void append_history(key) int key; { if(current_ptr == history_buffer + HISTORY_BUFFER - 1) walk_history(); if(IS_PRINT(key) || key == TAB) key |= FG_G | FG_R | FG_B | FG_I; else if(current_ptr == history_buffer || *(current_ptr-1) == 0) return; else key = 0; if(!(*current_ptr++ = key)) { history_ptr = current_ptr; prev_history(); clean_history(); show_history(); } } static void bs_history() { if(current_ptr == history_buffer) return; if(*(current_ptr-1)) *--current_ptr = 0; } /**************************************************************************/ /* keyboard input queue handler */ static void scan_kbd() { CHAR key; CHAR *walk; while (kbhit()) { if ((key = getkey()) == DEL || key == CTRL_BS) key = BS; if (key == SHIFT_TAB) key = TAB; if (key == CTRL_M) key = CTRL_J; if (key >= 256) { switch (key) { case AltH: hangup = 1; break; case AltS: spawn(); break; case AltE: sys_editor(); break; case AltF: sys_filemanager(); break; case AltM: toggle_video_mode(); break; case AltX: shutdowngame(); break; case AltZ: show_help(); break; case PgUp: case PgDn: case CrsrUp: case CrsrDn: case Home: case End: page(key); break; case CrsrRt: if (!next_history()) beep(); show_history(); break; case CrsrLt: if (!prev_history()) beep(); show_history(); break; case INS: insert_history(); return; default: reset_page(); if (special) { beep(); } else { special = key; } } /* end switch */ } /* end if key >= 256 */ else { /* now insert key in buffer */ reset_page(); if ((queue_end - kbd_queue) == KBD_QUEUE) { beep(); /* buffer full */ } else { *queue_end++ = key; } } } /* end while kbhit() */ } static CHAR wait_key() { CHAR *walk, key; do { scan_kbd(); } while (queue_end == kbd_queue); /* take first char out of queue */ key = *kbd_queue; for (walk = kbd_queue; walk < queue_end; walk++) *walk = *(walk + 1); queue_end--; return key; } static CHAR poll_key() { scan_kbd(); return (queue_end == kbd_queue) ? 0 : *kbd_queue; } static CHAR get_special() { CHAR key; key = special; special = 0; return key; } static CHAR any_key() { return special ? special : poll_key(); } /**************************************************************************/ /* console handling */ static void activate_console(number) int number; { init_display(number); clear_display(console[number].color); current = number; if (console[current].buffer == NULL) { status(current, "UNAVAILABLE", 0); return; } display_screen(current); if (console[current].connected) { status(current, "CONNECTED", 0); } else { status(current, "AVAILABLE", 0); } } static void check_inactive() { CHAR key; if (console[current].ready || console[current].connected || !any_key()) return; while (key = get_special()) if (key >= F1 && key <= F10) activate_console(key - F1); if (poll_key()) { wait_key(); /* removes one key from queue */ console[current].ready = 1; } } static int access_console(int vcon) { if (vcon < 0 || vcon >= CONSOLES) { fprintf(stderr, "\nERROR: invalid console #%d\n", vcon); error(ECOMUSG); } if (console[vcon].connected) return 0; /* warning? and then raise an error? */ fprintf(stderr, "\nWARNING: accessing inactive console #%d\n", vcon); error(ECOMUSG); } void vc_listen() { init_buffers(); activate_console(0); hangup = 0; } static int vc_write2(int vcon, char *msg, int len) { if (access_console(vcon) < 0) error(ECOMUSG); while (len--) vc_write(vcon, *msg++); return 1; } static int vc_write(int vcon, char ch) { switch (ch) { case '\n': dsp_crlf(vcon); break; case '\t': dsp_tab(vcon); break; case '\b': dsp_bs(vcon); break; case '\a': beep(); break; default : if (IS_PRINT(ch) || ch == ESC) { append_line_buffer(vcon, (CHAR) ch); } } return 1; } static int vc_read(int vcon, char *data, int length) { int count; CHAR key; char tmp[6]; int ansi; if (access_console(vcon) < 0) error(ECOMUSG); if (current != vcon) { if (poll_key() && !console[current].connected) { console[current].ready = 1; } return 0; } if (hangup) { hangup = 0; return 0; } for (count = 0; count < length && poll_key(); count++) { key = wait_key(); if (console[vcon].echo) { switch (key) { case CTRL_J: strcpy(tmp, "\n"); break; case BS: strcpy(tmp, "\b \b"); break; default: if (!IS_PRINT(key) && key != ESC && key != CTRL_G) { sprintf(tmp, "<%d>", key); } else { sprintf(tmp, "%c", key); } } vc_write2(vcon, tmp, strlen(tmp)); if (IS_PRINT(key) || key == CTRL_J || key == TAB) { append_history(key); } else if (key == BS) { bs_history(); } } *data++ = (char)key; } return count; } int vc_accept() { int vcon; check_inactive(); for (vcon = 0; vcon < CONSOLES; vcon++) if (console[vcon].ready) { console[vcon].connected = console[vcon].echo = 1; console[vcon].ready = 0; status(vcon, "CONNECTED", 0); return vcon; } /* error(ECOMFLW); change to non fatal error code */ error(EAGAIN); } /*ARGSUSED*/ int vc_select(mask, timeout, new_con) int *mask; struct timeval *timeout; int *new_con; { int vcon, copy, key; /* * get_special can't return more than one special * without re-reading the keyboard - hohum */ while (key = get_special()) if (key >= F1 && key <= F10) activate_console(key-F1); if (console[current].buffer && poll_key()) { /* look for new connections */ if (*new_con && !console[current].connected) { console[current].ready = 1; *mask = 0; return 1; } *new_con = 0; /* see if there is input from current console (a connection) */ if (console[current].connected && ((*mask >> current) & 1)) { *mask = 1 << current; return 1; } } /* to-do: read comm1.c and decide how to return.. */ error(EINTR); } static int vc_close(int vcon) { if (access_console(vcon) < 0) error(ECOMUSG); console[vcon].connected = 0; status(vcon, "AVAILABLE",0); return 0; } static void vc_echo(int vcon, int mode) { if (access_console(vcon) >= 0) console[vcon].echo = mode; } void vc_init(CLASS_DEF *cd) { vc_listen(); cd->max_sess = CONSOLES; cd->close = vc_close; cd->read = vc_read; cd->write = vc_write; cd->echo = vc_echo; } void vc_shutdown() { printf("\n[DETACHED]\n"); ScreenSetCursor(0,0); ScreenClear(); } /*************************************************************************/ static CHAR *my_atoi(value,str) CHAR *value; CHAR *str; { while (*str && !IS_INT(*str)) str++; for (*value = 0; IS_INT(*str); str++) *value = *value*10 + *str-ZERO; return str; } /*********************************************************************/ /* set color attributes */ static CHAR select_color(color) char *color; { CHAR attrib = 0; do { switch(*color) { case 'r': attrib |= FG_R; break; case 'g': attrib |= FG_G; break; case 'b': attrib |= FG_B; break; case 'R': attrib |= BG_R; break; case 'G': attrib |= BG_G; break; case 'B': attrib |= BG_B; break; case 'i': attrib |= FG_I; break; case 'f': attrib |= BLINK; break; } } while(*++color); return attrib; } /********************************************************************/ /* initialise */ static void init_display(int vcon) { char mono[] = "mono"; if (getenv("MUD_MODE") != NULL && strcmp(getenv("MUD_MODE"), mono) == 0) { video_address = 0xb0000UL; console[vcon].color = 0x0700; bar_attrib = 0x70; } else { video_address = 0xb8000UL; if (getenv("MUD_SCREEN") != NULL) { console[vcon].color = select_color(getenv("MUD_SCREEN")); } else { console[vcon].color = FG; } if (getenv("MUD_BAR") != NULL) { bar_attrib = select_color(getenv("MUD_BAR")) >> 8; } else { bar_attrib = BG >> 8; } } } static void init_buffers() { int con = CONSOLES; int i; while (con--) { console[con].connected = console[con].ready = console[con].x = 0; console[con].top = console[con].screen = console[con].buffer; console[con].end = console[con].buffer + PAGE1; init_display(con); for (i = 0; i < BUFFER; i++) { console[con].buffer[i] = (SPACE | console[con].color); } clear_line_buffer(con); } memset(history_buffer, 0, sizeof(history_buffer)); show_history(); } static void shift_buffer(int vcon) { int i; if ((console[vcon].end - console[vcon].buffer) >= BUFFER - PAGE) { for (i = 0; i + SHIFT < BUFFER && console[vcon].buffer[i+SHIFT]; i++) { console[vcon].buffer[i] = console[vcon].buffer[i+SHIFT]; } while(i < BUFFER) console[vcon].buffer[i++] = ((SPACE & 0xff) | console[vcon].color); console[vcon].end -= SHIFT; console[vcon].top = console[vcon].end - PAGE2; console[vcon].buffer[BUFFER] = 0; } } static void append_buffer(int vcon, CHAR *ptr) { for (;*ptr; ptr++) { shift_buffer(vcon); *console[vcon].end++ = *ptr; } while ((console[vcon].end - console[vcon].buffer)%WIDTH) { shift_buffer(vcon); *console[vcon].end++ = (SPACE | console[vcon].color); } console[vcon].top = console[vcon].end - PAGE2; } static int scrolling() { if(scroll) { scroll = (scroll != '*') ? '*' : '#'; ScreenPutChar(scroll, bar_attrib, WIDTH - 2, STATUS_LINE); return 1; } return 0; } static void dsp_crlf(int vcon) { if (!console[vcon].line_buffer[0]) { console[vcon].line_buffer[0] = (SPACE | console[vcon].color); } append_buffer(vcon, console[vcon].line_buffer); clear_line_buffer(vcon); if (current == vcon) { if (!scrolling()) display_screen(vcon); } } static void dsp_bs(con) int con; { if (!console[con].x) { beep(); return; } *--console[con].line_ptr = 0; if (con == current) ScreenSetCursor(STATUS_LINE-1,--console[con].x); } static void dsp_tab(con) int con; { int length; for(length = 0; console[con].line_buffer[length]; length++); if(length >= WIDTH-2-TAB_WIDTH) { dsp_crlf(con); } else { do { append_line_buffer(con,SPACE); } while (++length & TAB_WIDTH); } } static void display_line_buffer(con) int con; { int i; CHAR buf[LINE_BUFFER]; for (i = 0; i < LINE_BUFFER && console[con].line_buffer[i]; i++) { buf[i] = console[con].line_buffer[i]; } console[con].x = i%WIDTH; ScreenSetCursor(STATUS_LINE - 1, console[con].x); while (i < LINE_BUFFER) buf[i++] = SPACE | console[con].color; buffer_display(buf,LINE_BUFFER,PAGE2); } static void display_screen(con) int con; { buffer_display(console[con].top,PAGE2,0); console[con].x = 0; ScreenSetCursor(STATUS_LINE-1,0); display_line_buffer(con); status(con,((console[con].connected) ? "CONNECTED" : "AVAILABLE"),0); } static void clear_line_buffer(con) int con; { int i = LINE_BUFFER; console[con].line_ptr = console[con].line_buffer; while(i--) console[con].line_buffer[i] = 0; console[con].x = 0; } static void append_line_buffer(con,ch) int con; CHAR ch; { if(!console[con].ansi_ptr) { if(ch == ESC) { console[con].ansi_buffer[console[con].ansi_ptr++] = ESC; return; } else { *console[con].line_ptr++ = ch | console[con].color; } } else { if(console[con].ansi_ptr + 1 == ANSI_BUFFER) { move_ansi_buffer(con); return; } console[con].ansi_buffer[console[con].ansi_ptr++] = ch; switch(console[con].ansi_ptr) { case 2: if(ch != ANSI_BRACKET) { move_ansi_buffer(con); } break; case 3: if(!IS_INT(ch)) { move_ansi_buffer(con); } break; default: if(!IS_INT(ch) && ch != ANSI_COLON && ch != ANSI_M) { move_ansi_buffer(con); } else if(ch == ANSI_M) { set_ansi(con,console[con].ansi_buffer); clear_ansi_buffer(con); } } return; } if(console[con].x >= WIDTH-1) { append_buffer(con,console[con].line_buffer); clear_line_buffer(con); if(con == current) { ScreenSetCursor(STATUS_LINE-1,0); if(!scrolling()) display_screen(con); } } else if(current == con) { if(!scroll) { ScreenPutChar(ch,console[con].color>>8,console[con].x,STATUS_LINE-1); } ScreenSetCursor(STATUS_LINE-1,++console[con].x); } } /* ansi simulation */ static void clear_ansi_buffer(con) int con; { int i = ANSI_BUFFER; console[con].ansi_ptr = 0; while(i--) console[con].ansi_buffer[i] = 0; } static void move_ansi_buffer(con) int con; { CHAR *ptr; for(ptr = console[con].ansi_buffer;*ptr; ptr++, console[con].x++) { if(console[con].x >= WIDTH-1) { append_buffer(con,console[con].line_buffer); clear_line_buffer(con); } *console[con].line_ptr++ = *ptr | console[con].color; } if(current == con) ScreenSetCursor(STATUS_LINE-1,console[con].x); clear_ansi_buffer(con); if(current == con) display_screen(con); } static CHAR ansi_type(str) CHAR *str; { while(*str == ANSI_COLON || IS_INT(*str)) *str++; return *str; } static void set_ansi(con,ptr) int con; CHAR *ptr; { CHAR attrib; if(*ptr == ESC && *(ptr+1) == ANSI_BRACKET && IS_INT(*(ptr+2))) { switch(ansi_type(ptr+2)) { case ANSI_M: *ptr++; while(*ptr++ != ANSI_M) { ptr = my_atoi(&attrib,ptr); ansi_color(con,attrib); } break; } } } static void ansi_color(con,attrib) int con; CHAR attrib; { switch(attrib) { /* OFF */ case 0: init_display(con); break; /* BOLD */ case 1: if(getenv("MUD_BOLD") != NULL) { console[con].color = select_color(getenv("MUD_BOLD")); } else { console[con].color |= FG_I; } break; /* FAINT */ case 2: console[con].color &= ~FG_I; break; /* underline mono display only */ case 4: console[con].color |= FG_B; break; /* BLINK */ case 5: console[con].color |= BLINK; break; /* REVERSE BLINK */ case 6: console[con].color = ~console[con].color; console[con].color |= BLINK; break; /* REVERSE */ case 7: console[con].color = ~console[con].color; console[con].color &= ~BLINK; break; /* foreground * case 30: /* black */ console[con].color &= ~FG_R & ~FG_G & ~FG_B; break; case 31: /* red */ console[con].color &= ~FG_R & ~FG_G & ~FG_B; console[con].color |= FG_R; break; case 32: /* green */ console[con].color &= ~FG_R & ~FG_G & ~FG_B; console[con].color |= FG_G; break; case 33: /* yellow */ console[con].color &= ~FG_R & ~FG_G & ~FG_B; console[con].color |= FG_R | FG_G; break; case 34: /* blue */ console[con].color &= ~FG_R & ~FG_G & ~FG_B; console[con].color |= FG_B; break; case 35: /* magenta */ console[con].color &= ~FG_R & ~FG_G & ~FG_B; console[con].color |= FG_R | FG_B; break; case 36: /* cyan */ console[con].color &= ~FG_R & ~FG_G & ~FG_B; console[con].color |= FG_G | FG_B; break; case 37: /* white */ console[con].color |= FG_R | FG_G | FG_B; break; /* Background */ case 40: /* black */ console[con].color &= ~BG_R & ~BG_G & ~BG_B; break; case 41: /* red */ console[con].color &= ~BG_R & ~BG_G & ~BG_B; console[con].color |= BG_R; break; case 42: /* green */ console[con].color &= ~BG_R & ~BG_G & ~BG_B; console[con].color |= BG_G; break; case 43: /* yellow */ console[con].color &= ~BG_R & ~BG_G & ~BG_B; console[con].color |= BG_R | BG_G; break; case 44: /* blue */ console[con].color &= ~BG_R & ~BG_G & ~BG_B; console[con].color |= BG_B; break; case 45: /* magenta */ console[con].color &= ~BG_R & ~BG_G & ~BG_B; console[con].color |= BG_R | BG_B; break; case 46: /* cyan */ console[con].color &= ~BG_R & ~BG_G & ~BG_B; console[con].color |= BG_G | BG_B; break; case 47: /* white */ console[con].color |= BG_R | BG_G | BG_B; break; } } /* clear screen */ static void clear_display(color) CHAR color; { int i; CHAR buf[PAGE1]; for (i = 0; i < PAGE1; i++) buf[i] = SPACE | color; dosmemput(buf, PAGE1*2, video_address); } /* display buffer */ static void buffer_display(buf, length, screen_offset) CHAR *buf; int length; int screen_offset; { if (length + screen_offset > PAGE) length = PAGE - screen_offset; dosmemput(buf, length*2, video_address + 2*screen_offset); } /***************************************************************************/ /* status bar */ static void status(number, st_name, scroll) int number,scroll; short int *st_name; { char msg[WIDTH]; int walk; char mode[7]; sprintf(msg, " #%d [%s]%s MSDOS %s Amylaar%s%s %s Driver (Help: Alt-Z) ", number+1, st_name, scroll ? "SCROLLED" : "", MSDOS_VERSION, GAME_VERSION, PATCH_LEVEL LOCAL_LEVEL, /* if X-Comp was written as X-Compat the below would cause something to malfunction. stack would get overwritten and other nice things */ #ifdef COMPAT_MODE strcpy(mode,"Compat")); #else #ifdef NATIVE_MODE strcpy(mode,"Native")); #else strcpy(mode,"X-Comp")); #endif /* NATIVE_MODE */ #endif /* COMPAT_MODE */ for (walk = 0; msg[walk]; walk++) { ScreenPutChar(msg[walk],bar_attrib,walk,STATUS_LINE); } while(walk < WIDTH) { ScreenPutChar(SPACE,bar_attrib,walk++,STATUS_LINE); } } /**************************************************************************/ /* help */ static void show_help() { int attrib, i, x_pos, y_pos; char help[] = \ " -=[ Help ]=-\n\n" " Alt-h........Hang Up\n"\ " Alt-s........Spawn\n"\ " Alt-e........Dos Editor\n"\ " Alt-f........Dos File Manager\n"\ " Alt-m........Toggle Video Mode\n"\ " Alt-x........Shutdown Game\n"\ " Alt-z........Help\n"\ " F1-F10.......Virtual Consoles\n"\ " <home>.......Top of Screen Buffer\n"\ " <end>........End of Screen Buffer\n"\ " < ->, <- >...History Buffer\n"\ " <Insert>.....Insert Current History Line\n"\ "Press Key to Continue."; if (getenv("MUD_SCREEN") != NULL) { attrib = select_color(getenv("MUD_SCREEN")); } else { attrib = FG; } clear_display(attrib); for(i = 0, x_pos = 0, y_pos = 0; i < strlen(help); i++) { if(help[i] == '\n') { y_pos++; x_pos = 0; } else { ScreenPutChar(help[i],attrib >> 8,x_pos++,y_pos); } } ScreenSetCursor(y_pos,x_pos++); wait_key(); activate_console(current); } /* page movement */ static void page(key) CHAR key; { CHAR *ptr; if (!scroll) scroll = '#'; ScreenPutChar(scroll, bar_attrib, WIDTH - 2, STATUS_LINE); ptr = console[current].screen; switch (key) { case PgUp: if (ptr - PAGE1 < console[current].buffer) ptr = console[current].buffer; else ptr -= PAGE1; break; case CrsrUp: if (ptr - WIDTH < console[current].buffer) ptr = console[current].buffer; else ptr -= WIDTH; break; case PgDn: if (ptr + PAGE1 > console[current].top) ptr = console[current].top; else ptr += PAGE1; break; case CrsrDn: if (ptr + WIDTH > console[current].top) ptr = console[current].top; else ptr += WIDTH; break; case End: ptr = console[current].top; break; case Home: ptr = console[current].buffer; break; } console[current].screen = ptr; buffer_display(ptr, PAGE1, 0); } /* reset page */ static void reset_page() { scroll = 0; ScreenPutChar(SPACE,bar_attrib,WIDTH-2,STATUS_LINE); if (console[current].screen != console[current].top) { console[current].screen = console[current].top; display_screen(current); } } /********************************************************************/ /* video mode */ /* from gppconio src */ enum text_modes { LASTMODE=-1, BW40=0, C40, BW80, C80, MONO=7, C4350=64 }; void toggle_video_mode() { union REGS regs; static int mode = C4350; int mode_to_set; regs.h.ah = 0x12; regs.h.bl = 0x10; regs.h.bh = 0xff; int86(0x10, ®s, ®s); if(regs.h.bh == 0xff) return; /* mono */ if(mode == C4350) mode = C80; else mode = C4350; mode_to_set = mode; if (mode == C4350) /* * just set mode 3 and load 8x8 font, idea taken * (and code translated from Assembler to C) * form Csaba Biegels stdvga.asm */ mode_to_set = 0x03; regs.h.ah = 0x00; /* set mode */ regs.h.al = mode_to_set; int86(0x10, ®s, ®s); /* * enable cursor size emulation, see Ralf Browns * interrupt list */ regs.h.ah = 0x12; regs.h.bl = 0x34; regs.h.al = 0x00; /* 0: enable (1: disable) */ int86(0x10, ®s, ®s); if (mode == C4350) { /* load 8x8 font */ regs.x.ax = 0x1112; regs.x.bx = 0; int86(0x10, ®s, ®s); } display_screen(current); }