~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to terps/agility/os_dos.c

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* os_msdos.c -- interface routines for MS-DOS            */
 
2
/* Copyright (C) 1996,1997,1998    Robert Masenten        */
 
3
/*                                                        */
 
4
/* This is part of the source for the (Mostly) Universal  */
 
5
/*       AGT Interpreter                                  */
 
6
 
 
7
/* This has been written to work under Borland C (MSDOS16)
 
8
   and DJGPP (MSDOS32); it hasn't been tested with other compilers. */
 
9
 
 
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
 
12
   origin (0,0). */
 
13
 
 
14
 
 
15
 
 
16
/* What needs work for 32-bit case:
 
17
   set_font()
 
18
*/
 
19
 
 
20
/* What's done:
 
21
   rgetchar()
 
22
   draw_scanline()
 
23
   pictcmd():       Save/restore of text mode video memory
 
24
   setup_card():    Setting video-mode palette
 
25
*/
 
26
 
 
27
#define USE_EDITLINE
 
28
#define DEBUG_KEY 0  /* Turns on debugging of key functions */
 
29
 
 
30
#include <stdlib.h>
 
31
#include <stdio.h>
 
32
#include <dos.h>
 
33
#include <time.h>
 
34
#include <ctype.h>
 
35
#include <limits.h>
 
36
#include <assert.h>
 
37
 
 
38
#include "agility.h"
 
39
#include "interp.h"
 
40
 
 
41
#include <conio.h>
 
42
 
 
43
#ifdef __DJGPP__
 
44
#include <bios.h>
 
45
#include <dpmi.h>
 
46
#include <go32.h>
 
47
#include <pc.h>
 
48
#define outp(p,d) outportb(p,d)
 
49
#endif
 
50
 
 
51
#define cleareol rclreol
 
52
 
 
53
 
 
54
rbool use_bios;  /* If true, use the BIOS routines for text output.
 
55
                   (for the sake of blind users.) */
 
56
 
 
57
static int colorset[5]={7,14,0,15,1};
 
58
 
 
59
 
 
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 */
 
63
 
 
64
int scroll_count; /* Count of how many lines we have printed since
 
65
                     last player input. */
 
66
int status_height;
 
67
rbool have_compass;
 
68
int top_row; /* The absolute y value of the current top row. */
 
69
 
 
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? */
 
75
 
 
76
static char *active_font; /* Currently active font; NULL if none */
 
77
static int active_font_height;
 
78
 
 
79
typedef enum {MDA,CGA,MCGA,EGA64,EGA,VGA} gh_type;
 
80
static gh_type graph_hardware;
 
81
 
 
82
 
 
83
static char *fkey_text[24]={ /* Text for function keys */
 
84
  "help\n",
 
85
  "get ","drop ",
 
86
  "examine ","read ",
 
87
  "open ","close ",
 
88
  "inventory\n","look\n",
 
89
  "score\n",
 
90
  "save\n","restore\n",
 
91
  "exit\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"
 
95
};
 
96
 
 
97
 
 
98
#if 0
 
99
{
 
100
  "undo\n",
 
101
  "get ","drop ",
 
102
  "read ","unlock ",
 
103
  "open ","close ",
 
104
  "inventory\n","look\n",  
 
105
  "wait\n",
 
106
  "save\n","restore\n"};
 
107
#endif
 
108
 
 
109
/* Other candidates:
 
110
  view
 
111
  help
 
112
  examine (x) 
 
113
  again (g)   */    
 
114
 
 
115
 
 
116
#ifdef __DJGPP__
 
117
/*------------------------------------------------------------------*/
 
118
/*  32-bit library Compatibility Layer  */
 
119
/*------------------------------------------------------------------*/
 
120
 
 
121
/* Internal coordinates have an origin of (0,0), even though the
 
122
   calling coordinates are (1,1). */
 
123
 
 
124
#define rgettextinfo gettextinfo
 
125
#define r_setcursortype _setcursortype
 
126
 
 
127
static int winx1,winy1,winx2,winy2,screen_attr;
 
128
#if 0
 
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;
 
131
#endif
 
132
 
 
133
/* This has an origin of (0,0) */
 
134
void r0gotoxy(int x, int y)
 
135
{
 
136
  union REGS r;
 
137
  r.h.ah=0x02;
 
138
  r.h.dh=y;
 
139
  r.h.dl=x;
 
140
  r.h.bh=0; /* Page 0 */
 
141
  int86(0x10,&r,&r);
 
142
}
 
143
 
 
144
 
 
145
void get_cur_pos(int *px, int *py)
 
146
{
 
147
  union REGS r;  
 
148
  r.h.ah=0x03; 
 
149
  r.h.bh=0;  /* Page 0 */
 
150
  int86(0x10,&r,&r);
 
151
  *px=r.h.dl;
 
152
  *py=r.h.dh;
 
153
}
 
154
 
 
155
int rtextmode(int mode)
 
156
{
 
157
  union REGS r;
 
158
  struct text_info term_data;    
 
159
  int height;
 
160
 
 
161
  textmode(mode);
 
162
  gettextinfo(&term_data);
 
163
  height=term_data.screenheight;  /* Assume PC dimensions */
 
164
 
 
165
  winx1=0; winy1=0; winx2=79; winy2=height-1;
 
166
  screen_attr=7;
 
167
  if (!directvideo) {
 
168
    r.h.ah=5;
 
169
    r.h.al=0;
 
170
    int86(0x10,&r,&r);  /* Set active page to 0 */
 
171
    r0gotoxy(0,0);
 
172
  }
 
173
  return height;
 
174
}
 
175
 
 
176
 
 
177
void rtextattr(int attr)
 
178
{
 
179
  screen_attr=attr;
 
180
  if (directvideo) textattr(attr);
 
181
}
 
182
 
 
183
void rwindow(int x1, int y1, int x2, int y2)
 
184
{
 
185
  winx1=x1-1; winy1=y1-1; winx2=x2-1; winy2=y2-1;
 
186
  if (directvideo) window(x1,y1,x2,y2);
 
187
}
 
188
 
 
189
void rclrscr(void)
 
190
{
 
191
  union REGS r;
 
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;
 
197
  r.h.bh=screen_attr;
 
198
  int86(0x10,&r,&r);
 
199
  r0gotoxy(winx1,winy1);
 
200
}
 
201
 
 
202
void rclreol(void)
 
203
{
 
204
  union REGS r;
 
205
  int x,y;
 
206
 
 
207
  if (directvideo) {clreol();return;}
 
208
  get_cur_pos(&x,&y);
 
209
  r.h.ah=0x06; /* Scroll up */
 
210
  r.h.al=0x00; /* Blank window */
 
211
  r.h.ch=y; r.h.cl=x;
 
212
  r.h.dh=y; r.h.dl=winx2;
 
213
  r.h.bh=screen_attr;
 
214
  int86(0x10,&r,&r);
 
215
}
 
216
 
 
217
void rinsline(void)
 
218
{
 
219
  union REGS r;
 
220
  int x,y;  
 
221
  if (directvideo) {insline();return;}
 
222
  get_cur_pos(&x,&y);
 
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;
 
227
  r.h.bh=screen_attr;
 
228
  int86(0x10,&r,&r);
 
229
}
 
230
 
 
231
void rnewline(int *px,int *py)
 
232
{
 
233
  union REGS r;
 
234
  *px=winx1;
 
235
  if (*py<winy2) {
 
236
    (*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;
 
242
    r.h.bh=screen_attr;
 
243
    int86(0x10,&r,&r);      
 
244
  }
 
245
}
 
246
 
 
247
 
 
248
int rfastputch(char c,int *px, int *py)
 
249
{
 
250
  union REGS r;
 
251
  if (c=='\r') {
 
252
    return 0;
 
253
  }
 
254
  if (c=='\n') {
 
255
    rnewline(px,py);
 
256
    r0gotoxy(*px,*py);
 
257
    return 0;
 
258
  }
 
259
  r.h.ah=0x09; /* Print character w/attribute */
 
260
  r.h.al=c;
 
261
  r.h.bl=screen_attr;
 
262
  r.h.bh=0;
 
263
  r.x.cx=1;
 
264
  int86(0x10,&r,&r); /* Doesn't change cursor position */
 
265
  (*px)++; 
 
266
  if ((*px)>winx2)
 
267
    rnewline(px,py);
 
268
  r0gotoxy(*px,*py);
 
269
  return 0;
 
270
}
 
271
 
 
272
 
 
273
int rputch(char c)
 
274
{
 
275
  int x,y;
 
276
  if (directvideo) return putch(c);
 
277
  get_cur_pos(&x,&y);
 
278
  rfastputch(c,&x,&y);
 
279
  return 0;
 
280
}
 
281
 
 
282
 
 
283
int rputs(const char *s)
 
284
{
 
285
  int x,y;
 
286
  if (directvideo) return cputs(s);
 
287
  get_cur_pos(&x,&y);
 
288
  for(;*s!=0;s++)
 
289
    rfastputch(*s,&x,&y);
 
290
  return 0;
 
291
}
 
292
 
 
293
 
 
294
int rgetch(void)
 
295
{
 
296
  union REGS r;
 
297
  if (directvideo) return getch();
 
298
  r.h.ah=0x00;
 
299
  int86(0x16,&r,&r);
 
300
  return r.h.al;
 
301
}
 
302
 
 
303
int rgetche(void)
 
304
{
 
305
  int c;
 
306
  if (directvideo) return getche();
 
307
  c=rgetch();
 
308
  rputch(c&0xFF);
 
309
  return c;
 
310
}
 
311
 
 
312
void rgotoxy(int x,int y)
 
313
{
 
314
  if (directvideo) {gotoxy(x,y);return;}
 
315
  r0gotoxy(x-1+winx1,y-1+winy1);
 
316
}
 
317
 
 
318
int rwherex(void)
 
319
{
 
320
  int x,y;
 
321
  if (directvideo) return wherex();
 
322
  get_cur_pos(&x,&y);
 
323
  return x+1-winx1;
 
324
}
 
325
 
 
326
int rwherey(void)
 
327
{
 
328
  int x,y;
 
329
  if (directvideo) return wherey();
 
330
  get_cur_pos(&x,&y);
 
331
  return y+1-winy1;
 
332
}
 
333
 
 
334
 
 
335
 
 
336
#else /* ...if not __DJGPP__ */
 
337
 
 
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
 
348
#define rputs cputs
 
349
#define rputch putch
 
350
#define rgetche getche
 
351
#define rgetch getch
 
352
 
 
353
int rtextmode(int mode)
 
354
{
 
355
  struct text_info term_data;    
 
356
 
 
357
  textmode(mode);
 
358
  gettextinfo(&term_data);
 
359
  return term_data.screenheight;  /* Assume PC dimensions */
 
360
}
 
361
 
 
362
 
 
363
 
 
364
#endif 
 
365
 
 
366
 
 
367
/*------------------------------------------------------------------*/
 
368
/*   Text Style                                                     */
 
369
/*------------------------------------------------------------------*/
 
370
 
 
371
#define STATUS_STATE 0x3800
 
372
#define BOX_STATE 0x2800
 
373
#define START_STATE 0x0800
 
374
 
 
375
/* For state:
 
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
 
379
                       supress blinking
 
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 
 
383
     */
 
384
 
 
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
 
390
 
 
391
typedef unsigned short vstate;
 
392
static vstate state_stack[16];
 
393
int stateptr=0;  /* Points into state stack */
 
394
 
 
395
#define cstate state_stack[stateptr]  /* Current state */
 
396
 
 
397
static void set_state(vstate state)
 
398
{
 
399
  int c; /* Color */
 
400
  int bkgd; /* Background and blink bits */
 
401
 
 
402
  /* 0=normal/1=highlight/2=background/3=statfore/4=statback */
 
403
 
 
404
  if (state & NORM_BIT)
 
405
    c=colorset[cs_normal];
 
406
  else
 
407
    c=state & 0xF;  /* Extract color */
 
408
 
 
409
  if (state & RVID_BIT) {  /* Reverse video */
 
410
    bkgd=colorset[cs_statback];
 
411
    if (state & NORM_BIT)
 
412
      c=colorset[cs_statfore];
 
413
  } else 
 
414
    bkgd=colorset[cs_back];
 
415
 
 
416
  if (state & BOLD_BIT)
 
417
    if (state & NORM_BIT)  
 
418
      c=colorset[cs_bold];
 
419
    else c^=0x08; /* Toggle bold bit */
 
420
 
 
421
  if ( (state & BLINK_BIT) && !(state & STAT_BIT) ) 
 
422
    bkgd|=0x08; /* Blinking */
 
423
 
 
424
  bkgd=(bkgd<<4)|c;
 
425
  rtextattr(bkgd);
 
426
  cstate=state;
 
427
}
 
428
 
 
429
static void reset_state(void)
 
430
{
 
431
  set_state(cstate);
 
432
}
 
433
 
 
434
static void push_state(vstate state)
 
435
{
 
436
  if (stateptr==15) fatal("State stack overflow!");
 
437
  stateptr++;
 
438
  set_state(state);
 
439
}
 
440
 
 
441
static void pop_state(void)
 
442
{
 
443
  if (stateptr==0) fatal("State stack error: POP without PUSH!");
 
444
  stateptr--;
 
445
  set_state(cstate);
 
446
}
 
447
 
 
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 */
 
453
/*      blinking)  */
 
454
/* Also used to set other text attributes: */
 
455
/* -1=emphasized text, used (e.g.) for room titles */
 
456
/* -2=end emphasized text */
 
457
{
 
458
  vstate nstate;
 
459
 
 
460
  nstate=cstate;
 
461
  if (c==-1) 
 
462
    nstate=nstate|0x8000;
 
463
  else if (c==-2) 
 
464
    nstate=nstate & ~0x8000; /* BOLD off */
 
465
  else if (c==8) 
 
466
    nstate=nstate | 0x4000;  /* BLINK on */
 
467
  else if (c==7)  
 
468
    nstate=START_STATE;   /* "Normal" */
 
469
  else if (c==9)
 
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 */
 
473
  set_state(nstate);
 
474
}
 
475
 
 
476
 
 
477
 
 
478
/*------------------------------------------------------------------*/
 
479
/*  Misc. Functions                                                 */
 
480
/*------------------------------------------------------------------*/
 
481
 
 
482
 
 
483
void agt_delay(int n)
 
484
{
 
485
  if (BATCH_MODE) return;
 
486
  print_statline();
 
487
  sleep(n);
 
488
}
 
489
 
 
490
 
 
491
void agt_tone(int hz,int ms)
 
492
/* Produce a hz-Hertz sound for ms milliseconds */
 
493
{
 
494
  if (!sound_on) return;
 
495
  sound(hz);
 
496
  delay(ms);
 
497
  nosound();
 
498
}
 
499
 
 
500
int agt_rand(int a,int b)
 
501
/* Return random number from a to b inclusive */
 
502
{
 
503
    return a+(rand()>>2)%(b-a+1);
 
504
}
 
505
 
 
506
 
 
507
 
 
508
/*------------------------------------------------------------------*/
 
509
/*   Key Tables                                                     */
 
510
/*------------------------------------------------------------------*/
 
511
 
 
512
 
 
513
/*
 
514
   1000= backspace
 
515
   1001= delete
 
516
   1002= left
 
517
   1003= right
 
518
   1004= up
 
519
   1005= down
 
520
   1006= home
 
521
   1007= end
 
522
   1008= page up
 
523
   1009= page down  
 
524
   1010= ins
 
525
   1011= gray plus
 
526
   1012= gray minus
 
527
   10mm= Function key F<n> with mm=n+13 (F0==F10)
 
528
   1500= ^K
 
529
   1501= ^Y
 
530
   1502= ^L
 
531
   2000= unknown control character
 
532
*/
 
533
 
 
534
#define KEY_CNT 25
 
535
#define FKEY_BASE 13
 
536
#define FKEY_CNT  (12+8+4)
 
537
 
 
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 */
 
544
   0x44,  /* F10 */
 
545
   0x3b,0x3c,0x3d,0x3e,0x3f, /* F1-F5 */
 
546
   0x40,0x41,0x42,0x43,  /* F6-F9 */
 
547
   0x57,0x58}; /* F11-F12 */
 
548
 
 
549
 
 
550
static const char *keylist[12]={
 
551
  "del","left","right","up","down","home","end","pgup","pgdn",
 
552
  "ins", "plus", "minus"};
 
553
 
 
554
 
 
555
 
 
556
 
 
557
 
 
558
/*------------------------------------------------------------------*/
 
559
/*   Line Editor                                                    */
 
560
/*------------------------------------------------------------------*/
 
561
 
 
562
static int saved_tab=0;
 
563
 
 
564
unsigned xgetch(void)
 
565
{
 
566
  union REGS r;
 
567
 
 
568
  r.x.ax=0;
 
569
  int86(0x16,&r,&r);
 
570
  return r.x.ax;
 
571
}
 
572
 
 
573
 
 
574
int read_a_key(void)
 
575
{
 
576
  unsigned xc;
 
577
  char c;
 
578
  int i;
 
579
 
 
580
  scroll_count=0;
 
581
  if (saved_tab>0) {
 
582
    saved_tab--;
 
583
    return ' ';
 
584
  }
 
585
  xc=xgetch();
 
586
 
 
587
  if (xc==0x4e2b) xc=0x4e00; /* Gray plus */
 
588
  if (xc==0x4a2d) xc=0x4a00; /* Gray minus */
 
589
  c=xc&0xFF;
 
590
  if ( c!=0 )
 
591
    if (isprint(c)) return c;
 
592
    else if (c=='\n' || c=='\r') return '\n';
 
593
    else if (c=='\t') {
 
594
      saved_tab=4;
 
595
      return ' ';
 
596
    }
 
597
    else if (c=='\001')  /* Ctrl-A ==> Home */
 
598
      return 1006;
 
599
    else if (c=='\005')  /* Ctrl-E ==> End */
 
600
      return 1007;
 
601
    else if (c=='\010')  /* Ctrl-H ==> Backspace */
 
602
      return 1000;
 
603
    else if (c=='\013')  /* Ctrl-K */
 
604
      return 1500;
 
605
    else if (c=='\031') /* Ctrl-Y */
 
606
      return 1501;
 
607
    else if (c=='\014')  /* Ctrl-L */
 
608
      return 1502;
 
609
    else return 2000;
 
610
 
 
611
  /* Get extended code */
 
612
  c=(xc>>8)&0xFF;
 
613
  for(i=0;i<KEY_CNT;i++) {
 
614
    if (c==keytrans[i]) 
 
615
      if (!nav_arrow || i==0 || i>=FKEY_BASE)
 
616
        return 1000+i;
 
617
      else return 1000+FKEY_BASE+12+i-1;
 
618
  }
 
619
  return 2000;
 
620
}
 
621
 
 
622
 
 
623
 
 
624
 
 
625
#ifdef USE_EDITLINE
 
626
 
 
627
void agt_putc(char c)
 
628
{
 
629
#ifdef UNIX
 
630
  fix_loc();  /* Fixup if returning from being suspended */
 
631
#endif
 
632
  printf("%c",c);
 
633
  curr_x+=1;
 
634
}
 
635
 
 
636
static rbool old_yheight=0;
 
637
static int base_x,base_y; /* Base X value of first character of input */
 
638
 
 
639
/* This assumes the cursor is always positioned on the string
 
640
   being edited */
 
641
static void update_cursor(int cursor)
 
642
{
 
643
  int curr_y;
 
644
 
 
645
  curr_x=base_x+cursor;
 
646
  curr_y=base_y;
 
647
  while (curr_x>=screen_width) {
 
648
    curr_x-=screen_width;
 
649
    curr_y++;
 
650
  }
 
651
  rgotoxy(curr_x+1,curr_y+1);
 
652
}
 
653
 
 
654
/* static rbool save_accum_text=0;*/
 
655
 
 
656
static void update_line(int cursor,char *buff)
 
657
{
 
658
  int yval, yheight, xpos, i, curr_y;
 
659
  
 
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) {
 
664
    base_y--;
 
665
    /*    save_accum_text=1;*/ 
 
666
    rputs("\r\n");
 
667
    /* save_accum_text=0;*/
 
668
  }
 
669
  for(yval=yheight;yval<old_yheight;yval++) {
 
670
    rgotoxy(1,base_y+yval+1);
 
671
    cleareol();
 
672
  }
 
673
  old_yheight=yheight;
 
674
  xpos=cursor-1;
 
675
  if (xpos<0) xpos=0;
 
676
  update_cursor(xpos);
 
677
  curr_x=rwherex()-1;
 
678
  curr_y=rwherey()-1;
 
679
  for(yval=curr_y-base_y;yval<yheight;yval++) {
 
680
    cleareol();
 
681
    for(i=curr_x;i<screen_width;i++) {
 
682
      if (buff[xpos]==0) break;
 
683
      rputch(buff[xpos++]);
 
684
    }
 
685
    curr_x=0;
 
686
    if (base_y+yval+status_height<screen_height) 
 
687
      rgotoxy(curr_x+1,base_y+yval+2);
 
688
    else break;
 
689
  }
 
690
  update_cursor(cursor);
 
691
}
 
692
 
 
693
static void redisplay_line(char *buff)
 
694
{
 
695
  update_line(0,buff);
 
696
}
 
697
 
 
698
#define ENABLE_HIST
 
699
static char **hist=NULL;
 
700
static long histcount=0;
 
701
static long histmax=10; 
 
702
 
 
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 */
 
707
{
 
708
  static char *yank_text=NULL;
 
709
  rbool editmode, exitflag;
 
710
  int key;
 
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;
 
716
  int i, curr_hist;
 
717
 
 
718
  buff=rmalloc(2);
 
719
  savebuff=NULL;
 
720
  curr_hist=0;
 
721
  buff[0]=buff[1]=0;
 
722
  cursor=buffleng=0;buffspace=2;
 
723
  base_x=rwherex()-1; base_y=rwherey()-1;
 
724
  editmode=(state==0);
 
725
  saved_tab=0;
 
726
  old_yheight=0;
 
727
  scroll_count=0;
 
728
  exitflag=0;
 
729
 
 
730
#ifdef UNIX
 
731
  set_term_noncanon();
 
732
  keyread=keyptr=0;  /* Clear key-buffer */
 
733
#endif
 
734
 
 
735
  for(;;) {
 
736
    key=read_a_key();
 
737
    if (DEBUG_KEY) printf("{%d}",key);
 
738
    if (key<1000) { /* Real character entered */
 
739
      if (state>0) { /* One key */
 
740
        if (state==1) {
 
741
          agt_putc(key);
 
742
          agt_newline();
 
743
        }
 
744
        buff[0]=key; buff[1]=0;
 
745
        break;
 
746
      } 
 
747
 
 
748
#ifdef ENABLE_HIST
 
749
      if (savebuff!=NULL) {
 
750
        rfree(savebuff);
 
751
        buff=rstrdup(buff);
 
752
        buffspace=buffleng+1;
 
753
      }
 
754
#endif
 
755
      if (key=='\n') {
 
756
        update_cursor(buffleng);      
 
757
        break;
 
758
      }
 
759
      /* add character to buffer */
 
760
      buffleng++;
 
761
      if (buffleng+1>buffspace) buffspace+=20;
 
762
      buff=rrealloc(buff,buffspace);
 
763
      for(i=buffleng;i>cursor;i--)
 
764
        buff[i]=buff[i-1];      
 
765
      buff[cursor++]=key;
 
766
      update_line(cursor,buff);
 
767
    } 
 
768
    else switch(key-1000) 
 
769
      { /* Special key */
 
770
      case 0: /* Backspace */
 
771
        if (!editmode || cursor==0) break;
 
772
        cursor--;
 
773
        /* Fall through... */
 
774
      case 1: /* Delete */
 
775
        if (!editmode || buffleng==cursor) break;
 
776
#ifdef ENABLE_HIST
 
777
        if (savebuff!=NULL) {
 
778
          rfree(savebuff);
 
779
          buff=rstrdup(buff);
 
780
          buffspace=buffleng+1;
 
781
        }
 
782
#endif
 
783
        for(i=cursor;i<buffleng;i++)
 
784
          buff[i]=buff[i+1];
 
785
        buffleng--;
 
786
        update_line(cursor,buff);
 
787
        break;
 
788
      case 2: /* Left arrow */
 
789
        if (editmode && cursor>0) 
 
790
          update_cursor(--cursor);
 
791
        break;
 
792
      case 3: /* Right arrow */
 
793
        if (editmode && cursor<buffleng)          
 
794
          update_cursor(++cursor);
 
795
        break;
 
796
#ifdef ENABLE_HIST
 
797
      case 4: /* Up arrow: Command history */   
 
798
        if (!editmode || histcount==0) break;
 
799
        if (savebuff==NULL) { /* Save current line */
 
800
          savebuff=buff;
 
801
          curr_hist=histcount;
 
802
        }
 
803
        curr_hist--;
 
804
        if (curr_hist<0) {
 
805
          curr_hist=0;  
 
806
          break;
 
807
        }
 
808
        buff=hist[curr_hist];
 
809
        buffleng=strlen(buff);
 
810
        cursor=0;
 
811
        redisplay_line(buff);
 
812
        break;
 
813
      case 5: /* Down arrow: Command history */
 
814
        if (!editmode || savebuff==NULL) break;
 
815
        curr_hist++;
 
816
        if (curr_hist>=histcount) { 
 
817
          /* Reached bottom: restore original line */
 
818
          curr_hist=histcount;
 
819
          buff=savebuff;
 
820
          savebuff=NULL;
 
821
        } else
 
822
          buff=hist[curr_hist];
 
823
        buffleng=strlen(buff);
 
824
        cursor=0;
 
825
        redisplay_line(buff);
 
826
        break;
 
827
#endif
 
828
      case 6: /* Home */
 
829
        if (!editmode) break;
 
830
        cursor=0;
 
831
        update_cursor(cursor);
 
832
        break;
 
833
      case 7: /* End */
 
834
        if (!editmode) break;
 
835
        cursor=buffleng;
 
836
        update_cursor(cursor);
 
837
        break;
 
838
      case 8: /* Page up : Scroll back */
 
839
      case 9: /* Page down */
 
840
        break;
 
841
      case 500: /* Ctrl-K: Delete to EOL */
 
842
        if (!editmode) break;
 
843
#ifdef ENABLE_HIST
 
844
        if (savebuff!=NULL) {
 
845
          rfree(savebuff);
 
846
          buff=rstrdup(buff);
 
847
          buffspace=buffleng+1;
 
848
        }
 
849
#endif
 
850
        rfree(yank_text);
 
851
        yank_text=rstrdup(buff+cursor);
 
852
        buffleng=cursor;
 
853
        buff[buffleng]=0;
 
854
        update_line(cursor,buff);
 
855
        break;
 
856
      case 501:  /* Ctrl-Y: Yank */
 
857
        if (!editmode) break;
 
858
        { 
 
859
          int txtleng;
 
860
#ifdef ENABLE_HIST
 
861
          if (savebuff!=NULL) {
 
862
            rfree(savebuff);
 
863
            buff=rstrdup(buff);
 
864
            buffspace=buffleng+1;
 
865
          }
 
866
#endif
 
867
          if (yank_text==NULL)
 
868
            txtleng=0;
 
869
          else
 
870
            txtleng=strlen(yank_text);
 
871
          buffleng+=txtleng;
 
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);
 
879
          cursor+=txtleng;
 
880
          update_cursor(cursor);
 
881
        }
 
882
        break;
 
883
      case 502: /* Ctrl-L: Redraw screen */
 
884
#ifdef UNIX
 
885
        agt_clrscr();
 
886
        base_y=curr_y;
 
887
        printf("%s",accum_text); /* Redraw prompt */
 
888
        if (editmode) 
 
889
          redisplay_line(buff);
 
890
#endif
 
891
        break;
 
892
 
 
893
      default:
 
894
        if (key<1000+FKEY_BASE || key>=1000+FKEY_BASE+FKEY_CNT)
 
895
          break;
 
896
        if (!editmode) break;
 
897
        { 
 
898
          int txtleng;
 
899
#ifdef ENABLE_HIST
 
900
          if (savebuff!=NULL) {
 
901
            rfree(savebuff);
 
902
            buff=rstrdup(buff);
 
903
            buffspace=buffleng+1;
 
904
          }
 
905
#endif
 
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. */
 
910
            txtleng--;
 
911
            exitflag=1; /* Finish entering this line */
 
912
          }
 
913
          buffleng+=txtleng;
 
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);
 
921
          cursor+=txtleng;
 
922
          update_cursor(cursor);
 
923
        }
 
924
        break;
 
925
      }
 
926
 
 
927
    if (exitflag) break;
 
928
  }
 
929
#ifdef UNIX
 
930
  set_term_normal();
 
931
#endif
 
932
  buff=rrealloc(buff,(buffleng+1));
 
933
  if (state==0) {
 
934
    if (histmax==0 || histcount<histmax) 
 
935
      hist=rrealloc(hist,(++histcount)*sizeof(char*));
 
936
    else 
 
937
      for(i=0;i<histcount-1;i++)
 
938
        hist[i]=hist[i+1];
 
939
    hist[histcount-1]=rstrdup(buff);
 
940
  }
 
941
  return buff;
 
942
}
 
943
#endif
 
944
 
 
945
 
 
946
 
 
947
 
 
948
 
 
949
 
 
950
/*------------------------------------------------------------------*/
 
951
/*   Basic Input and Output Code                                    */
 
952
/*------------------------------------------------------------------*/
 
953
 
 
954
 
 
955
static void script_out(const char *s)
 
956
{
 
957
  if (DEBUG_OUT) 
 
958
    fprintf(debugfile,"%s",s);
 
959
  if (script_on) fprintf(scriptfile,"%s",s);
 
960
}
 
961
 
 
962
 
 
963
 
 
964
int tmpcnt=0;
 
965
 
 
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 */
 
972
{
 
973
#ifndef USE_EDITLINE  
 
974
  static int input_error=0;
 
975
#endif
 
976
  char *s;
 
977
 
 
978
  scroll_count=0;
 
979
  print_statline();
 
980
 
 
981
#ifdef USE_EDITLINE
 
982
  s=line_edit(0);
 
983
#else
 
984
  s=rmalloc(300);
 
985
  s[0]=297;
 
986
  s[1]=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");
 
990
      exit(1);
 
991
    }
 
992
  } input_error=0;
 
993
 
 
994
  s=rrealloc(s,s[1]+3);  
 
995
  memmove(s,s+2,s[1]+1);
 
996
  printf("\n");
 
997
#endif
 
998
 
 
999
  printf("\n");
 
1000
  script_out(s);script_out("\n");
 
1001
  curr_x=rwherex()-1;
 
1002
  return s;
 
1003
}
 
1004
 
 
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) */
 
1010
{
 
1011
  char c;
 
1012
  char s[2];
 
1013
 
 
1014
  scroll_count=0;
 
1015
  print_statline();
 
1016
 
 
1017
  if (echo_char) 
 
1018
    c=rgetche();    /* Get with echo */
 
1019
  else c=rgetch();   /* Get w/o echo */
 
1020
  if (c==0) rgetch(); /* Throw away extended character */
 
1021
  if (echo_char) {
 
1022
    s[0]=c;s[1]=0;
 
1023
    script_out(s);
 
1024
    agt_newline();
 
1025
  }
 
1026
  curr_x=rwherex()-1;
 
1027
  return c;
 
1028
}
 
1029
 
 
1030
 
 
1031
static void print_compass(void)
 
1032
{
 
1033
  int cwidth, i;
 
1034
 
 
1035
  if (status_width< 9+4*12) return;
 
1036
  rgotoxy(1,2);
 
1037
  rputs("  EXITS: ");cwidth=9;
 
1038
  for(i=0;i<12;i++)
 
1039
    if (compass_rose & (1<<i)) {
 
1040
      rputs(exitname[i]);
 
1041
      rputs(" ");
 
1042
      cwidth+=strlen(exitname[i])+1;
 
1043
    }
 
1044
  for(i=cwidth;i<status_width;i++) rputs(" ");
 
1045
}
 
1046
 
 
1047
 
 
1048
static rbool is_fullscreen; /* True until we print the first status line */
 
1049
 
 
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) */
 
1053
{
 
1054
   int savex, savey;
 
1055
 
 
1056
   savex=rwherex();savey=rwherey()+top_row;  /* Save old postion */
 
1057
   if (is_fullscreen) { /* Need to move text down a bit */
 
1058
        int i;
 
1059
        rgotoxy(1,1);
 
1060
        for(i=0;i<status_height;i++)
 
1061
          rinsline();
 
1062
   }
 
1063
   rwindow(1,1,screen_width,screen_height);  /* Set window to whole screen */
 
1064
   rgotoxy(1,1);
 
1065
   push_state(STATUS_STATE);
 
1066
   rputs(s);  /* Console put string */
 
1067
   if (have_compass) {
 
1068
     status_height=2;
 
1069
     top_row=3;
 
1070
     print_compass();
 
1071
   } else {
 
1072
     top_row=2;
 
1073
     status_height=1;
 
1074
   }
 
1075
   pop_state();
 
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 */
 
1079
   return;
 
1080
}
 
1081
 
 
1082
 
 
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) */
 
1086
{
 
1087
  rclrscr();
 
1088
  curr_x=0;
 
1089
  if (DEBUG_OUT) fprintf(stderr,"\n\n<RCLRSCR>\n\n");
 
1090
  if (script_on) fprintf(scriptfile,"\n\n\n\n");
 
1091
  scroll_count=0;
 
1092
}
 
1093
 
 
1094
rbool cursor_wrap;
 
1095
 
 
1096
void agt_puts(const char *s)
 
1097
{
 
1098
  int old_x;
 
1099
  old_x=rwherex()-1;
 
1100
  rputs(s);
 
1101
  curr_x=rwherex()-1;
 
1102
  if (curr_x<old_x+strlen(s))  /* We wrapped */
 
1103
    cursor_wrap=1;
 
1104
  if (DEBUG_OUT) fprintf(stderr,"%s",s);
 
1105
  if (script_on) fprintf(scriptfile,"%s",s);
 
1106
}
 
1107
 
 
1108
void agt_newline(void)
 
1109
{
 
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");
 
1114
  scroll_count++;
 
1115
  if (scroll_count>=screen_height-status_height-1) {
 
1116
    rputs("  --MORE--"); /* Notice: no newline */
 
1117
    agt_waitkey();
 
1118
    rgotoxy(1,rwherey()); /* Move to beginning of line */
 
1119
    rclreol();  /* Clear to end of line: erase the --MORE-- */
 
1120
  }
 
1121
}
 
1122
 
 
1123
 
 
1124
 
 
1125
 
 
1126
/*------------------------------------------------------------------*/
 
1127
/*  Text Box Routines                                               */
 
1128
/*------------------------------------------------------------------*/
 
1129
 
 
1130
 
 
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
 
1135
                            with the box */
 
1136
 
 
1137
static void box_border(char *c)
 
1138
{
 
1139
#ifdef DRAW_BORDER
 
1140
  agt_puts(c);
 
1141
#else
 
1142
  agt_puts(" ");
 
1143
#endif
 
1144
}
 
1145
 
 
1146
 
 
1147
#define VLINE_STR "\263"  /* 0xB3 or 0xBA */
 
1148
 
 
1149
static void boxrule(int bottom)
 
1150
/* Draw line at top or bottom of box */
 
1151
 
1152
  int i;
 
1153
 
 
1154
  if (bottom) 
 
1155
    box_border("\300"); /* 0xC0 or 0xC8 */   
 
1156
  else 
 
1157
    box_border("\332"); /* 0xDA or 0xC9 */
 
1158
  for(i=0;i<box_width+2;i++) box_border("\304");  /* 0xC4 or 0xCD */
 
1159
  if (bottom)
 
1160
    box_border("\311");  /* 0xC9 or 0xBC */
 
1161
  else
 
1162
    box_border("\277"); /* 0xBF or 0xBB */
 
1163
}
 
1164
 
 
1165
 
 
1166
static void boxpos(void)
 
1167
{
 
1168
  int curr_y;
 
1169
 
 
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);
 
1173
  curr_x=box_startx;
 
1174
}
 
1175
 
 
1176
void agt_makebox(int width,int height,unsigned long flags)
 
1177
/* Flags: TB_TTL, TB_BORDER, TB_NOCENT */
 
1178
{
 
1179
  int box_starty;
 
1180
 
 
1181
  boxflags=flags;
 
1182
  box_width=width;
 
1183
  if (boxflags&TB_BORDER) {  /* Add space for border */
 
1184
    width+=4;
 
1185
    height+=2;
 
1186
  }
 
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;
 
1190
 
 
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;
 
1197
    delta_scroll=0;
 
1198
    scroll_count=0;
 
1199
    rwindow(1,1,screen_width,screen_height); /* Titles get the whole screen */
 
1200
    is_fullscreen=1;
 
1201
  } else {  /* Compute vertical position of non-title box */
 
1202
    box_starty=rwherey()-1-height;
 
1203
    if (box_starty<1) {
 
1204
      delta_scroll=1-box_starty;
 
1205
      box_starty=1;
 
1206
    } else delta_scroll=0;
 
1207
  }
 
1208
 
 
1209
  curr_x=box_startx;
 
1210
  rgotoxy(box_startx+1,box_starty+1);
 
1211
 
 
1212
  if (boxflags&TB_BORDER) {
 
1213
    push_state(BOX_STATE);
 
1214
    boxrule(0);
 
1215
    boxpos();
 
1216
    box_border(VLINE_STR);
 
1217
    agt_puts(" ");
 
1218
  }
 
1219
}
 
1220
 
 
1221
void agt_qnewline(void)
 
1222
{
 
1223
  if (boxflags&TB_BORDER) { 
 
1224
    agt_puts(" ");
 
1225
    box_border(VLINE_STR);
 
1226
  }
 
1227
  boxpos();
 
1228
  if (boxflags&TB_BORDER) {
 
1229
    box_border(VLINE_STR);
 
1230
    agt_puts(" ");
 
1231
  }
 
1232
}
 
1233
 
 
1234
void agt_endbox(void)
 
1235
{
 
1236
  if (boxflags&TB_BORDER) {
 
1237
    agt_puts(" ");
 
1238
    box_border(VLINE_STR);
 
1239
    boxpos();
 
1240
    boxrule(1);
 
1241
    pop_state();
 
1242
  }
 
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();
 
1247
}
 
1248
 
 
1249
 
 
1250
 
 
1251
/*------------------------------------------------------------------*/
 
1252
/*   CFG Editor (In development)                                    */
 
1253
/*------------------------------------------------------------------*/
 
1254
#if 0
 
1255
 
 
1256
static char **readconf(fc_type fc)
 
1257
{
 
1258
 
 
1259
}
 
1260
 
 
1261
 
 
1262
static void writeconf(fc_type fc, char **conf)
 
1263
{
 
1264
 
 
1265
}
 
1266
 
 
1267
 
 
1268
static char *edops[]={"color","navarrow","tone","compass","input_bold"};
 
1269
 
 
1270
 
 
1271
static rbool checkopt(int i)
 
1272
     /* Return true if option i is true */
 
1273
{
 
1274
  switch(i) {
 
1275
    case 1:return nav_arrow;  
 
1276
    case 2:return PURE_TONE;
 
1277
    case 3:return have_compass;
 
1278
    case 4:return PURE_INPUT;
 
1279
    default: return 1;
 
1280
  }
 
1281
}  
 
1282
 
 
1283
 
 
1284
static void savechange(fc_type fc, uchar changes)
 
1285
     /* Call this to save changes to configuration */
 
1286
{
 
1287
  char **conf, *s;
 
1288
  int i;
 
1289
  int lopt[5];
 
1290
  /* lxxx holds the line number of xxx */
 
1291
 
 
1292
  lcolor=lnavarrow=lcompass=ltone=linputbold=-1;  
 
1293
  conf=readconf(fc);
 
1294
  for(numline=0;conf[numline]!=NULL;numline++) {
 
1295
    /* Detect COLOR, NAVARROW, TONE, COMPASS, INPUT_BOLD */
 
1296
    s=conf[numline];
 
1297
    while(strncasecmp(s,"no_",3)==0) s+=3;
 
1298
    for(i=0;i<5;i++)
 
1299
      if (strncasecmp(s,edops[i],strlen(edops[i]))==0) {
 
1300
        lopt[i]=numline;
 
1301
        break;
 
1302
      }
 
1303
  }
 
1304
 
 
1305
  /* Rebuild config file */
 
1306
  for(i=0;i<5;i++, changes>>=1)
 
1307
    if (changes & 1) { /* Check bit */
 
1308
 
 
1309
      if (i==0) { /* COLOR */
 
1310
        int j;
 
1311
        s=rmalloc(5+5*15); /* More than enough space */
 
1312
        strcpy(s,"color");
 
1313
        for(j=0;j<5;j++) {
 
1314
          strcat(s," ");
 
1315
          strcat(s,colorname[colorset[j]]);
 
1316
        }
 
1317
 
 
1318
      } else { /* Non-COLOR options */
 
1319
        s=rmalloc(strlen(edops[i])+4); /* Room for NO_ & \0 */
 
1320
        if (!checkopt(i))
 
1321
          strcpy(s,"no_");
 
1322
        else s[0]=0;
 
1323
        strcat(s,edops[i]);
 
1324
      }
 
1325
 
 
1326
      if (i>=0) {  /* Change existing line */
 
1327
        rfree(conf[numline]); 
 
1328
        conf[numline]=s;       
 
1329
      } else {   /* Add new line */
 
1330
        conf=rrealloc(++numline);
 
1331
        conf[numline-1]=s;
 
1332
        conf[numline]=NULL;
 
1333
      }
 
1334
 
 
1335
    }
 
1336
  writeconf(fc, conf);
 
1337
 
 
1338
  for(i=0;i<numline;i++)
 
1339
    rfree(conf[i]);
 
1340
  rfree(conf);
 
1341
}
 
1342
 
 
1343
 
 
1344
void editconf(void)
 
1345
{
 
1346
 
 
1347
 
 
1348
  
 
1349
 
 
1350
}
 
1351
 
 
1352
 
 
1353
 
 
1354
 
 
1355
 
 
1356
#endif
 
1357
/*------------------------------------------------------------------*/
 
1358
/*   Parsing CONFIG Options                                         */
 
1359
/*------------------------------------------------------------------*/
 
1360
 
 
1361
const char *colorname[16]=
 
1362
{"black","blue","green","cyan","red","magenta","brown","lightgray",
 
1363
 "darkgray","lightblue","lightgreen","lightcyan","lightred","lightmagenta",
 
1364
"yellow","white"};
 
1365
 
 
1366
static int parse_color(int index,char *cname)
 
1367
{
 
1368
  int i;
 
1369
  for(i=0;i<16;i++)
 
1370
    if(strcasecmp(colorname[i],cname)==0) return i;
 
1371
  return colorset[index];
 
1372
}
 
1373
 
 
1374
 
 
1375
static void getcolors(int cnum,char *clist[])
 
1376
{
 
1377
  int i;
 
1378
 
 
1379
  if (cnum>5) cnum=5;
 
1380
  for(i=0;i<cnum;i++)
 
1381
    colorset[i]=parse_color(i,clist[i]);
 
1382
  colorset[cs_back]&=0x7;
 
1383
  colorset[cs_statback]&=0x7;
 
1384
}
 
1385
 
 
1386
 
 
1387
/* Duplicate s and add '/' if neccessary */
 
1388
char *makepathentry(char *s)
 
1389
{
 
1390
  char *p;
 
1391
  int n;
 
1392
  rbool addslash;
 
1393
 
 
1394
  addslash=0;
 
1395
  n=strlen(s);
 
1396
  if (s[n-1]!='\\') addslash=1;
 
1397
  p=rmalloc(n+addslash+1);
 
1398
  strcpy(p,s);
 
1399
  if (addslash) {
 
1400
    p[n]='\\';
 
1401
    p[n+1]=0; /* Mark new end of string */
 
1402
  }
 
1403
  return p;
 
1404
}
 
1405
 
 
1406
void free_gamepath(void)
 
1407
{
 
1408
  char **p;
 
1409
 
 
1410
  if (gamepath==NULL) return;
 
1411
 
 
1412
  /* We skip the first element which always points to "" */
 
1413
  for(p=gamepath+1;*p!=NULL;p++)
 
1414
    rfree(*p);
 
1415
  rfree(gamepath);
 
1416
}
 
1417
 
 
1418
 
 
1419
#define opt(s) (!strcasecmp(optstr[0],s))
 
1420
 
 
1421
void set_fkey(char *keyname, char *words[], int numwords)
 
1422
{
 
1423
  int n,i,leng;
 
1424
  char *s;
 
1425
  rbool err;
 
1426
  static long keys_defined=0;
 
1427
 
 
1428
  err=0; n=0;
 
1429
  if (tolower(keyname[0])!='f') {
 
1430
    err=1;
 
1431
    for(i=0;i<12;i++) 
 
1432
      if (0==strcasecmp(keylist[i],keyname)) {
 
1433
        err=0;
 
1434
        n=i+12;
 
1435
      }
 
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;
 
1439
    if (n>12) err=1;
 
1440
    if (n==10) n=0;
 
1441
    if (n>10) n--;
 
1442
  }
 
1443
  if (err) {
 
1444
    writeln("Unrecognized KEY name.");
 
1445
    return;
 
1446
  }
 
1447
 
 
1448
  leng=0;
 
1449
  for(i=0;i<numwords;i++)
 
1450
    leng+=strlen(words[i]);
 
1451
  s=rmalloc(leng+numwords+1);
 
1452
  s[0]=0;
 
1453
 
 
1454
  /* This isn't very efficient, but it doesn't need to be. */
 
1455
  for(i=0;i<numwords;i++) {
 
1456
    strcat(s,words[i]);
 
1457
    strcat(s," ");
 
1458
  }
 
1459
  i=strlen(s)-2;
 
1460
  if (i>=0 && s[i]=='+') {
 
1461
    s[i]='\n';
 
1462
    s[i+1]=0;
 
1463
  }
 
1464
 
 
1465
  if (keys_defined & (1<<n)) rfree(fkey_text[n]);
 
1466
  fkey_text[n]=s;
 
1467
  keys_defined|=(1<<n);
 
1468
}
 
1469
 
 
1470
 
 
1471
#define opt(s) (!strcasecmp(optstr[0],s))
 
1472
 
 
1473
rbool agt_option(int optnum,char *optstr[],rbool setflag)
 
1474
/* If setflag is 0, then the option was prefixed with NO_ */
 
1475
{
 
1476
  int i;
 
1477
 
 
1478
  if (optnum==0) return 1;
 
1479
  if (opt("COMPASS")) {
 
1480
    have_compass=1;
 
1481
    return 1;
 
1482
  }
 
1483
  if (opt("FONT")) {
 
1484
    font_enable=setflag;
 
1485
    return 1;
 
1486
  }
 
1487
  if (opt("NAVARROW")) {
 
1488
    nav_arrow=setflag;
 
1489
    return 1;
 
1490
  }
 
1491
  if (opt("BIOS")) {
 
1492
    use_bios=setflag;
 
1493
    return 1;
 
1494
  }
 
1495
  if (opt("BLOCK_CURSOR")) {
 
1496
    block_cursor=setflag;
 
1497
    return 1;
 
1498
  }
 
1499
  if (opt("COLORS") || opt("COLOURS")) {
 
1500
    getcolors(optnum-1,optstr+1);
 
1501
    return 1;}
 
1502
  if (opt("HISTORY")) {
 
1503
    histmax=strtol(optstr[1],NULL,10);
 
1504
    if (histmax<0) histmax=0;
 
1505
    return 1;
 
1506
  }
 
1507
  if (opt("50_LINE")) {
 
1508
    tall_screen=setflag;
 
1509
    return 1;
 
1510
  }
 
1511
  if (opt("KEY") && optnum>=2) {
 
1512
    set_fkey(optstr[1],optstr+2,optnum-2);
 
1513
    return 1;
 
1514
  }
 
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;
 
1522
    return 1;
 
1523
  }
 
1524
  return 0;
 
1525
}
 
1526
 
 
1527
#undef opt
 
1528
 
 
1529
static char *progname;
 
1530
static const char *cfgname="agil.cfg";
 
1531
 
 
1532
FILE *agt_globalfile(int fid)
 
1533
{
 
1534
  char *s,*t;
 
1535
  FILE *f;
 
1536
 
 
1537
  if (fid==0 && progname!=NULL) {
 
1538
    s=rstrdup(progname);
 
1539
    t=s+strlen(s);
 
1540
    while (t!=s && *t!='\\' && *t!=':') t--; 
 
1541
    if (*t!=0) t++;
 
1542
    *t=0;
 
1543
    s=rrealloc(s,strlen(s)+strlen(cfgname)+1);
 
1544
    strcat(s,cfgname);
 
1545
    f=fopen(s,"rb");
 
1546
    rfree(s);
 
1547
    return f;
 
1548
  }
 
1549
  return NULL;
 
1550
}
 
1551
 
 
1552
 
 
1553
 
 
1554
 
 
1555
 
 
1556
/*------------------------------------------------------------------*/
 
1557
/*  Initialization and Shutdown                                     */
 
1558
/*------------------------------------------------------------------*/
 
1559
 
 
1560
static void id_hardware(void)
 
1561
{
 
1562
  union REGS r;
 
1563
 
 
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 */
 
1568
  int86(0x10,&r,&r);
 
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 */
 
1573
 
 
1574
    if (r.h.bl==0) graph_hardware=EGA64;
 
1575
    else graph_hardware=EGA;
 
1576
 
 
1577
    r.x.ax=0x1A00;
 
1578
    int86(0x10,&r,&r);
 
1579
    if (r.h.al==0x1A) /* We have a VGA */
 
1580
      graph_hardware=VGA;
 
1581
 
 
1582
  } else { /* MDA/CGA/MCGA */
 
1583
    r.x.ax=0x1A00;
 
1584
    int86(0x10,&r,&r);
 
1585
    if (r.h.al==0x1A) { /* We have an MCGA */
 
1586
      graph_hardware=MCGA;
 
1587
      return;
 
1588
    }
 
1589
 
 
1590
    graph_hardware=CGA;
 
1591
 
 
1592
    r.h.ah=0x0F; /* Get current video mode */
 
1593
    int86(0x10,&r,&r);
 
1594
    if ((r.h.al & 0x7F)==7)
 
1595
      graph_hardware=MDA;
 
1596
  }
 
1597
}
 
1598
 
 
1599
 
 
1600
static int save_mode;
 
1601
static int save_attr;
 
1602
 
 
1603
void init_interface(int argc,char *argv[])
 
1604
{
 
1605
  struct text_info term_data;
 
1606
 
 
1607
  active_font=NULL;
 
1608
 
 
1609
  id_hardware();
 
1610
 
 
1611
  if (argc>0) progname=argv[0]; else progname=NULL;
 
1612
  script_on=0;scriptfile=NULL;
 
1613
  scroll_count=0;
 
1614
  cursor_wrap=0;
 
1615
  font_enable=1;
 
1616
  nav_arrow=0;
 
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. */
 
1625
  use_bios=0;  
 
1626
  rtextmode(C80);  /* Change to color, 80 column mode */
 
1627
  screen_height=25;  /* Assume PC dimensions */
 
1628
  status_width=screen_width=80;
 
1629
  rclrscr();
 
1630
  rwindow(1,1,screen_width,screen_height); is_fullscreen=1;
 
1631
  top_row=1;
 
1632
  rgotoxy(1,1); /* Upper-left hand corner of just defined window */
 
1633
}
 
1634
 
 
1635
void start_interface(fc_type fc)
 
1636
{
 
1637
  if (tall_screen) { 
 
1638
    screen_height=rtextmode(C4350);  /* Change to color, 80 column mode */
 
1639
    rclrscr();
 
1640
    rgotoxy(1,1); /* Upper-left hand corner of just defined window */
 
1641
  }
 
1642
  directvideo=!use_bios; /* Set directvideo according to options */
 
1643
  free_gamepath();
 
1644
  if (stable_random)
 
1645
    srand(6);
 
1646
  else 
 
1647
    srand(time(0));
 
1648
  gamefile_name=fc->gamename;
 
1649
  if (block_cursor)
 
1650
    r_setcursortype(_SOLIDCURSOR);
 
1651
  else
 
1652
    r_setcursortype(_NORMALCURSOR);
 
1653
  rclrscr();
 
1654
  curr_x=0;scroll_count=0;
 
1655
  if (have_compass)
 
1656
     status_height=2;
 
1657
  else
 
1658
      status_height=1;
 
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
 
1661
                      is printed */
 
1662
  top_row=status_height+1;
 
1663
  set_state(7);
 
1664
}
 
1665
 
 
1666
void close_interface(void)
 
1667
{
 
1668
  if (scriptfile!=NULL)
 
1669
    fclose(scriptfile);
 
1670
  agt_newline();agt_newline();
 
1671
  if (block_cursor) r_setcursortype(_NORMALCURSOR);
 
1672
  rtextmode(save_mode);
 
1673
  rtextattr(save_attr);
 
1674
  rgotoxy(1,25);
 
1675
  rclreol();
 
1676
  rgotoxy(1,24);
 
1677
  rclreol();
 
1678
 /* rclrscr();*/
 
1679
}
 
1680
 
 
1681
 
 
1682
 
 
1683
 
 
1684
 
 
1685
 
 
1686
#ifdef REPLACE_BNW
 
1687
 
 
1688
/*------------------------------------------------------------------*/
 
1689
/*   GRAPHICS AND FONT SUPPORT                                      */
 
1690
/*------------------------------------------------------------------*/
 
1691
 
 
1692
 
 
1693
/* This cheats a bit, using "hidden" data from filename.c */
 
1694
 
 
1695
static FILE *linopen(char *name, char *ext)
 
1696
{
 
1697
  FILE *f;
 
1698
  char *fname;
 
1699
 
 
1700
  fname=assemble_filename(hold_fc->path,name,ext);
 
1701
  f=fopen(fname,"rb");
 
1702
  rfree(fname);
 
1703
  return f;
 
1704
}
 
1705
 
 
1706
/*------------------------------------------------------------------*/
 
1707
/* FONT Routines                                                    */
 
1708
/*------------------------------------------------------------------*/
 
1709
 
 
1710
static char *save_font;
 
1711
static int save_font_height;
 
1712
 
 
1713
static int set_font(char *fontdef, int font_height)
 
1714
{
 
1715
#ifdef MSDOS16
 
1716
  struct REGPACK r;
 
1717
 
 
1718
  r.r_ax=0x1100;
 
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;
 
1724
  intr(0x10,&r);
 
1725
 
 
1726
#else /* MSDOS32 */
 
1727
 
 
1728
  __dpmi_regs r;
 
1729
 
 
1730
  /* If the transfer buffer isn't large enough, we just silently fail.
 
1731
     We should really do something like allocate our own buffer 
 
1732
     in this case. */
 
1733
  if (font_height*256>_go32_info_block.size_of_transfer_buffer)
 
1734
    return 1; 
 
1735
 
 
1736
  r.x.ax=0x1100;
 
1737
  r.h.bh=font_height; /* 8 bytes per character in BH; 0 in BL */
 
1738
  r.h.bl=0; 
 
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);
 
1745
#endif
 
1746
  return 0;
 
1747
}
 
1748
 
 
1749
 
 
1750
static void save_old_font(void)
 
1751
{
 
1752
  union REGS r;
 
1753
 
 
1754
  if (graph_hardware<MCGA) {
 
1755
    /* User-defined fonts aren't supported */
 
1756
    font_enable=0;
 
1757
    return;
 
1758
  }
 
1759
 
 
1760
  r.x.ax=0x1130;
 
1761
  r.h.bh=0;
 
1762
  int86(0x10,&r,&r);
 
1763
  save_font_height=r.x.cx;
 
1764
}
 
1765
 
 
1766
 
 
1767
static void restore_font(void)
 
1768
{
 
1769
    union REGS r;
 
1770
 
 
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 */
 
1775
    else
 
1776
      r.x.ax=0x1102;  /* 8x8 */
 
1777
    r.h.bl=0;
 
1778
    int86(0x10,&r,&r);
 
1779
    /* ... if MCGA ... */
 
1780
    /* if (graph_hardware==MCGA) {*/
 
1781
      r.x.ax=0x1103;
 
1782
      r.h.bl=0;
 
1783
      int86(0x10,&r,&r);
 
1784
    /* } */
 
1785
}
 
1786
 
 
1787
 
 
1788
 
 
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)
 
1793
*/
 
1794
{
 
1795
  FILE *fontfile;
 
1796
  char *buff, *fontname;
 
1797
  int height;
 
1798
 
 
1799
  if (!font_enable) return;
 
1800
 
 
1801
  if (cmd==2)
 
1802
    save_old_font();
 
1803
  if (!font_enable) return;
 
1804
 
 
1805
 
 
1806
  if (cmd==0 || cmd==2) {
 
1807
    if (cmd==0) {
 
1808
      fontname=fontlist[font];
 
1809
    }
 
1810
    else fontname=gamefile_name;
 
1811
 
 
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) {
 
1817
      /* Error message */
 
1818
      return;
 
1819
    }
 
1820
    height=height/256;
 
1821
    buff=rmalloc(256*height);
 
1822
    memset(buff,0,256*height);
 
1823
 
 
1824
    fseek(fontfile,0,SEEK_SET);
 
1825
    if (fread(buff,height,256,fontfile)!=256) {
 
1826
        fclose(fontfile);
 
1827
        rfree(buff);
 
1828
        return;
 
1829
    }
 
1830
    fclose(fontfile);
 
1831
    if (set_font(buff,height)) {
 
1832
      /* Print error message */
 
1833
    }
 
1834
    rfree(active_font);
 
1835
    active_font=buff;
 
1836
    active_font_height=height;
 
1837
    return;
 
1838
  } else if (cmd==1) {
 
1839
    rfree(active_font);
 
1840
    restore_font();
 
1841
  }
 
1842
}
 
1843
 
 
1844
 
 
1845
 
 
1846
 
 
1847
 
 
1848
/*------------------------------------------------------------------*/
 
1849
/*   Graphics Support                                               */
 
1850
/*------------------------------------------------------------------*/
 
1851
 
 
1852
static rbool in_gmode=0;
 
1853
 
 
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 */
 
1860
 
 
1861
/* Modes 1-4 differ only in pallette */
 
1862
 
 
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};
 
1868
 
 
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};
 
1874
  
 
1875
 
 
1876
int pick_gmode(int gmode, int pmode, int xsize, int ysize)
 
1877
{
 
1878
  int save_gmode, work_gmode;
 
1879
 
 
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)
 
1883
      return gmode;
 
1884
 
 
1885
  save_gmode=gmode; work_gmode=-1;
 
1886
  /* Okay, we don't know what mode we are; try to pick the best for
 
1887
     this image */
 
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))
 
1893
      continue;
 
1894
    if (gmode==5 && graph_hardware==MCGA) continue;
 
1895
 
 
1896
    if (paltype[gmode]!=pmode) continue;
 
1897
    work_gmode=gmode;
 
1898
    if (mode_x[gmode]<xsize || mode_y[gmode]<ysize) continue;
 
1899
    return gmode;
 
1900
  }
 
1901
  return work_gmode; /* May need to be clipped */
 
1902
}
 
1903
 
 
1904
 
 
1905
int pix_per_byte[]={8,4,8,1};
 
1906
 
 
1907
/* 8421  */
 
1908
/* IRGB */
 
1909
 
 
1910
#define BPI 8
 
1911
#define BPR 4
 
1912
#define BPG 2
 
1913
#define BPB 1
 
1914
 
 
1915
#ifdef MSDOS16
 
1916
typedef uchar* graphptr;
 
1917
#define graphwrite(dst,src,leng) memcpy(dst,src,leng)
 
1918
#else /* MSDOS32 */
 
1919
typedef unsigned long graphptr;
 
1920
#define graphwrite(dst,src,leng) dosmemput(src,leng,dst)
 
1921
#endif
 
1922
 
 
1923
void draw_scanline(uchar *linebuff,int gmode,int y_start,
 
1924
                   int linesize,int sizex)
 
1925
{
 
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;
 
1931
  int i;
 
1932
 
 
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 */
 
1936
 
 
1937
#ifdef MSDOS16
 
1938
    if (gmode<=4) target=(uchar*)0xB8000000L;
 
1939
    else target=(uchar*)0xA0000000L;
 
1940
#else /* MSDOS32 */
 
1941
    if (gmode<=4) target=0xB8000L;
 
1942
    else target=0xA0000L;
 
1943
#endif
 
1944
 
 
1945
    target+=i+y_start*mode_bpl;
 
1946
 
 
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 */
 
1953
 
 
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) */
 
1961
 
 
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 */
 
1972
    }
 
1973
    return;
 
1974
  }
 
1975
 
 
1976
  target+=mode_bpl; /* Move to beginning of next line */
 
1977
 
 
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 */
 
1984
    for(i=0;i<4;i++) {
 
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);
 
1989
    }
 
1990
  }
 
1991
}
 
1992
 
 
1993
 
 
1994
 
 
1995
/* This flips the bits and separates them by three bits */
 
1996
static const uchar paltrans[]={0,8,1,9};
 
1997
 
 
1998
 
 
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 */
 
2002
{
 
2003
  red>>=6;
 
2004
  green>>=6;
 
2005
  blue>>=6; 
 
2006
  return paltrans[blue]+(paltrans[green]<<1)+(paltrans[red]<<2);
 
2007
}
 
2008
 
 
2009
 
 
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)
 
2013
{
 
2014
#ifdef MSDOS16
 
2015
  union REGS r;
 
2016
  struct SREGS segreg;
 
2017
#else /* MSDOS32 */
 
2018
  __dpmi_regs r;
 
2019
#endif
 
2020
 
 
2021
  if (!dacflag) 
 
2022
    r.x.ax=0x1002;
 
2023
  else {
 
2024
    r.x.ax=0x1012;
 
2025
    r.x.bx=0;
 
2026
    r.x.cx=leng;
 
2027
  }
 
2028
#ifdef MSDOS16
 
2029
  r.x.dx=((long)palptr)&0xFFFF;
 
2030
  segreg.es=((long)palptr)>>16;
 
2031
  int86x(0x10,&r,&r,&segreg);
 
2032
#else /* MSDOS32 */
 
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);
 
2037
#endif
 
2038
}
 
2039
 
 
2040
 
 
2041
#define ival(n) (header[n]+(header[n+1]<<8))
 
2042
 
 
2043
 
 
2044
static rbool setup_card(FILE *pcxfile,uchar *header,int gmode, int pmode)
 
2045
{
 
2046
  int i;
 
2047
  uchar *tmppal, *pal;
 
2048
  int havepal; /* 0=No, 1=Yes, but not VGA, 2=Yes, maybe VGA */
 
2049
  union REGS r;
 
2050
 
 
2051
  if (header[1]==5) havepal=2;
 
2052
  else if (header[1]==2) havepal=1;
 
2053
  else havepal=0;
 
2054
 
 
2055
  if (pmode==3 && havepal!=2) {
 
2056
    writeln("ERROR: PCX file corrupted: bad color depth.");
 
2057
    return 0;
 
2058
  }
 
2059
 
 
2060
  /*-------------------------------------*/
 
2061
  /* Read in VGA palette                 */
 
2062
  /*-------------------------------------*/
 
2063
 
 
2064
  /* Next, read in the VGA palette if neccessary */
 
2065
  pal=NULL;
 
2066
  if (pmode==3) { /* VGA palette */
 
2067
    uchar c;
 
2068
    long n;
 
2069
 
 
2070
    pal=rmalloc(256*3);
 
2071
    fseek(pcxfile,0,SEEK_END);
 
2072
    n=ftell(pcxfile);
 
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.");
 
2076
       rfree(pal);
 
2077
       return 0;
 
2078
    }
 
2079
    if (c!=12) {
 
2080
      writeln("ERROR: PCX file corrupted: bad palette.");
 
2081
      rfree(pal);
 
2082
      return 0;
 
2083
    }
 
2084
    if (fread(pal,768,1,pcxfile)!=1) {
 
2085
       writeln("GAME ERROR: Errors reading palette from picture file.");
 
2086
       rfree(pal);
 
2087
       return 0;
 
2088
    }
 
2089
  }
 
2090
 
 
2091
 
 
2092
  /*-------------------------------------*/
 
2093
  /* Set up video mode                   */
 
2094
  /*-------------------------------------*/
 
2095
 
 
2096
  /* -- Need to save old video state here -- */
 
2097
 
 
2098
  /* Set video mode */
 
2099
  r.x.ax=mode[gmode];
 
2100
  int86(0x10,&r,&r);
 
2101
  in_gmode=1;
 
2102
 
 
2103
  /*-------------------------------------*/
 
2104
  /* Set up Palette                      */
 
2105
  /*-------------------------------------*/
 
2106
 
 
2107
#if 0
 
2108
  if (pmode==2 && paltype[gmode]==3) {
 
2109
    /* Set up fake EGA palette */
 
2110
    pal=rmalloc(256*3);
 
2111
    for(i=0;i<3*16;i++) 
 
2112
      pal[i]=header[16+i];
 
2113
    for(i=3*16;i<3*256;i++)
 
2114
      pal[i]=0;
 
2115
  } else if (pmode<=1 && paltype[gmode]==2) {
 
2116
    /* This could occur with a high resolution 2 or 4 color image */
 
2117
 
 
2118
    fatal("Unsupported image class.");
 
2119
 
 
2120
  } else assert(pmode==paltype[gmode]);
 
2121
#endif
 
2122
 
 
2123
  assert(pmode==paltype[gmode]);
 
2124
 
 
2125
  /* Now to set the palette */
 
2126
  if (paltype[gmode]==1) { /* CGA palette */
 
2127
    r.h.ah=0x0B;
 
2128
    r.h.bh=1;
 
2129
    if (pmode==1 && havepal!=0)
 
2130
      r.h.bl=(header[19]>>6)&0x01;
 
2131
    else 
 
2132
      r.h.bl=(gmode-1)>>1; /* Top bit==> palette */
 
2133
    int86(0x10,&r,&r);
 
2134
 
 
2135
    r.h.ah=0x0B; /* Set background and intensity bits */
 
2136
    r.h.bh=0;
 
2137
    if (pmode==1 && havepal!=0) 
 
2138
      r.h.bl= ( (header[19]>>1) & 0x10 ) | (header[16]>>4);
 
2139
    else
 
2140
      r.h.bl=((gmode-1)&1)<<4; /* Background will be 0. */
 
2141
  }
 
2142
  else if (paltype[gmode]==2 && havepal!=0) {  /* EGA Palette */
 
2143
    tmppal=rmalloc(17);
 
2144
    if (graph_hardware!=VGA)
 
2145
      for(i=0;i<16;i++)
 
2146
        tmppal[i]=build_ega_pal(header[16+3*i],
 
2147
                                header[17+3*i],
 
2148
                                header[18+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);
 
2152
    rfree(tmppal);
 
2153
 
 
2154
    if (graph_hardware==VGA) { /* Now reprogram the DAC */
 
2155
      tmppal=rmalloc(17*3);
 
2156
      for(i=0;i<16;i++) {
 
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;          
 
2160
      }
 
2161
      tmppal[0]=tmppal[1]=tmppal[2]=0; /* Overscan color is black */
 
2162
      bios_set_pal(tmppal,17,1);
 
2163
    }
 
2164
  } else if (paltype[gmode]==3 && havepal!=0) { /* MCGA Palette */
 
2165
    for(i=0;i<256*3;i++)
 
2166
      pal[i]>>=2;
 
2167
    bios_set_pal(pal,256,1);
 
2168
  }
 
2169
  return 1;
 
2170
}
 
2171
 
 
2172
 
 
2173
#ifdef DEBUG_VIDCARD
 
2174
static int test_pattern(int y, int p)
 
2175
{
 
2176
  if (p==1) return (1<<(y%8));
 
2177
  return 0;
 
2178
}
 
2179
#endif
 
2180
 
 
2181
static int save_pmode; /* Debugging only */
 
2182
 
 
2183
 
 
2184
 
 
2185
#define PCX_BUFFSIZE 16000
 
2186
static uchar *fbuff;
 
2187
static int fb_index;
 
2188
 
 
2189
static int readbyte(FILE *f)
 
2190
{
 
2191
  int n;
 
2192
 
 
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);
 
2197
    fb_index=0;
 
2198
  }
 
2199
  return fbuff[fb_index++];
 
2200
}
 
2201
 
 
2202
 
 
2203
 
 
2204
 
 
2205
static void display_PCX(FILE *pcxfile, int gmode)
 
2206
     /* pcxfile= the file to display.
 
2207
        gmode= suggested video mode. */
 
2208
{
 
2209
  int i,j, k;
 
2210
  int pmode; /* PCX palette mode: 0=CGA hires 1=CGA, 2=EGA, 3=MCGA */
 
2211
  uchar header[128];
 
2212
  int xsize,ysize;
 
2213
  uchar *linebuff; /* Up to four planes */
 
2214
  int linesize; /* Number of bytes in a line */
 
2215
  int y_ofs;
 
2216
  int c;
 
2217
 
 
2218
  /*-------------------------------------*/
 
2219
  /* Read in header                      */
 
2220
  /*-------------------------------------*/
 
2221
 
 
2222
  if (fread(header,128,1,pcxfile)!=1) {
 
2223
    writeln("GAME ERROR: Picture file corrupted.");
 
2224
    return;
 
2225
  }
 
2226
 
 
2227
  /* Verify header */
 
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;}
 
2231
 
 
2232
  /* Determine which palette type we're using */
 
2233
 
 
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 */
 
2238
  else {
 
2239
       writeln("ERROR: Unsupported graphics mode.");
 
2240
       return;
 
2241
  }
 
2242
 
 
2243
  xsize=ival(8)-ival(4)+1;
 
2244
  ysize=ival(10)-ival(6)+1;
 
2245
 
 
2246
  gmode=pick_gmode(gmode,pmode,xsize,ysize);
 
2247
  if (gmode==-1) {pmode=-4; return;}
 
2248
 
 
2249
  assert(pmode==paltype[gmode]); /* Temporary */
 
2250
 
 
2251
  /* Clip if neccessary */
 
2252
  if (xsize>mode_x[gmode]) xsize=mode_x[gmode];
 
2253
  if (ysize>mode_y[gmode]) ysize=mode_y[gmode];
 
2254
 
 
2255
  save_pmode=pmode;
 
2256
 
 
2257
  if (!setup_card(pcxfile,header,gmode,pmode)) return;
 
2258
 
 
2259
 
 
2260
  /*-------------------------------------*/
 
2261
  /* Draw picture                       */
 
2262
  /*-------------------------------------*/
 
2263
 
 
2264
  fseek(pcxfile,128,SEEK_SET); /* Beginning of picture data */
 
2265
 
 
2266
  linesize=ival(66);
 
2267
  linebuff=rmalloc(linesize*header[65]);
 
2268
 
 
2269
  y_ofs=(mode_y[gmode]-ysize)/2;
 
2270
 
 
2271
  /* This will set up the scanline drawing routines */
 
2272
  draw_scanline(NULL,gmode,y_ofs,linesize,xsize);
 
2273
 
 
2274
#ifdef DEBUG_VIDCARD
 
2275
  for(i=0;i<ysize;i++) {
 
2276
    memset(linebuff,0,linesize*header[65]);
 
2277
    if (pmode==2) {
 
2278
       int j;
 
2279
       for(j=0;j<4;j++)
 
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 */
 
2287
 
 
2288
    draw_scanline(linebuff,gmode,y_ofs+i,linesize,xsize);
 
2289
  }
 
2290
#endif
 
2291
 
 
2292
  fbuff=rmalloc(PCX_BUFFSIZE); /* The input buffer */
 
2293
  fb_index=PCX_BUFFSIZE;
 
2294
 
 
2295
  /* Draw picture */
 
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);
 
2304
          assert(c!=EOF);
 
2305
        if (c==EOF) {save_pmode=-2;return;}
 
2306
        for(;k>0 && j<linesize*header[65];k--)
 
2307
          linebuff[j++]=c;
 
2308
          if (k>0) {save_pmode=-3;return;}
 
2309
      } else
 
2310
        linebuff[j++]=c;
 
2311
    }
 
2312
    draw_scanline(linebuff,gmode,y_ofs+i,linesize,xsize);
 
2313
  }
 
2314
  rfree(fbuff);
 
2315
  rfree(linebuff);
 
2316
}
 
2317
 
 
2318
 
 
2319
 
 
2320
 
 
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.
 
2325
  */
 
2326
{
 
2327
  union REGS r;
 
2328
  char *base;
 
2329
  int gmode;
 
2330
  FILE *pcxfile=NULL;
 
2331
 
 
2332
  int savex,savey;
 
2333
  char *save_vidmem;
 
2334
 
 
2335
  if (graph_hardware==MDA) return; /* MDA is out */
 
2336
 
 
2337
  if (cmd==1) base=pictlist[pict];
 
2338
  else if (cmd==2) base=pixlist[pict];
 
2339
  else if (cmd==3) base=gamefile_name;
 
2340
  else return;
 
2341
 
 
2342
  while(kbhit()) rgetch(); /* Discard any buffered keypresses */
 
2343
 
 
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;
 
2351
  }
 
2352
  if (gmode==-1) {
 
2353
    pcxfile=linopen(base,".pcx");
 
2354
    if (pcxfile==NULL) return;
 
2355
    /* Leave gmode as -1 */
 
2356
  }
 
2357
 
 
2358
  in_gmode=0;
 
2359
  savex=rwherex();
 
2360
  savey=rwherey();
 
2361
#ifdef MSDOS16
 
2362
  save_vidmem=rmalloc(2*25*80);
 
2363
  memcpy(save_vidmem,(void*)0xB8000000L,2*25*80);
 
2364
#else /* MSDOS32 */
 
2365
  if (graph_hardware>MCGA) 
 
2366
    save_vidmem=rmalloc(2*ScreenRows()*ScreenCols());
 
2367
  else
 
2368
    save_vidmem=rmalloc(2*25*80);
 
2369
  ScreenRetrieve(save_vidmem);
 
2370
#endif
 
2371
 
 
2372
  display_PCX(pcxfile,gmode);
 
2373
 
 
2374
  fclose(pcxfile);
 
2375
 
 
2376
  /*-------------------------------------*/
 
2377
  /* Wait for key and restore text mode  */
 
2378
  /*-------------------------------------*/
 
2379
 
 
2380
  if (in_gmode) {
 
2381
 
 
2382
    if (!BATCH_MODE) rgetch();  /* Wait for a key-press */
 
2383
    
 
2384
    r.x.ax=0x0003;  /* Restore text mode */
 
2385
    int86(0x10,&r,&r);
 
2386
 
 
2387
#ifdef MSDOS16
 
2388
    memcpy((void*)0xB8000000L,save_vidmem,2*25*80); /* Restore video mem */
 
2389
#else /* MSDOS32 */
 
2390
    ScreenUpdate(save_vidmem);
 
2391
#endif
 
2392
    rgotoxy(savex,savey);  /* Restore cursor position */
 
2393
    if (active_font!=NULL)   /* Restore font, if neccessary */
 
2394
      set_font(active_font,active_font_height);
 
2395
    reset_state();
 
2396
 
 
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 */
 
2401
 
 
2402
  }
 
2403
  /* rprintf("Mode: %d\n",save_pmode); */
 
2404
  rfree(save_vidmem);
 
2405
}
 
2406
 
 
2407
 
 
2408
 
 
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.
 
2412
   1=play song
 
2413
   2=repeat song
 
2414
   3=end repeat
 
2415
   4=end song
 
2416
   5=suspend song
 
2417
   6=resume song
 
2418
   7=clean-up
 
2419
   8=turn sound on
 
2420
   9=turn sound off
 
2421
   -1=Is a song playing? (0=false, -1=true)
 
2422
   -2=Is the sound on?  (0=false, -1=true)
 
2423
*/
 
2424
{
 
2425
  if (cmd==8) sound_on=1;
 
2426
  else if (cmd==9) sound_on=0;
 
2427
  if (cmd==-1) return sound_on;
 
2428
  return 0;
 
2429
}
 
2430
 
 
2431
#endif /* REPLACE_BNW */