1
/* os_msdos.c -- interface routines for MS-DOS */
2
/* Copyright (C) 1996,1997,1998 Robert Masenten */
4
/* This is part of the source for the (Mostly) Universal */
7
/* This has been written to work under Borland C (MSDOS16)
8
and DJGPP (MSDOS32); it hasn't been tested with other compilers. */
10
/* NOTE: The library functions for screen location put the origin
11
at (1,1), but curr_x, curr_y, box_startx, and box_starty have
16
/* What needs work for 32-bit case:
23
pictcmd(): Save/restore of text mode video memory
24
setup_card(): Setting video-mode palette
28
#define DEBUG_KEY 0 /* Turns on debugging of key functions */
48
#define outp(p,d) outportb(p,d)
51
#define cleareol rclreol
54
rbool use_bios; /* If true, use the BIOS routines for text output.
55
(for the sake of blind users.) */
57
static int colorset[5]={7,14,0,15,1};
60
/* cs_ stands for "color scheme" */
61
enum {cs_normal=0, cs_bold, cs_back, cs_statfore, cs_statback} color_scheme;
62
/* normal/highlight/background/statfore/statback */
64
int scroll_count; /* Count of how many lines we have printed since
68
int top_row; /* The absolute y value of the current top row. */
70
static char *gamefile_name;
71
static rbool font_enable;
72
static rbool nav_arrow;
73
static rbool block_cursor;
74
static rbool tall_screen; /* 43/50 line mode? */
76
static char *active_font; /* Currently active font; NULL if none */
77
static int active_font_height;
79
typedef enum {MDA,CGA,MCGA,EGA64,EGA,VGA} gh_type;
80
static gh_type graph_hardware;
83
static char *fkey_text[24]={ /* Text for function keys */
88
"inventory\n","look\n",
92
"w\n","e\n","n\n","s\n",
93
"nw\n","sw\n","ne\n","se\n",
94
"enter\n","up\n","down\n"
104
"inventory\n","look\n",
106
"save\n","restore\n"};
117
/*------------------------------------------------------------------*/
118
/* 32-bit library Compatibility Layer */
119
/*------------------------------------------------------------------*/
121
/* Internal coordinates have an origin of (0,0), even though the
122
calling coordinates are (1,1). */
124
#define rgettextinfo gettextinfo
125
#define r_setcursortype _setcursortype
127
static int winx1,winy1,winx2,winy2,screen_attr;
129
static int winx1=0,winy1=0,winx2=79,winy2=24,screen_attr=7;
130
static int winx1=1,winy1=1,winx2=80,winy2=25,screen_attr=7;
133
/* This has an origin of (0,0) */
134
void r0gotoxy(int x, int y)
140
r.h.bh=0; /* Page 0 */
145
void get_cur_pos(int *px, int *py)
149
r.h.bh=0; /* Page 0 */
155
int rtextmode(int mode)
158
struct text_info term_data;
162
gettextinfo(&term_data);
163
height=term_data.screenheight; /* Assume PC dimensions */
165
winx1=0; winy1=0; winx2=79; winy2=height-1;
170
int86(0x10,&r,&r); /* Set active page to 0 */
177
void rtextattr(int attr)
180
if (directvideo) textattr(attr);
183
void rwindow(int x1, int y1, int x2, int y2)
185
winx1=x1-1; winy1=y1-1; winx2=x2-1; winy2=y2-1;
186
if (directvideo) window(x1,y1,x2,y2);
192
if (directvideo) {clrscr();return;}
193
r.h.ah=0x06; /* Scroll up */
194
r.h.al=0x00; /* Blank window */
195
r.h.ch=winy1; r.h.cl=winx1;
196
r.h.dh=winy2; r.h.dl=winx2;
199
r0gotoxy(winx1,winy1);
207
if (directvideo) {clreol();return;}
209
r.h.ah=0x06; /* Scroll up */
210
r.h.al=0x00; /* Blank window */
212
r.h.dh=y; r.h.dl=winx2;
221
if (directvideo) {insline();return;}
223
r.h.ah=0x07; /* Scroll down */
224
r.h.al=0x01; /* One line */
225
r.h.ch=y; r.h.cl=winx1;
226
r.h.dh=winy2; r.h.dl=winx2;
231
void rnewline(int *px,int *py)
237
} else { /* Scroll */
238
r.h.ah=0x06; /* Scroll up */
239
r.h.al=0x01; /* One line */
240
r.h.ch=winy1; r.h.cl=winx1;
241
r.h.dh=winy2; r.h.dl=winx2;
248
int rfastputch(char c,int *px, int *py)
259
r.h.ah=0x09; /* Print character w/attribute */
264
int86(0x10,&r,&r); /* Doesn't change cursor position */
276
if (directvideo) return putch(c);
283
int rputs(const char *s)
286
if (directvideo) return cputs(s);
289
rfastputch(*s,&x,&y);
297
if (directvideo) return getch();
306
if (directvideo) return getche();
312
void rgotoxy(int x,int y)
314
if (directvideo) {gotoxy(x,y);return;}
315
r0gotoxy(x-1+winx1,y-1+winy1);
321
if (directvideo) return wherex();
329
if (directvideo) return wherey();
336
#else /* ...if not __DJGPP__ */
338
#define rtextattr textattr
339
#define rwindow window
340
#define rgettextinfo gettextinfo
341
#define r_setcursortype _setcursortype
342
#define rclrscr clrscr
343
#define rclreol clreol
344
#define rinsline insline
345
#define rgotoxy gotoxy
346
#define rwherex wherex
347
#define rwherey wherey
350
#define rgetche getche
353
int rtextmode(int mode)
355
struct text_info term_data;
358
gettextinfo(&term_data);
359
return term_data.screenheight; /* Assume PC dimensions */
367
/*------------------------------------------------------------------*/
369
/*------------------------------------------------------------------*/
371
#define STATUS_STATE 0x3800
372
#define BOX_STATE 0x2800
373
#define START_STATE 0x0800
376
currently low 4 bits are color.
377
bit 11 (0x0800) indicates we should use "normal" color
378
bit 12 (0x1000) indicates we are printing the status line, so
380
bit 13 (0x2000) indicates whether we are in reverse video mode or not
381
bit 14 (0x4000) indicates whether we are blinking or not
382
bit 15 (0x8000) indicates whether bold is on or not
385
#define BOLD_BIT 0x8000
386
#define BLINK_BIT 0x4000
387
#define RVID_BIT 0x2000
388
#define STAT_BIT 0x1000
389
#define NORM_BIT 0x0800
391
typedef unsigned short vstate;
392
static vstate state_stack[16];
393
int stateptr=0; /* Points into state stack */
395
#define cstate state_stack[stateptr] /* Current state */
397
static void set_state(vstate state)
400
int bkgd; /* Background and blink bits */
402
/* 0=normal/1=highlight/2=background/3=statfore/4=statback */
404
if (state & NORM_BIT)
405
c=colorset[cs_normal];
407
c=state & 0xF; /* Extract color */
409
if (state & RVID_BIT) { /* Reverse video */
410
bkgd=colorset[cs_statback];
411
if (state & NORM_BIT)
412
c=colorset[cs_statfore];
414
bkgd=colorset[cs_back];
416
if (state & BOLD_BIT)
417
if (state & NORM_BIT)
419
else c^=0x08; /* Toggle bold bit */
421
if ( (state & BLINK_BIT) && !(state & STAT_BIT) )
422
bkgd|=0x08; /* Blinking */
429
static void reset_state(void)
434
static void push_state(vstate state)
436
if (stateptr==15) fatal("State stack overflow!");
441
static void pop_state(void)
443
if (stateptr==0) fatal("State stack error: POP without PUSH!");
448
void agt_textcolor(int c)
449
/* Set text color to color #c, where the colors are as follows: */
450
/* 0=Black, 1=Blue, 2=Green, 3=Cyan, 4=Red, 5=Magenta, 6=Brown, */
451
/* 7=White("normal"), 8=Blinking. */
452
/* 9= *Just* White (not neccessarily "normal" and no need to turn off */
454
/* Also used to set other text attributes: */
455
/* -1=emphasized text, used (e.g.) for room titles */
456
/* -2=end emphasized text */
462
nstate=nstate|0x8000;
464
nstate=nstate & ~0x8000; /* BOLD off */
466
nstate=nstate | 0x4000; /* BLINK on */
468
nstate=START_STATE; /* "Normal" */
470
nstate=(nstate & ~0x080F) | 7; /* Set color to 7: white */
471
else if (c>=0 && c<7)
472
nstate=(nstate & ~0x080F) | c; /* Set color to c */
478
/*------------------------------------------------------------------*/
479
/* Misc. Functions */
480
/*------------------------------------------------------------------*/
483
void agt_delay(int n)
485
if (BATCH_MODE) return;
491
void agt_tone(int hz,int ms)
492
/* Produce a hz-Hertz sound for ms milliseconds */
494
if (!sound_on) return;
500
int agt_rand(int a,int b)
501
/* Return random number from a to b inclusive */
503
return a+(rand()>>2)%(b-a+1);
508
/*------------------------------------------------------------------*/
510
/*------------------------------------------------------------------*/
527
10mm= Function key F<n> with mm=n+13 (F0==F10)
531
2000= unknown control character
536
#define FKEY_CNT (12+8+4)
538
static char keytrans[KEY_CNT]={
539
0x00,0x53, /* Delete and backspace */
540
0x4b,0x4d,0x48,0x50, /* Arrow keys */
541
0x47,0x4F, /* Home and End */
542
0x49,0x51, /* PgUp, PgDown */
543
0x52,0x4E,0x4A, /* Ins, Plus, Minus */
545
0x3b,0x3c,0x3d,0x3e,0x3f, /* F1-F5 */
546
0x40,0x41,0x42,0x43, /* F6-F9 */
547
0x57,0x58}; /* F11-F12 */
550
static const char *keylist[12]={
551
"del","left","right","up","down","home","end","pgup","pgdn",
552
"ins", "plus", "minus"};
558
/*------------------------------------------------------------------*/
560
/*------------------------------------------------------------------*/
562
static int saved_tab=0;
564
unsigned xgetch(void)
587
if (xc==0x4e2b) xc=0x4e00; /* Gray plus */
588
if (xc==0x4a2d) xc=0x4a00; /* Gray minus */
591
if (isprint(c)) return c;
592
else if (c=='\n' || c=='\r') return '\n';
597
else if (c=='\001') /* Ctrl-A ==> Home */
599
else if (c=='\005') /* Ctrl-E ==> End */
601
else if (c=='\010') /* Ctrl-H ==> Backspace */
603
else if (c=='\013') /* Ctrl-K */
605
else if (c=='\031') /* Ctrl-Y */
607
else if (c=='\014') /* Ctrl-L */
611
/* Get extended code */
613
for(i=0;i<KEY_CNT;i++) {
615
if (!nav_arrow || i==0 || i>=FKEY_BASE)
617
else return 1000+FKEY_BASE+12+i-1;
627
void agt_putc(char c)
630
fix_loc(); /* Fixup if returning from being suspended */
636
static rbool old_yheight=0;
637
static int base_x,base_y; /* Base X value of first character of input */
639
/* This assumes the cursor is always positioned on the string
641
static void update_cursor(int cursor)
645
curr_x=base_x+cursor;
647
while (curr_x>=screen_width) {
648
curr_x-=screen_width;
651
rgotoxy(curr_x+1,curr_y+1);
654
/* static rbool save_accum_text=0;*/
656
static void update_line(int cursor,char *buff)
658
int yval, yheight, xpos, i, curr_y;
660
yheight=(base_x+strlen(buff)+screen_width-1)/screen_width; /* Round up */
661
/* printf("<%d+%d>",base_y,yheight);*/
662
rgotoxy(screen_width,screen_height);
663
while (base_y+yheight+status_height>screen_height && base_y>1) {
665
/* save_accum_text=1;*/
667
/* save_accum_text=0;*/
669
for(yval=yheight;yval<old_yheight;yval++) {
670
rgotoxy(1,base_y+yval+1);
679
for(yval=curr_y-base_y;yval<yheight;yval++) {
681
for(i=curr_x;i<screen_width;i++) {
682
if (buff[xpos]==0) break;
683
rputch(buff[xpos++]);
686
if (base_y+yval+status_height<screen_height)
687
rgotoxy(curr_x+1,base_y+yval+2);
690
update_cursor(cursor);
693
static void redisplay_line(char *buff)
699
static char **hist=NULL;
700
static long histcount=0;
701
static long histmax=10;
703
static char *line_edit(int state)
704
/* state=0, input a line.
705
state=1, input character with echo
706
state=2, input character with no echo */
708
static char *yank_text=NULL;
709
rbool editmode, exitflag;
711
int buffleng, buffspace; /* buffspace is space allocated for buffer,
712
buffleng is space really used */
713
static int cursor; /* Where the insertion point is in buffer:
714
insert at this location */
715
char *buff, *savebuff;
722
cursor=buffleng=0;buffspace=2;
723
base_x=rwherex()-1; base_y=rwherey()-1;
732
keyread=keyptr=0; /* Clear key-buffer */
737
if (DEBUG_KEY) printf("{%d}",key);
738
if (key<1000) { /* Real character entered */
739
if (state>0) { /* One key */
744
buff[0]=key; buff[1]=0;
749
if (savebuff!=NULL) {
752
buffspace=buffleng+1;
756
update_cursor(buffleng);
759
/* add character to buffer */
761
if (buffleng+1>buffspace) buffspace+=20;
762
buff=rrealloc(buff,buffspace);
763
for(i=buffleng;i>cursor;i--)
766
update_line(cursor,buff);
768
else switch(key-1000)
770
case 0: /* Backspace */
771
if (!editmode || cursor==0) break;
773
/* Fall through... */
775
if (!editmode || buffleng==cursor) break;
777
if (savebuff!=NULL) {
780
buffspace=buffleng+1;
783
for(i=cursor;i<buffleng;i++)
786
update_line(cursor,buff);
788
case 2: /* Left arrow */
789
if (editmode && cursor>0)
790
update_cursor(--cursor);
792
case 3: /* Right arrow */
793
if (editmode && cursor<buffleng)
794
update_cursor(++cursor);
797
case 4: /* Up arrow: Command history */
798
if (!editmode || histcount==0) break;
799
if (savebuff==NULL) { /* Save current line */
808
buff=hist[curr_hist];
809
buffleng=strlen(buff);
811
redisplay_line(buff);
813
case 5: /* Down arrow: Command history */
814
if (!editmode || savebuff==NULL) break;
816
if (curr_hist>=histcount) {
817
/* Reached bottom: restore original line */
822
buff=hist[curr_hist];
823
buffleng=strlen(buff);
825
redisplay_line(buff);
829
if (!editmode) break;
831
update_cursor(cursor);
834
if (!editmode) break;
836
update_cursor(cursor);
838
case 8: /* Page up : Scroll back */
839
case 9: /* Page down */
841
case 500: /* Ctrl-K: Delete to EOL */
842
if (!editmode) break;
844
if (savebuff!=NULL) {
847
buffspace=buffleng+1;
851
yank_text=rstrdup(buff+cursor);
854
update_line(cursor,buff);
856
case 501: /* Ctrl-Y: Yank */
857
if (!editmode) break;
861
if (savebuff!=NULL) {
864
buffspace=buffleng+1;
870
txtleng=strlen(yank_text);
872
while(buffleng+1>buffspace) buffspace+=20;
873
buff=rrealloc(buff,buffspace);
874
for(i=buffleng;i>=cursor+txtleng;i--)
875
buff[i]=buff[i-txtleng];
876
for(i=0;i<txtleng;i++)
877
buff[cursor+i]=yank_text[i];
878
update_line(cursor,buff);
880
update_cursor(cursor);
883
case 502: /* Ctrl-L: Redraw screen */
887
printf("%s",accum_text); /* Redraw prompt */
889
redisplay_line(buff);
894
if (key<1000+FKEY_BASE || key>=1000+FKEY_BASE+FKEY_CNT)
896
if (!editmode) break;
900
if (savebuff!=NULL) {
903
buffspace=buffleng+1;
906
txtleng=strlen(fkey_text[key-1000-FKEY_BASE]);
907
if (fkey_text[key-1000-FKEY_BASE][txtleng-1]=='\n') {
908
/* Newlines should only appear at the end; they indicate
909
that this function key should cause the line to be entered. */
911
exitflag=1; /* Finish entering this line */
914
while(buffleng+1>buffspace) buffspace+=20;
915
buff=rrealloc(buff,buffspace);
916
for(i=buffleng;i>=cursor+txtleng;i--)
917
buff[i]=buff[i-txtleng];
918
for(i=0;i<txtleng;i++)
919
buff[cursor+i]=fkey_text[key-1000-FKEY_BASE][i];
920
update_line(cursor,buff);
922
update_cursor(cursor);
932
buff=rrealloc(buff,(buffleng+1));
934
if (histmax==0 || histcount<histmax)
935
hist=rrealloc(hist,(++histcount)*sizeof(char*));
937
for(i=0;i<histcount-1;i++)
939
hist[histcount-1]=rstrdup(buff);
950
/*------------------------------------------------------------------*/
951
/* Basic Input and Output Code */
952
/*------------------------------------------------------------------*/
955
static void script_out(const char *s)
958
fprintf(debugfile,"%s",s);
959
if (script_on) fprintf(scriptfile,"%s",s);
966
char *agt_input(int in_type)
967
/* read a line from the keyboard, allocating space for it using malloc */
968
/* in_type: 0=command, 1=number, 2=question, 3=userstr, 4=filename,*/
969
/* 5=RESTART,RESTORE,UNDO,QUIT */
970
/* Negative values are for internal use by the interface (i.e. this module) */
971
/* We completely ignore the value of in_type */
974
static int input_error=0;
987
if (cgets(s)==NULL) { /* I have no idea if cgets _ever_ returns NULL */
988
if (++input_error>10) {
989
printf("Console read failure.\n");
994
s=rrealloc(s,s[1]+3);
995
memmove(s,s+2,s[1]+1);
1000
script_out(s);script_out("\n");
1005
char agt_getkey(rbool echo_char)
1006
/* Reads a character and returns it, possibly reading in a full line
1007
depending on the platform */
1008
/* If echo_char=1, echo character. If 0, then the character is not
1009
required to be echoed (and ideally shouldn't be) */
1018
c=rgetche(); /* Get with echo */
1019
else c=rgetch(); /* Get w/o echo */
1020
if (c==0) rgetch(); /* Throw away extended character */
1031
static void print_compass(void)
1035
if (status_width< 9+4*12) return;
1037
rputs(" EXITS: ");cwidth=9;
1039
if (compass_rose & (1<<i)) {
1042
cwidth+=strlen(exitname[i])+1;
1044
for(i=cwidth;i<status_width;i++) rputs(" ");
1048
static rbool is_fullscreen; /* True until we print the first status line */
1050
void agt_statline(const char *s)
1051
/* Output a string at location (x,y), with attributes attr */
1052
/* 0=normal, 1=background(e.g. status line) */
1056
savex=rwherex();savey=rwherey()+top_row; /* Save old postion */
1057
if (is_fullscreen) { /* Need to move text down a bit */
1060
for(i=0;i<status_height;i++)
1063
rwindow(1,1,screen_width,screen_height); /* Set window to whole screen */
1065
push_state(STATUS_STATE);
1066
rputs(s); /* Console put string */
1076
rwindow(1,status_height+1,screen_width,screen_height); is_fullscreen=0;
1077
/* Exclude status line from window again */
1078
rgotoxy(savex,savey-top_row); /* Return to old postion */
1083
void agt_clrscr(void)
1084
/* This should clear the screen and put the cursor at the upper left
1085
corner (or one down if there is a status line) */
1089
if (DEBUG_OUT) fprintf(stderr,"\n\n<RCLRSCR>\n\n");
1090
if (script_on) fprintf(scriptfile,"\n\n\n\n");
1096
void agt_puts(const char *s)
1102
if (curr_x<old_x+strlen(s)) /* We wrapped */
1104
if (DEBUG_OUT) fprintf(stderr,"%s",s);
1105
if (script_on) fprintf(scriptfile,"%s",s);
1108
void agt_newline(void)
1110
if (!cursor_wrap) rputs("\r\n");
1111
curr_x=0;cursor_wrap=0;
1112
if (DEBUG_OUT) fprintf(stderr,"\n");
1113
if (script_on) fprintf(scriptfile,"\n");
1115
if (scroll_count>=screen_height-status_height-1) {
1116
rputs(" --MORE--"); /* Notice: no newline */
1118
rgotoxy(1,rwherey()); /* Move to beginning of line */
1119
rclreol(); /* Clear to end of line: erase the --MORE-- */
1126
/*------------------------------------------------------------------*/
1127
/* Text Box Routines */
1128
/*------------------------------------------------------------------*/
1131
static unsigned long boxflags;
1132
static int box_startx; /* Starting x of box; starts from 0 */
1133
static int box_width;
1134
static int delta_scroll; /* Amount we are adding to vertical scroll
1137
static void box_border(char *c)
1147
#define VLINE_STR "\263" /* 0xB3 or 0xBA */
1149
static void boxrule(int bottom)
1150
/* Draw line at top or bottom of box */
1155
box_border("\300"); /* 0xC0 or 0xC8 */
1157
box_border("\332"); /* 0xDA or 0xC9 */
1158
for(i=0;i<box_width+2;i++) box_border("\304"); /* 0xC4 or 0xCD */
1160
box_border("\311"); /* 0xC9 or 0xBC */
1162
box_border("\277"); /* 0xBF or 0xBB */
1166
static void boxpos(void)
1170
curr_y=rwherey(); /* == y location + 1 for status line */
1171
if (curr_y>screen_height) curr_y=screen_height;
1172
rgotoxy(box_startx+1,curr_y+1);
1176
void agt_makebox(int width,int height,unsigned long flags)
1177
/* Flags: TB_TTL, TB_BORDER, TB_NOCENT */
1183
if (boxflags&TB_BORDER) { /* Add space for border */
1187
if (boxflags&TB_NOCENT) box_startx=0;
1188
else box_startx=(screen_width-width)/2; /* Center the box horizontally */
1189
if (box_startx<0) box_startx=0;
1191
/* Now we need to compute the vertical position of the box */
1192
if (flags & TB_TTL) { /* Title: centered horizontally */
1193
box_starty=(screen_height-height)/2;
1194
if (box_starty+height+8>screen_height) /* Make room for credits */
1195
box_starty=screen_height-height-8;
1196
if (box_starty<1) box_starty=1;
1199
rwindow(1,1,screen_width,screen_height); /* Titles get the whole screen */
1201
} else { /* Compute vertical position of non-title box */
1202
box_starty=rwherey()-1-height;
1204
delta_scroll=1-box_starty;
1206
} else delta_scroll=0;
1210
rgotoxy(box_startx+1,box_starty+1);
1212
if (boxflags&TB_BORDER) {
1213
push_state(BOX_STATE);
1216
box_border(VLINE_STR);
1221
void agt_qnewline(void)
1223
if (boxflags&TB_BORDER) {
1225
box_border(VLINE_STR);
1228
if (boxflags&TB_BORDER) {
1229
box_border(VLINE_STR);
1234
void agt_endbox(void)
1236
if (boxflags&TB_BORDER) {
1238
box_border(VLINE_STR);
1243
scroll_count+=delta_scroll;
1244
agt_newline(); /* NOT agt_qnewline() */
1245
if ( (boxflags&TB_TTL) )
1246
while(rwherey()+1<screen_height-8) agt_newline();
1251
/*------------------------------------------------------------------*/
1252
/* CFG Editor (In development) */
1253
/*------------------------------------------------------------------*/
1256
static char **readconf(fc_type fc)
1262
static void writeconf(fc_type fc, char **conf)
1268
static char *edops[]={"color","navarrow","tone","compass","input_bold"};
1271
static rbool checkopt(int i)
1272
/* Return true if option i is true */
1275
case 1:return nav_arrow;
1276
case 2:return PURE_TONE;
1277
case 3:return have_compass;
1278
case 4:return PURE_INPUT;
1284
static void savechange(fc_type fc, uchar changes)
1285
/* Call this to save changes to configuration */
1290
/* lxxx holds the line number of xxx */
1292
lcolor=lnavarrow=lcompass=ltone=linputbold=-1;
1294
for(numline=0;conf[numline]!=NULL;numline++) {
1295
/* Detect COLOR, NAVARROW, TONE, COMPASS, INPUT_BOLD */
1297
while(strncasecmp(s,"no_",3)==0) s+=3;
1299
if (strncasecmp(s,edops[i],strlen(edops[i]))==0) {
1305
/* Rebuild config file */
1306
for(i=0;i<5;i++, changes>>=1)
1307
if (changes & 1) { /* Check bit */
1309
if (i==0) { /* COLOR */
1311
s=rmalloc(5+5*15); /* More than enough space */
1315
strcat(s,colorname[colorset[j]]);
1318
} else { /* Non-COLOR options */
1319
s=rmalloc(strlen(edops[i])+4); /* Room for NO_ & \0 */
1326
if (i>=0) { /* Change existing line */
1327
rfree(conf[numline]);
1329
} else { /* Add new line */
1330
conf=rrealloc(++numline);
1336
writeconf(fc, conf);
1338
for(i=0;i<numline;i++)
1357
/*------------------------------------------------------------------*/
1358
/* Parsing CONFIG Options */
1359
/*------------------------------------------------------------------*/
1361
const char *colorname[16]=
1362
{"black","blue","green","cyan","red","magenta","brown","lightgray",
1363
"darkgray","lightblue","lightgreen","lightcyan","lightred","lightmagenta",
1366
static int parse_color(int index,char *cname)
1370
if(strcasecmp(colorname[i],cname)==0) return i;
1371
return colorset[index];
1375
static void getcolors(int cnum,char *clist[])
1381
colorset[i]=parse_color(i,clist[i]);
1382
colorset[cs_back]&=0x7;
1383
colorset[cs_statback]&=0x7;
1387
/* Duplicate s and add '/' if neccessary */
1388
char *makepathentry(char *s)
1396
if (s[n-1]!='\\') addslash=1;
1397
p=rmalloc(n+addslash+1);
1401
p[n+1]=0; /* Mark new end of string */
1406
void free_gamepath(void)
1410
if (gamepath==NULL) return;
1412
/* We skip the first element which always points to "" */
1413
for(p=gamepath+1;*p!=NULL;p++)
1419
#define opt(s) (!strcasecmp(optstr[0],s))
1421
void set_fkey(char *keyname, char *words[], int numwords)
1426
static long keys_defined=0;
1429
if (tolower(keyname[0])!='f') {
1432
if (0==strcasecmp(keylist[i],keyname)) {
1436
} else { /* Name of form 'Fnn' */
1437
n=strtol(keyname+1,&s,0); /* s will point to the first erroneous char */
1438
if (keyname[1]==0 || *s!=0) err=1;
1444
writeln("Unrecognized KEY name.");
1449
for(i=0;i<numwords;i++)
1450
leng+=strlen(words[i]);
1451
s=rmalloc(leng+numwords+1);
1454
/* This isn't very efficient, but it doesn't need to be. */
1455
for(i=0;i<numwords;i++) {
1460
if (i>=0 && s[i]=='+') {
1465
if (keys_defined & (1<<n)) rfree(fkey_text[n]);
1467
keys_defined|=(1<<n);
1471
#define opt(s) (!strcasecmp(optstr[0],s))
1473
rbool agt_option(int optnum,char *optstr[],rbool setflag)
1474
/* If setflag is 0, then the option was prefixed with NO_ */
1478
if (optnum==0) return 1;
1479
if (opt("COMPASS")) {
1484
font_enable=setflag;
1487
if (opt("NAVARROW")) {
1495
if (opt("BLOCK_CURSOR")) {
1496
block_cursor=setflag;
1499
if (opt("COLORS") || opt("COLOURS")) {
1500
getcolors(optnum-1,optstr+1);
1502
if (opt("HISTORY")) {
1503
histmax=strtol(optstr[1],NULL,10);
1504
if (histmax<0) histmax=0;
1507
if (opt("50_LINE")) {
1508
tall_screen=setflag;
1511
if (opt("KEY") && optnum>=2) {
1512
set_fkey(optstr[1],optstr+2,optnum-2);
1515
if (opt("PATH") && optnum>=2) {
1516
free_gamepath(); /* Throw away previous settings */
1517
gamepath=rmalloc((optnum+1)*sizeof(char*)); /* optnum-1+1 */
1518
gamepath[0]=""; /* ==> The current directory */
1519
for(i=1;i<optnum;i++) /* Starting at the 2nd entry of both */
1520
gamepath[i]=makepathentry(optstr[i]);
1521
gamepath[optnum]=NULL;
1529
static char *progname;
1530
static const char *cfgname="agil.cfg";
1532
FILE *agt_globalfile(int fid)
1537
if (fid==0 && progname!=NULL) {
1538
s=rstrdup(progname);
1540
while (t!=s && *t!='\\' && *t!=':') t--;
1543
s=rrealloc(s,strlen(s)+strlen(cfgname)+1);
1556
/*------------------------------------------------------------------*/
1557
/* Initialization and Shutdown */
1558
/*------------------------------------------------------------------*/
1560
static void id_hardware(void)
1564
r.h.ah=0x12; /* EGA+ Misc functions */
1565
r.h.bl=0x10; /* ...get information */
1566
r.h.bh=0x37; /* Check value */
1567
r.x.cx=0x73F1; /* Random check value */
1569
if ( (r.h.bh==0 || r.h.bh==1) &&
1570
(r.h.bl>=0 && r.h.bl<=3) &&
1571
(r.h.ch & 0xF0)==0 && (r.h.cl & 0xF0)==0) {
1572
/* Okay, the function works; we have an EGA/VGA */
1574
if (r.h.bl==0) graph_hardware=EGA64;
1575
else graph_hardware=EGA;
1579
if (r.h.al==0x1A) /* We have a VGA */
1582
} else { /* MDA/CGA/MCGA */
1585
if (r.h.al==0x1A) { /* We have an MCGA */
1586
graph_hardware=MCGA;
1592
r.h.ah=0x0F; /* Get current video mode */
1594
if ((r.h.al & 0x7F)==7)
1600
static int save_mode;
1601
static int save_attr;
1603
void init_interface(int argc,char *argv[])
1605
struct text_info term_data;
1611
if (argc>0) progname=argv[0]; else progname=NULL;
1612
script_on=0;scriptfile=NULL;
1617
have_compass=0;status_height=0;
1618
block_cursor=0; tall_screen=0;
1619
center_on=par_fill_on=0;
1620
DEBUG_OUT=0;debugfile=stderr;
1621
rgettextinfo(&term_data);
1622
save_mode=term_data.currmode;
1623
save_attr=term_data.attribute;
1624
directvideo=0; /* During startup, go through BIOS. */
1626
rtextmode(C80); /* Change to color, 80 column mode */
1627
screen_height=25; /* Assume PC dimensions */
1628
status_width=screen_width=80;
1630
rwindow(1,1,screen_width,screen_height); is_fullscreen=1;
1632
rgotoxy(1,1); /* Upper-left hand corner of just defined window */
1635
void start_interface(fc_type fc)
1638
screen_height=rtextmode(C4350); /* Change to color, 80 column mode */
1640
rgotoxy(1,1); /* Upper-left hand corner of just defined window */
1642
directvideo=!use_bios; /* Set directvideo according to options */
1648
gamefile_name=fc->gamename;
1650
r_setcursortype(_SOLIDCURSOR);
1652
r_setcursortype(_NORMALCURSOR);
1654
curr_x=0;scroll_count=0;
1659
rwindow(1,1,screen_width,screen_height); /* Set window to whole screen */
1660
is_fullscreen=1; /* We use the whole screen until the first status line
1662
top_row=status_height+1;
1666
void close_interface(void)
1668
if (scriptfile!=NULL)
1670
agt_newline();agt_newline();
1671
if (block_cursor) r_setcursortype(_NORMALCURSOR);
1672
rtextmode(save_mode);
1673
rtextattr(save_attr);
1688
/*------------------------------------------------------------------*/
1689
/* GRAPHICS AND FONT SUPPORT */
1690
/*------------------------------------------------------------------*/
1693
/* This cheats a bit, using "hidden" data from filename.c */
1695
static FILE *linopen(char *name, char *ext)
1700
fname=assemble_filename(hold_fc->path,name,ext);
1701
f=fopen(fname,"rb");
1706
/*------------------------------------------------------------------*/
1708
/*------------------------------------------------------------------*/
1710
static char *save_font;
1711
static int save_font_height;
1713
static int set_font(char *fontdef, int font_height)
1719
r.r_bx=font_height<<8; /* 8 bytes per character in BH; 0 in BL */
1720
r.r_cx=256; /* Number of characters defined */
1721
r.r_dx=0; /* Start at ASCII 0. */
1722
r.r_es=((long)fontdef)>>16;
1723
r.r_bp=((long)fontdef)&0xFFFF;
1730
/* If the transfer buffer isn't large enough, we just silently fail.
1731
We should really do something like allocate our own buffer
1733
if (font_height*256>_go32_info_block.size_of_transfer_buffer)
1737
r.h.bh=font_height; /* 8 bytes per character in BH; 0 in BL */
1739
r.x.cx=256; /* Number of characters defined */
1740
r.x.dx=0; /* Start at ASCII 0. */
1741
dosmemput(fontdef,font_height*256, __tb);
1742
r.x.es=__tb>>4; /* Segment */
1743
r.x.bp=__tb&0x0F; /* Offset */
1744
__dpmi_int(0x10,&r);
1750
static void save_old_font(void)
1754
if (graph_hardware<MCGA) {
1755
/* User-defined fonts aren't supported */
1763
save_font_height=r.x.cx;
1767
static void restore_font(void)
1771
if (save_font_height==14)
1772
r.x.ax=0x1101; /* 8x14 */
1773
else if (save_font_height==16)
1774
r.x.ax=0x1104; /* 8x16 */
1776
r.x.ax=0x1102; /* 8x8 */
1779
/* ... if MCGA ... */
1780
/* if (graph_hardware==MCGA) {*/
1789
void fontcmd(int cmd,int font)
1790
/* 0=Load font, name is fontlist[font]
1791
1=Restore original font
1792
2=Set startup font. (<gamename>.FNT)
1796
char *buff, *fontname;
1799
if (!font_enable) return;
1803
if (!font_enable) return;
1806
if (cmd==0 || cmd==2) {
1808
fontname=fontlist[font];
1810
else fontname=gamefile_name;
1812
fontfile=linopen(fontname,".fnt");
1813
if (fontfile==NULL) return;
1814
fseek(fontfile,0,SEEK_END);
1815
height=ftell(fontfile);
1816
if (height%256!=0) {
1821
buff=rmalloc(256*height);
1822
memset(buff,0,256*height);
1824
fseek(fontfile,0,SEEK_SET);
1825
if (fread(buff,height,256,fontfile)!=256) {
1831
if (set_font(buff,height)) {
1832
/* Print error message */
1836
active_font_height=height;
1838
} else if (cmd==1) {
1848
/*------------------------------------------------------------------*/
1849
/* Graphics Support */
1850
/*------------------------------------------------------------------*/
1852
static rbool in_gmode=0;
1854
static char *gfxext[]={".P06",
1855
".P40",".P41",".P42",".P43", /* 0-4: CGA */
1856
".P13", /* 5: EGA */
1857
".P19", /* 6: MCGA */
1858
".P14",".P16", /* 7-8: EGA */
1859
".P18"}; /* 9: VGA */
1861
/* Modes 1-4 differ only in pallette */
1863
/* 0 1 2 3 4 5 6 7 8 9 */
1864
static int paltype[]={0, 1, 1, 1, 1, 2, 3, 2, 2, 2};
1865
static int mode_x[]={640,320,320,320,320, 320,320, 640,640, 640};
1866
static int mode_y[]={200,200,200,200,200, 200,200, 200,350, 480};
1867
static int mode[] ={ 6, 4, 4, 4, 4, 13, 19, 14, 16, 18};
1869
/* paltype is the log_2 of the bit depth */
1870
/* Mode 16 with lowmem EGA only has 2bpp */
1871
/* Mode to start from for each video type */
1872
/* MDA, CGA, MCGA, EGA65, EGA, VGA */
1873
static int start_mode[]={-1,4,6,7,8,9};
1876
int pick_gmode(int gmode, int pmode, int xsize, int ysize)
1878
int save_gmode, work_gmode;
1880
if (gmode!=-1) /* Check that gmode is consitent with file */
1881
if (mode_x[gmode]>=xsize && mode_y[gmode]>=ysize &&
1882
paltype[gmode]==pmode)
1885
save_gmode=gmode; work_gmode=-1;
1886
/* Okay, we don't know what mode we are; try to pick the best for
1888
/* work_gmode will contain the highest resolution mode with the
1889
neccessary color depth; if we can't find a perfect mode, we'll
1890
use this and clip. */
1891
for(gmode=0;gmode<=start_mode[graph_hardware];gmode++) {
1892
if (gmode==6 && (graph_hardware==EGA || graph_hardware==EGA64))
1894
if (gmode==5 && graph_hardware==MCGA) continue;
1896
if (paltype[gmode]!=pmode) continue;
1898
if (mode_x[gmode]<xsize || mode_y[gmode]<ysize) continue;
1901
return work_gmode; /* May need to be clipped */
1905
int pix_per_byte[]={8,4,8,1};
1916
typedef uchar* graphptr;
1917
#define graphwrite(dst,src,leng) memcpy(dst,src,leng)
1919
typedef unsigned long graphptr;
1920
#define graphwrite(dst,src,leng) dosmemput(src,leng,dst)
1923
void draw_scanline(uchar *linebuff,int gmode,int y_start,
1924
int linesize,int sizex)
1926
static const char mmr[4]=
1927
{BPB,BPG,BPR,BPI}; /* Seq Mask Map Register values */
1928
static int mode_bpl, writesize;
1929
static uchar end_mask;
1930
static graphptr target;
1933
if (linebuff==NULL) { /* Set up before first line */
1934
mode_bpl=mode_x[gmode]/pix_per_byte[paltype[gmode]];
1935
i=(mode_x[gmode]-sizex)/(2*pix_per_byte[paltype[gmode]]); /* Center it */
1938
if (gmode<=4) target=(uchar*)0xB8000000L;
1939
else target=(uchar*)0xA0000000L;
1941
if (gmode<=4) target=0xB8000L;
1942
else target=0xA0000L;
1945
target+=i+y_start*mode_bpl;
1947
/* Now set i to the number of "extra" pixels */
1948
i=linesize*pix_per_byte[paltype[gmode]]-sizex;
1949
writesize=linesize-i/pix_per_byte[paltype[gmode]];
1950
i=i%pix_per_byte[paltype[gmode]];
1951
i=i*(1<<8/pix_per_byte[paltype[gmode]]); /* i=# bits of excess */
1952
end_mask=(0xFF<<i)&0xFF; /* ...and construct a bit mask */
1954
if (paltype[gmode]==2) { /* Bit plane graphics */
1955
/* 3CE/3CF: Graphic Control Registers */
1956
/* Graphic Ctrl Reg (3CE/3CF):
1957
1: 0x00 (Enable Set/reset: CPU => bitplanes)
1958
3: 0x00 (Function select: replace)
1959
5: 0x00 (Write and read mode 0)
1960
8: 0xFF (Bit Mask) */
1962
/* First, basic initalization. Most of these are default values,
1963
but it doesn't hurt to be careful */
1964
outp(0x3CE,0x01); /* Enable Set/Reset Register */
1965
outp(0x3CF,0x00); /* ... ignore Set/Reset register */
1966
outp(0x3CE,0x03); /* Function Select Register */
1967
outp(0x3CF,0x00); /* ... replace and don't rotate */
1968
outp(0x3CE,0x05); /* Mode Register */
1969
outp(0x3CF,0x00); /* ... write and read mode 0 */
1970
outp(0x3CE,0x08); /* Bit Mask Register */
1971
outp(0x3CF,0xFF); /* ... write to everything */
1976
target+=mode_bpl; /* Move to beginning of next line */
1978
if (paltype[gmode]!=2) { /* The easy case: just one plane */
1979
linebuff[writesize-1]&=end_mask;
1980
graphwrite(target,linebuff,writesize);
1981
} else { /* 4 planes, 1 bit/pixel/plane */
1982
/* 3C4/3C5: Video Sequencer Registers
1983
2: Map Mask Register */
1985
outp(0x3C4,2); /* Map Mask Register */
1986
outp(0x3C5,mmr[i]); /* ... select the given bitplane */
1987
linebuff[linesize*i+writesize-1]&=end_mask;
1988
graphwrite(target,linebuff+linesize*i,writesize);
1995
/* This flips the bits and separates them by three bits */
1996
static const uchar paltrans[]={0,8,1,9};
1999
static uchar build_ega_pal(uchar red, uchar green, uchar blue)
2000
/* Construct 6-bit color code, on pattern
2001
00rgbRGB, from Rrxxxxxx, Ggxxxxxx, Bbxxxxxx */
2006
return paltrans[blue]+(paltrans[green]<<1)+(paltrans[red]<<2);
2010
/* When dacflag is 0, this sets the video palette;
2011
when dacflag is 1, it sets the DAC registers instead */
2012
static void bios_set_pal(uchar *palptr, unsigned leng, rbool dacflag)
2016
struct SREGS segreg;
2029
r.x.dx=((long)palptr)&0xFFFF;
2030
segreg.es=((long)palptr)>>16;
2031
int86x(0x10,&r,&r,&segreg);
2033
dosmemput(palptr,leng*(dacflag?3:1), __tb);
2034
r.x.dx=__tb & 0x000F; /* Offset */
2035
r.x.es=__tb>>4; /* Segment */
2036
__dpmi_int(0x10,&r);
2041
#define ival(n) (header[n]+(header[n+1]<<8))
2044
static rbool setup_card(FILE *pcxfile,uchar *header,int gmode, int pmode)
2047
uchar *tmppal, *pal;
2048
int havepal; /* 0=No, 1=Yes, but not VGA, 2=Yes, maybe VGA */
2051
if (header[1]==5) havepal=2;
2052
else if (header[1]==2) havepal=1;
2055
if (pmode==3 && havepal!=2) {
2056
writeln("ERROR: PCX file corrupted: bad color depth.");
2060
/*-------------------------------------*/
2061
/* Read in VGA palette */
2062
/*-------------------------------------*/
2064
/* Next, read in the VGA palette if neccessary */
2066
if (pmode==3) { /* VGA palette */
2071
fseek(pcxfile,0,SEEK_END);
2073
if (fseek(pcxfile,n-256*3-1,SEEK_SET)
2074
|| fread(&c,1,1,pcxfile)!=1) {
2075
writeln("GAME ERROR: Errors reading picture file.");
2080
writeln("ERROR: PCX file corrupted: bad palette.");
2084
if (fread(pal,768,1,pcxfile)!=1) {
2085
writeln("GAME ERROR: Errors reading palette from picture file.");
2092
/*-------------------------------------*/
2093
/* Set up video mode */
2094
/*-------------------------------------*/
2096
/* -- Need to save old video state here -- */
2098
/* Set video mode */
2103
/*-------------------------------------*/
2104
/* Set up Palette */
2105
/*-------------------------------------*/
2108
if (pmode==2 && paltype[gmode]==3) {
2109
/* Set up fake EGA palette */
2112
pal[i]=header[16+i];
2113
for(i=3*16;i<3*256;i++)
2115
} else if (pmode<=1 && paltype[gmode]==2) {
2116
/* This could occur with a high resolution 2 or 4 color image */
2118
fatal("Unsupported image class.");
2120
} else assert(pmode==paltype[gmode]);
2123
assert(pmode==paltype[gmode]);
2125
/* Now to set the palette */
2126
if (paltype[gmode]==1) { /* CGA palette */
2129
if (pmode==1 && havepal!=0)
2130
r.h.bl=(header[19]>>6)&0x01;
2132
r.h.bl=(gmode-1)>>1; /* Top bit==> palette */
2135
r.h.ah=0x0B; /* Set background and intensity bits */
2137
if (pmode==1 && havepal!=0)
2138
r.h.bl= ( (header[19]>>1) & 0x10 ) | (header[16]>>4);
2140
r.h.bl=((gmode-1)&1)<<4; /* Background will be 0. */
2142
else if (paltype[gmode]==2 && havepal!=0) { /* EGA Palette */
2144
if (graph_hardware!=VGA)
2146
tmppal[i]=build_ega_pal(header[16+3*i],
2149
else for(i=0;i<16;i++) tmppal[i]=i+1; /* For VGA hardware, point to DAC */
2150
tmppal[16]=0; /* Set overscan to 0 */
2151
bios_set_pal(tmppal,17,0);
2154
if (graph_hardware==VGA) { /* Now reprogram the DAC */
2155
tmppal=rmalloc(17*3);
2157
tmppal[3+3*i]=header[16+3*i]>>2;
2158
tmppal[4+3*i]=header[17+3*i]>>2;
2159
tmppal[5+3*i]=header[18+3*i]>>2;
2161
tmppal[0]=tmppal[1]=tmppal[2]=0; /* Overscan color is black */
2162
bios_set_pal(tmppal,17,1);
2164
} else if (paltype[gmode]==3 && havepal!=0) { /* MCGA Palette */
2165
for(i=0;i<256*3;i++)
2167
bios_set_pal(pal,256,1);
2173
#ifdef DEBUG_VIDCARD
2174
static int test_pattern(int y, int p)
2176
if (p==1) return (1<<(y%8));
2181
static int save_pmode; /* Debugging only */
2185
#define PCX_BUFFSIZE 16000
2186
static uchar *fbuff;
2187
static int fb_index;
2189
static int readbyte(FILE *f)
2193
if (fb_index==PCX_BUFFSIZE) {
2194
n=fread(fbuff,1,PCX_BUFFSIZE,f);
2195
if (n==0) return EOF;
2196
if (n<PCX_BUFFSIZE) memset(fbuff+n,0,PCX_BUFFSIZE-n);
2199
return fbuff[fb_index++];
2205
static void display_PCX(FILE *pcxfile, int gmode)
2206
/* pcxfile= the file to display.
2207
gmode= suggested video mode. */
2210
int pmode; /* PCX palette mode: 0=CGA hires 1=CGA, 2=EGA, 3=MCGA */
2213
uchar *linebuff; /* Up to four planes */
2214
int linesize; /* Number of bytes in a line */
2218
/*-------------------------------------*/
2219
/* Read in header */
2220
/*-------------------------------------*/
2222
if (fread(header,128,1,pcxfile)!=1) {
2223
writeln("GAME ERROR: Picture file corrupted.");
2228
if (header[0]!=10 || header[2]!=1 ||
2229
(header[1]!=1 && header[1]!=2 && header[1]!=3 && header[1]!=5))
2230
{writeln("ERROR: Unrecognized PCX version.");return;}
2232
/* Determine which palette type we're using */
2234
if (header[3]==1 && header[65]==1) pmode=0; /* CGA 2-color */
2235
else if (header[3]==2 && header[65]==1) pmode=1; /* CGA 4-color */
2236
else if (header[3]==1 && header[65]==4) pmode=2; /* EGA/VGA 16-color*/
2237
else if (header[3]==8 && header[65]==1) pmode=3; /* MCGA 256-color */
2239
writeln("ERROR: Unsupported graphics mode.");
2243
xsize=ival(8)-ival(4)+1;
2244
ysize=ival(10)-ival(6)+1;
2246
gmode=pick_gmode(gmode,pmode,xsize,ysize);
2247
if (gmode==-1) {pmode=-4; return;}
2249
assert(pmode==paltype[gmode]); /* Temporary */
2251
/* Clip if neccessary */
2252
if (xsize>mode_x[gmode]) xsize=mode_x[gmode];
2253
if (ysize>mode_y[gmode]) ysize=mode_y[gmode];
2257
if (!setup_card(pcxfile,header,gmode,pmode)) return;
2260
/*-------------------------------------*/
2262
/*-------------------------------------*/
2264
fseek(pcxfile,128,SEEK_SET); /* Beginning of picture data */
2267
linebuff=rmalloc(linesize*header[65]);
2269
y_ofs=(mode_y[gmode]-ysize)/2;
2271
/* This will set up the scanline drawing routines */
2272
draw_scanline(NULL,gmode,y_ofs,linesize,xsize);
2274
#ifdef DEBUG_VIDCARD
2275
for(i=0;i<ysize;i++) {
2276
memset(linebuff,0,linesize*header[65]);
2280
memset(linebuff+j*linesize,
2281
test_pattern(i,j),linesize);
2282
} else if (pmode==3) {
2283
memset(linebuff,0,linesize);
2284
} else if (pmode==1) {
2285
memset(linebuff,0,linesize);
2286
} else memset(linebuff,0,linesize); /* Vertical lines */
2288
draw_scanline(linebuff,gmode,y_ofs+i,linesize,xsize);
2292
fbuff=rmalloc(PCX_BUFFSIZE); /* The input buffer */
2293
fb_index=PCX_BUFFSIZE;
2296
for(i=0;i<ysize;i++) {
2297
memset(linebuff,0,linesize*header[65]);
2298
for(j=0;j<linesize*header[65];) {
2299
c=readbyte(pcxfile);
2300
if (c==EOF) {save_pmode=-1;return;}
2301
if ( (c&0xC0)==0xC0) {
2302
k=c&0x3F; /* Count=lower 6 bits */
2303
c=readbyte(pcxfile);
2305
if (c==EOF) {save_pmode=-2;return;}
2306
for(;k>0 && j<linesize*header[65];k--)
2308
if (k>0) {save_pmode=-3;return;}
2312
draw_scanline(linebuff,gmode,y_ofs+i,linesize,xsize);
2321
void pictcmd(int cmd,int pict)
2322
/* 1=show global picture, name is pictlist[pict]
2323
2=show room picture, name is pixlist[pict]
2324
3=Show title picture.
2335
if (graph_hardware==MDA) return; /* MDA is out */
2337
if (cmd==1) base=pictlist[pict];
2338
else if (cmd==2) base=pixlist[pict];
2339
else if (cmd==3) base=gamefile_name;
2342
while(kbhit()) rgetch(); /* Discard any buffered keypresses */
2344
/* Find graphics file; determine mode from extension... */
2345
for(gmode=start_mode[graph_hardware];gmode>=0;gmode--) {
2346
if (gmode==6 && (graph_hardware==EGA || graph_hardware==EGA64))
2347
continue; /* EGA should skip MCGA mode */
2348
if (gmode==5 && graph_hardware==MCGA) continue; /* ... and conversely */
2349
pcxfile=linopen(base,gfxext[gmode]);
2350
if (pcxfile!=NULL) break;
2353
pcxfile=linopen(base,".pcx");
2354
if (pcxfile==NULL) return;
2355
/* Leave gmode as -1 */
2362
save_vidmem=rmalloc(2*25*80);
2363
memcpy(save_vidmem,(void*)0xB8000000L,2*25*80);
2365
if (graph_hardware>MCGA)
2366
save_vidmem=rmalloc(2*ScreenRows()*ScreenCols());
2368
save_vidmem=rmalloc(2*25*80);
2369
ScreenRetrieve(save_vidmem);
2372
display_PCX(pcxfile,gmode);
2376
/*-------------------------------------*/
2377
/* Wait for key and restore text mode */
2378
/*-------------------------------------*/
2382
if (!BATCH_MODE) rgetch(); /* Wait for a key-press */
2384
r.x.ax=0x0003; /* Restore text mode */
2388
memcpy((void*)0xB8000000L,save_vidmem,2*25*80); /* Restore video mem */
2390
ScreenUpdate(save_vidmem);
2392
rgotoxy(savex,savey); /* Restore cursor position */
2393
if (active_font!=NULL) /* Restore font, if neccessary */
2394
set_font(active_font,active_font_height);
2397
/* -- Need to restore old video state here -- */
2398
/* -- Primary font (16*256=4K) */
2399
/* -- Screen memory (2*25*80=4K) */
2400
/* -- Cursor position and current screen attributes */
2403
/* rprintf("Mode: %d\n",save_pmode); */
2409
int musiccmd(int cmd,int song)
2410
/* For cmd=1 or 2, the name of the song is songlist[song]
2411
The other commands don't take an additional argument.
2421
-1=Is a song playing? (0=false, -1=true)
2422
-2=Is the sound on? (0=false, -1=true)
2425
if (cmd==8) sound_on=1;
2426
else if (cmd==9) sound_on=0;
2427
if (cmd==-1) return sound_on;
2431
#endif /* REPLACE_BNW */