1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "glk/agt/agility.h"
24 #include "glk/agt/interp.h"
25
26 namespace Glk {
27 namespace AGT {
28
29 /* This module contains a miscellany of things that are somewhat */
30 /* system dependent but not enough so to justify being put in */
31 /* OS_<whatever>.c */
32 /* --writestr() and writeln().*/
33 /* --Hooks for sound, pictures, and fonts. */
34 /* --yesno() and wait_return() */
35 /* --Some lower level file stuff */
36 /* --main() and command line parseing stuff */
37
38 #ifndef REPLACE_BNW
39
40 /* #define DEBUG_BELLS_AND_WHISTLES */
41
42 /* Warning for fontcmd, pictcmd, musiccmd:
43 These all extract filenames from fontlist, pictlist, pixlist, songlist.
44 Any of these are allowed to be NULL and this should be checked
45 before accessing them. */
46
47 #ifdef DEBUG_BELLS_AND_WHISTLES
bnw_report(char * cmdstr,filename * list,int index)48 void bnw_report(char *cmdstr, filename *list, int index) {
49 writeln("");
50 writestr(">** ");
51 writestr(cmdstr);
52 writestr(" ");
53 if (list != NULL) {
54 writestr(list[index]);
55 writestr(" ");
56 }
57 writeln("**<");
58 }
59 #endif /* DEBUG_BELLS_AND_WHISTLES */
60
fontcmd(int cmd,int font)61 void fontcmd(int cmd, int font)
62 /* 0=Load font, name is fontlist[font]
63 1=Restore original (pre-startup) font
64 2=Set startup font. (<gamename>.FNT)
65 */
66 {
67 #ifdef DEBUG_BELLS_AND_WHISTLES
68 if (cmd == 0) bnw_report("Loading Font", fontlist, font);
69 else if (cmd == 1) bnw_report("Restoring original font", NULL, 0);
70 #endif
71 return;
72 }
73
pictcmd(int cmd,int pict)74 void pictcmd(int cmd, int pict)
75 /* 1=show global picture, name is pictlist[pict]
76 2=show room picture, name is pixlist[pict]
77 3=show startup picture <gamename>.P..
78 */
79 {
80 #ifdef DEBUG_BELLS_AND_WHISTLES
81 if (cmd == 1) bnw_report("Showing picture", pictlist, pict);
82 else if (cmd == 2) bnw_report("Showing pix", pixlist, pict);
83 agt_waitkey();
84 #endif
85 return;
86 }
87
88
89
musiccmd(int cmd,int song)90 int musiccmd(int cmd, int song)
91 /* For cmd=1 or 2, the name of the song is songlist[song]
92 The other commands don't take an additional argument.
93 1=play song
94 2=repeat song
95 3=end repeat
96 4=end song
97 5=suspend song
98 6=resume song
99 7=clean-up
100 8=turn sound on
101 9=turn sound off
102 -1=Is a song playing? (0=false, -1=true)
103 -2=Is the sound on? (0=false, -1=true)
104 */
105 {
106 if (cmd == 8) sound_on = 1;
107 else if (cmd == 9) sound_on = 0;
108 #ifdef DEBUG_BELLS_AND_WHISTLES
109 switch (cmd) {
110 case 1:
111 bnw_report("Play song", songlist, song);
112 break;
113 case 2:
114 bnw_report("Repeat song", songlist, song);
115 break;
116 case 3:
117 bnw_report("End repeat", NULL, 0);
118 break;
119 case 4:
120 bnw_report("End song", NULL, 0);
121 break;
122 case 5:
123 bnw_report("Suspend song", NULL, 0);
124 break;
125 case 6:
126 bnw_report("Resume song", NULL, 0);
127 break;
128 case 7:
129 bnw_report("Clean up", NULL, 0);
130 break;
131 case 8:
132 bnw_report("Sound On", NULL, 0);
133 break;
134 case 9:
135 bnw_report("Sound Off", NULL, 0);
136 break;
137 case -1:
138 return yesno("Is song playing?");
139 case -2:
140 return 1;
141 }
142 #endif
143 return 0;
144 }
145
146 #endif /* REPLACE_BNW */
147
148 static char linebuff[100];
149 static int lp; /* Line pointer */
150 static rbool savenl = 0;
151 static rbool needfill; /* Used for paragraph filling */
152 static rbool quotemode = 0;
153
debugout(const char * s)154 void debugout(const char *s) {
155 int i;
156
157 if (DEBUG_OUT) {
158 debugfile->write(s, strlen(s));
159 } else {
160 lp = 0;
161 for (; *s != 0; s++) {
162 if (curr_x + lp >= screen_width || lp > 80) {
163 if (lp + curr_x >= screen_width)
164 lp = screen_width - curr_x - 1;
165 linebuff[lp] = 0;
166 agt_puts(linebuff);
167 agt_newline();
168 lp = 0;
169 }
170 if (*s == '\n') {
171 linebuff[lp] = 0;
172 agt_puts(linebuff);
173 agt_newline();
174 lp = 0;
175 } else if (*s == '\t') {
176 for (i = 0; i < 3; i++) linebuff[lp++] = ' ';
177 } else if (*s >= 0 && *s <= 9) linebuff[lp++] = ' ';
178 else linebuff[lp++] = *s;
179 }
180 linebuff[lp] = 0;
181 agt_puts(linebuff);
182 }
183 }
184
185
close_pfile(genfile f,int ft)186 int close_pfile(genfile f, int ft)
187 /* ft=0 for script, 4 for log_in, 5 for log_out */
188 {
189 delete f;
190 return 0;
191 }
192
193
194
get_log(void)195 static char *get_log(void)
196 /* Read string from logfile_in */
197 {
198 char *s;
199 static int dead_log;
200
201 if (!filevalid(log_in, fLOG)) { /* We are finishing up */
202 if (++dead_log > 100) fatal("Internal error: LOG.");
203 assert(BATCH_MODE);
204 s = (char *)rmalloc(2);
205 s[0] = ' ';
206 s[1] = 0;
207 return s;
208 }
209
210 s = (char *)rmalloc(1000);
211 s[0] = ' ';
212 s[1] = 0;
213 (void)textgets(log_in, s, 1000);
214 if (texteof(log_in)) { /* Reached end of logfile */
215 close_pfile(log_in, 1);
216 log_in = BAD_TEXTFILE;
217 if (BATCH_MODE) {
218 writeln("");
219 writeln("ERROR: Unexpected end of log file.");
220 agt_quit(); /* This doesn't actually quit; it just sets things
221 up so we *will* quit. */
222 dead_log = 0;
223 } else {
224 logflag &= ~2;
225 fast_replay = 0;
226 }
227 } else { /* Need to delay or wait for keypress */
228 if (logdelay == -1) agt_waitkey();
229 else agt_delay(logdelay);
230 if (s[0] != 0) writeln(s);
231 }
232 return s;
233 }
234
235
put_log(const char * s)236 static void put_log(const char *s)
237 /* Write s to logfile_out */
238 {
239 textputs(log_out, s);
240 if (s[strlen(s) - 1] != '\n')
241 textputs(log_out, "\n");
242 }
243
244
agt_readline(int in_type)245 char *agt_readline(int in_type) {
246 char *s;
247
248 if (PURE_INPUT) agt_textcolor(-1);
249 if (logflag & 2)
250 s = get_log();
251 else
252 s = agt_input(in_type);
253
254 if (g_vm->shouldQuit())
255 return nullptr;
256
257 if (PURE_INPUT)
258 agt_textcolor(-2);
259
260 if (logflag & 1)
261 put_log(s);
262
263 return s;
264 }
265
agt_getchar(void)266 char agt_getchar(void) {
267 char c, *s, buff[2];
268
269 if (PURE_INPUT) agt_textcolor(-1);
270 if (logflag & 2) {
271 s = get_log();
272 c = s[0];
273 rfree(s);
274 } else
275 c = agt_getkey(1);
276 if (PURE_INPUT) agt_textcolor(-2);
277 if (logflag & 1) {
278 buff[0] = c;
279 buff[1] = 0;
280 put_log(buff);
281 }
282 return c;
283 }
284
agt_center(rbool b)285 void agt_center(rbool b)
286 /* 1=turn on text centering, 0=turn off */
287 /* At the moment, this is only used for game end messages */
288 /* When it is on, text output with writeln() should be 'centered'; */
289 /* it is up to the interface to decide what that means. */
290 /* writestr() should not be called while centering is on. */
291 {
292 center_on = b;
293 }
294
agt_par(rbool b)295 void agt_par(rbool b)
296 /* This has been added for the sake of anyone trying to get this to */
297 /* work on less-than-80 column screens. My personal opinion is that this */
298 /* is probably hopeless; many AGT games assume 80-column format for */
299 /* creating tables and ascii graphics. Nevertheless... */
300 /* Text between an agt_par(1) and an agt_par(0) is logically connected */
301 /* (all part of one description) and so it *might* be possible to reformat */
302 /* it, treating multiple lines as being one paragraph. */
303 /* At the very least, you should look for blank lines and indentation */
304 /* since a single section of text could contain multiple paragraphs. */
305 /* Sections of text _not_ between an agt_par(1) and an agt_par(0) should */
306 /* be treated as though each line were a new paragraph */
307 {
308 par_fill_on = b;
309 if (b == 0 && savenl) agt_newline();
310 savenl = 0;
311 needfill = 0;
312 }
313
314 /* This handles the various format code. They all show up after
315 '\r'; unrecogonized codes are just ignored */
xlat_format_code(uchar c)316 static uchar xlat_format_code(uchar c) {
317 if (c == 0xFF) {
318 if (fix_ascii) return trans_ibm[0xFF - 0x80];
319 else return 0xFF;
320 }
321 return 0;
322 }
323
324 #define FMT_CODE_CNT 15
325
run_format_code(uchar c)326 static void run_format_code(uchar c) {
327 if (c < FMT_CODE_CNT)
328 agt_textcolor(c - 3);
329 }
330
331 #define format_code(c) ((c>0 && c<=LAST_TEXTCODE)||((uchar)c==FORMAT_CODE))
332
writestr(const char * s)333 void writestr(const char *s) {
334 int i, j;
335 char c;
336 int endmark, old_x;
337
338 if (savenl) {
339 assert(par_fill_on);
340 if (!isalnum(s[0])) agt_newline();
341 else agt_puts(" ");
342 /* If combining two lines, insert a space between them. */
343 }
344 savenl = 0;
345 i = 0;
346 lp = 0;
347
348 while (s[i] != 0) {
349 for (; s[i] != 0 && lp < 90 && curr_x + lp < screen_width; i++)
350 if (s[i] == '\t')
351 for (j = 0; j < TAB_SIZE && curr_x + lp < screen_width; j++) linebuff[lp++] = ' ';
352 else if (format_code(s[i])) {
353 linebuff[lp++] = ' '; /* Color code */
354 break;
355 } else if (s[i] == '\r') { /* New format code */
356 if (s[i + 1] == 0) continue; /* Bogus format code */
357 if (((uchar)s[i + 1]) < FMT_CODE_CNT) break;
358 c = (char)xlat_format_code((uchar)s[++i]);
359 if (c != 0) linebuff[lp++] = c;
360 } else if (s[i] == '\n') {
361 break;
362 } else linebuff[lp++] = s[i];
363
364 linebuff[lp] = 0;
365
366 /* Backtrack to last space; in case of formatting codes, we should
367 already have one */
368 endmark = lp;
369
370 if (!isspace(s[i]) && !format_code(s[i]) && s[i] != 0) {
371 /* If we aren't conveniently at a break...*/
372 do { /* Find last space */
373 endmark--;
374 } while (endmark > 0 && !isspace(linebuff[endmark]));
375 }
376
377 if (endmark == 0 && !isspace(linebuff[endmark])) { /* Can't find a break */
378 if (curr_x + lp < screen_width) /* Not a line break */
379 endmark = lp; /* Break at end; it doesn't matter that much */
380 else /* We _need_ a line break but are having trouble finding one */
381 if (curr_x > 0) /* already stuff on this line printed previously */
382 endmark = 0; /* i.e. print out nothing; move it to next line */
383 else /* We have a single word that is longer than our line */
384 endmark = screen_width; /* Give up */
385 }
386
387 c = linebuff[endmark];
388 linebuff[endmark] = 0;
389 old_x = curr_x;
390
391 agt_puts(linebuff);
392
393 linebuff[endmark] = c;
394
395 if (old_x + lp >= screen_width)
396 /* Need to insert line break and skip any spaces */
397 {
398 if (!quotemode) agt_newline();
399 else return; /* In quote mode, just truncate */
400
401 /* Now set up beginning of next line: skip over whitespace */
402 while (endmark < lp && isspace(linebuff[endmark]))
403 endmark++; /* Eliminate EOL whitespace */
404 if (endmark == lp) {
405 /* Nothing left; eliminate whitespace at beginning
406 of next line */
407 while (isspace(s[i]) && s[i] != '\r') i++;
408 lp = endmark = 0;
409 }
410 needfill = 1;
411 if (endmark == lp && s[i] == 0) {
412 needfill = 2;
413 return; /* If only spaces left, don't print them */
414 }
415 }
416
417 /* Now copy remaining text */
418 for (j = 0; endmark < lp; j++, endmark++) linebuff[j] = linebuff[endmark];
419 lp = j;
420
421 /* Now to deal with format codes */
422 if ((unsigned char)s[i] == FORMAT_CODE) {
423 i++;
424 if (bold_mode) { /* Translate as BOLD toggle */
425 if (textbold)
426 agt_textcolor(-2); /* Turn bold off */
427 else agt_textcolor(-1); /* Turn bold on */
428 textbold = !textbold;
429 } else /* translate as BLACK */
430 agt_textcolor(0);
431 } else if (s[i] > 0 && s[i] <= LAST_TEXTCODE)
432 agt_textcolor(s[i++]);
433 else if (s[i] == '\r') {
434 run_format_code((uchar)s[i + 1]);
435 i += 2;
436 } else if (s[i] == '\n') {
437 i += 1;
438 agt_newline();
439 }
440 }
441 }
442
443
444
writeln(const char * s)445 void writeln(const char *s) {
446 int i, pad;
447 char *padstr;
448
449 if (center_on && (int)strlen(s) + curr_x < screen_width) {
450 pad = (screen_width - strlen(s)) / 2;
451 padstr = (char *)rmalloc((pad + 1) * sizeof(char));
452 for (i = 0; i < pad; i++) padstr[i] = ' ';
453 padstr[i] = 0;
454 agt_puts(padstr);
455 rfree(padstr);
456 }
457 writestr(s);
458 /* needfill=2 if writestr ended with a line that wrapped only
459 because of excess spaces (which have been discarded); needfill==1
460 if writestr wrapped a line for any reason */
461 /* If needfill==2, we've already issued a new-line, so don't issue a
462 second one. */
463 /* If needfill==1, set savenl rather than wrapping (writestr will
464 then decide to wrap or not depending on whether the next line starts
465 with text or nontext), *unless* we are version magx, in which case
466 the game author presumably knew what they were doing, so honor their
467 wishes. */
468 if (par_fill_on && needfill == 1)
469 if (aver >= AGX00) agt_newline();
470 else savenl = 1;
471 else if (needfill != 2)
472 agt_newline();
473 needfill = 0;
474 }
475
476
fixstatchar(uchar c)477 static char fixstatchar(uchar c)
478 /* Eliminate formating characters in the status line */
479 {
480 if (c == '\t' || c <= LAST_TEXTCODE ||
481 (c == FORMAT_CODE) || c == '\r' || c == '\n')
482 return ' ';
483 return c;
484 }
485
print_statline(void)486 void print_statline(void)
487 /* Use strings in l_stat and r_stat */
488 {
489 int i, j;
490 char *s, *t;
491 static rbool lastline = 0; /* Was a non-empty status line printed last time? */
492
493 s = (char *)rmalloc((status_width + 1) * sizeof(char));
494
495 /* If both strings empty, don't print the status line */
496 if (l_stat[0] == 0 && r_stat[0] == 0 && !lastline) return;
497 lastline = (l_stat[0] || r_stat[0]);
498
499 i = status_width - strlen(l_stat) - strlen(r_stat);
500
501 j = 0;
502 if (r_stat[0] == 0) { /* Center the status line */
503 while (j < i / 2) s[j++] = ' ';
504 i -= j;
505 } else if (i > 6) {
506 s[j++] = ' ';
507 i -= 2;
508 } /* If statline is wide enough, put a
509 space on each side */
510
511 if ((int)strlen(l_stat) < status_width) /* Copy left side of status line into s*/
512 for (t = l_stat; *t != 0; t++) s[j++] = fixstatchar(*t);
513
514 for (; i > 0; i--) s[j++] = ' '; /* Insert space between left and right sides */
515
516 if (j + (int)strlen(r_stat) <= status_width) /*Copy right side into s */
517 for (t = r_stat; *t != 0; t++) s[j++] = fixstatchar(*t);
518
519 while (j < status_width) s[j++] = ' '; /* Pad any extra width with spaces */
520 s[j] = 0; /* Put end of string marker */
521 agt_statline(s); /* Output it */
522 rfree(s);
523 }
524
525
padout(int padleng)526 void padout(int padleng) {
527 int i;
528 char *pstr;
529
530 if (padleng <= 0) return;
531 pstr = (char *)rmalloc(padleng + 1);
532 for (i = 0; i < padleng; i++) pstr[i] = ' ';
533 pstr[padleng] = 0;
534 writestr(pstr);
535 free(pstr);
536 }
537
textwidth(char * s)538 static int textwidth(char *s) {
539 int n;
540
541 n = 0;
542 for (; *s != 0; s++) n += (*s == '\t') ? TAB_SIZE : 1;
543 return n;
544 }
545
textbox(char * (txt[]),int len,unsigned long flags)546 void textbox(char *(txt[]), int len, unsigned long flags)
547 /* TB_TTL, TB_BOLD, TB_BORDER, TB_CENTER */
548 {
549 int i, width, padwidth;
550 int *linewidth;
551
552 agt_textcolor(7);
553 if (flags & TB_BOLD) agt_textcolor(-1);
554 else agt_textcolor(-2);
555
556 linewidth = (int *)rmalloc(len * sizeof(int));
557
558 width = 0; /* This contains the maximum width of any line */
559 for (i = 0; i < len; i++) {
560 linewidth[i] = textwidth(txt[i]);
561 if (linewidth[i] > width) width = linewidth[i];
562 }
563
564 agt_makebox(width, len, flags & ~(TB_BOLD | TB_CENTER));
565 quotemode = 1; /* So newlines will cause truncation rather than a
566 real newline */
567 for (i = 0; i < len; i++) {
568 padwidth = width - linewidth[i]; /* Amount of padding we need */
569 if (flags & TB_CENTER) {
570 padout(padwidth / 2);
571 padwidth -= padwidth / 2;
572 }
573 writestr(txt[i]);
574 padout(padwidth);
575 if (i != len - 1) agt_qnewline();
576 }
577 agt_endbox();
578 quotemode = 0; /* Back to normal */
579
580 agt_textcolor(7);
581 textbold = 0;
582 }
583
584
585 #ifndef REPLACE_MENU
586
agt_menu(const char * header,int size,int width,menuentry * menu)587 int agt_menu(const char *header, int size, int width, menuentry *menu)
588 /* This is _very_ minimal as it stands */
589 {
590 int i, j;
591 char sbuff[10];
592 int numcol, colheight;
593
594 if (size == 0) return 0;
595
596 width = width + 5;
597 numcol = screen_width / width;
598 colheight = size / numcol;
599 if (size % numcol != 0) colheight++;
600
601 writeln(header);
602 for (i = 0; i < colheight; i++) {
603 for (j = 0; j < numcol; j++) {
604 if (j * colheight + i >= size) break;
605 sprintf(sbuff, "%2d.", j * colheight + i + 1);
606 writestr(sbuff);
607 writestr(menu[j * colheight + i]);
608 if (j < numcol - 1) padout(width - 3 - strlen(menu[j * colheight + i]));
609 }
610 writeln("");
611 }
612 do {
613 writestr("Choice:");
614 i = read_number() - 1;
615 if (i < 0 || i >= size)
616 writeln("Please choose an option from the menu.");
617 } while (i < 0 || i >= size);
618 return i;
619 }
620
621 #endif /* REPLACE_MENU */
622
623
624
prompt_out(int n)625 void prompt_out(int n)
626 /* n=1 standard prompt
627 n=2 question prompt */
628 {
629 agt_textcolor(7);
630 if (PURE_INPUT && n == 1) agt_textcolor(-1);
631 if (n == 1) {
632 agt_newline();
633 gen_sysmsg(1, ">", MSG_MAIN, NULL);
634 }
635 if (n == 2) agt_puts("? ");
636 agt_textcolor(7);
637 }
638
agt_waitkey(void)639 void agt_waitkey(void) {
640 if (BATCH_MODE || fast_replay)
641 return;
642 agt_getkey(0);
643 }
644
645
wait_return(void)646 void wait_return(void) {
647 writeln(" --- HIT ANY KEY ---");
648 agt_waitkey();
649 }
650
651
yesno(const char * s)652 rbool yesno(const char *s)
653 /* True for yes, false for no. */
654 {
655 char c;
656
657 writestr(s);
658 writestr(" ");
659 c = 'y';
660 do {
661 if (c != 'y')
662 writestr("Please answer <y>es or <n>o. ");
663 c = tolower(agt_getchar());
664 } while (c != 'y' && c != 'n' && !quitflag);
665 return (c == 'y');
666 }
667
668
set_test_mode(fc_type fc)669 void set_test_mode(fc_type fc) {
670 const char *errstr;
671
672 log_in = readopen(fc, fLOG, &errstr);
673
674 if (make_test) {
675 if (errstr == NULL)
676 fatal("Log file already exists.");
677 log_out = writeopen(fc, fLOG, NULL, &errstr);
678 if (errstr != NULL)
679 fatal("Couldn't create log file.");
680 logflag = 1;
681 return;
682 }
683
684 logdelay = 0;
685 if (errstr != NULL)
686 fatal("Couldn't open log file.");
687 logflag = 2;
688
689 script_on = 1;
690 scriptfile = writeopen(fc, fSCR, NULL, &errstr);
691 if (errstr != NULL)
692 fatal("Couldn't open script file.");
693 }
694
695
696 #ifndef REPLACE_GETFILE
697
698 /* This opens the file refered to by fname and returns it */
uf_open(fc_type fc,filetype ext,rbool rw)699 static genfile uf_open(fc_type fc, filetype ext, rbool rw) {
700 char *errstr;
701 genfile f;
702
703 if (rw) { /* Check to see if we are overwriting... */
704 if (fileexist(fc, ext) && ext != fSCR) {
705 if (!yesno("This file already exists; overwrite?"))
706 /* That is, DON'T overwrite */
707 return badfile(ext);
708 }
709 f = writeopen(fc, ext, NULL, &errstr);
710 } else
711 f = readopen(fc, ext, &errstr);
712 if (errstr != NULL) writeln(errstr);
713 return f;
714 }
715
716 static fc_type last_save = NULL;
717 static fc_type last_log = NULL;
718 static fc_type last_script = NULL;
719
720
get_user_file(int ft)721 genfile get_user_file(int ft)
722 /* ft= 0:script, 1:save 2:restore, 3:log(read) 4:log(write) */
723 /* Should return file in open state, ready to be read or written to,
724 as the case may be */
725 {
726 /* int extlen;*/
727 rbool rw; /* True if writing, false if reading */
728 filetype ext;
729 genfile fd;
730 fc_type def_fc, fc;
731 char *fname;
732 char *ftype;
733 char *p, *q;
734
735 switch (ft) {
736 case 0:
737 ftype = "script ";
738 def_fc = last_script;
739 rw = 1;
740 ext = fSCR;
741 break;
742 case 1:
743 ftype = "save ";
744 def_fc = last_save;
745 rw = 1;
746 ext = fSAV;
747 break;
748 case 2:
749 ftype = "restore ";
750 def_fc = last_save;
751 rw = 0;
752 ext = fSAV;
753 break;
754 case 3:
755 ftype = "log ";
756 def_fc = last_log;
757 rw = 0;
758 ext = fLOG;
759 break;
760 case 4:
761 ftype = "log ";
762 def_fc = last_log;
763 rw = 1;
764 ext = fLOG;
765 break;
766 default:
767 writeln("<INTERNAL ERROR: invalid file type>");
768 return badfile(fSAV);
769 }
770
771 writestr(" ");
772 writestr("Enter ");
773 if (ftype != NULL) writestr(ftype);
774 writestr("file name");
775 if (def_fc != NULL) {
776 char *s;
777 s = formal_name(def_fc, ext);
778 writestr(" (");
779 writestr(s);
780 writestr(")");
781 rfree(s);
782 }
783 writestr(": ");
784
785 if (PURE_INPUT) agt_textcolor(-1);
786 fname = agt_input(4);
787 if (PURE_INPUT) agt_textcolor(-2);
788
789 /* Delete whitespace before and after the file name. */
790 for (p = fname; isspace(*p); p++);
791 if (*p == 0) { /* Line is all whitespace; use default if there is one */
792 if (def_fc == NULL) {
793 writeln("Never mind.");
794 rfree(fname);
795 return badfile(ext);
796 } else {
797 rfree(fname);
798 fc = def_fc;
799 }
800 } else { /* Line is _not_ all whitespace: we have a file name */
801 for (q = fname; *p != 0; p++, q++)
802 *q = *p;
803 q--;
804 while (isspace(*q)) q--;
805 q++;
806 *q = 0;
807 fc = init_file_context(fname, ext);
808 }
809
810 fd = uf_open(fc, ext, rw);
811
812 if (!filevalid(fd, ext)) {
813 if (fc != def_fc) release_file_context(&fc);
814 return fd;
815 }
816
817 switch (ft) {
818 case 0:
819 last_script = fc;
820 break;
821 case 1:
822 last_save = fc;
823 break;
824 case 2:
825 last_save = fc;
826 break;
827 case 3:
828 last_log = fc;
829 break;
830 case 4:
831 last_log = fc;
832 break;
833 }
834 if (fc != def_fc) release_file_context(&def_fc);
835 return fd;
836 }
837
838
set_default_filenames(fc_type fc)839 void set_default_filenames(fc_type fc) {
840 last_save = convert_file_context(fc, fSAV, NULL);
841 last_log = convert_file_context(fc, fLOG, NULL);
842 last_script = convert_file_context(fc, fSCR, NULL);
843 }
844
845
846
847 #endif /* REPLACE_GETFILE */
848
849
850
851
script(uchar onp)852 void script(uchar onp) {
853 if (onp == script_on)
854 if (onp == 0) writeln("Scripting wasn't on.");
855 else writeln("Scripting is already on.");
856 else if (onp == 1) {
857 scriptfile = get_user_file(0);
858 if (filevalid(scriptfile, fSCR)) script_on = 1;
859 } else if (filevalid(scriptfile, fSCR)) {
860 close_pfile(scriptfile, 0);
861 scriptfile = BAD_TEXTFILE;
862 script_on = 0;
863 }
864 }
865
866
logon(void)867 void logon(void) {
868 if (logflag & 1) {
869 writeln("Already logging");
870 return;
871 }
872 log_out = get_user_file(4);
873 if (filevalid(log_out, fLOG))
874 logflag |= 1;
875 }
876
replay(int delay)877 void replay(int delay) {
878 if (logflag & 2) return; /* Nested replays are meaningless */
879 log_in = get_user_file(3);
880 if (filevalid(log_in, fLOG)) {
881 logflag |= 2;
882 logdelay = delay;
883 }
884 }
885
886
887 /* These two are intended to be called by the platform-dependent
888 interface (e.g. if the user had chosen these from some general purpose
889 menu) */
890 /* They're never called from the rest of the code */
891
agt_save(void)892 void agt_save(void) {
893 g_vm->saveGame();
894 }
895
agt_restore(void)896 void agt_restore(void) {
897 doing_restore = 1;
898 }
899
agt_restart(void)900 void agt_restart(void) {
901 doing_restore = 2;
902 }
903
agt_quit(void)904 void agt_quit(void) {
905 doing_restore = 4;
906 }
907
908
909 /* This should be rmalloc'd */
910 static fc_type newgame_fc;
911
new_game(void)912 fc_type new_game(void) {
913 return newgame_fc;
914 }
915
agt_newgame(fc_type fc)916 void agt_newgame(fc_type fc) {
917 newgame_fc = fc;
918 doing_restore = 3;
919 }
920
921 #if 0
922 static rbool end_cmd_options;
923 #endif
924
set_default_options(void)925 void set_default_options(void) {
926 init_flags();
927 flag = (rbool *)rmalloc(sizeof(rbool));
928 debug_parse = 0;
929 DEBUG_AGT_CMD = 0;
930 DEBUG_EXEC_VERB = 0;
931 DEBUG_DISAMBIG = 0;
932 DEBUG_SMSG = 0;
933 }
934
helpmsg(void)935 void helpmsg(void) {
936 /*
937 printf(" -i Try to use IBM character set.\n");
938 printf(" -1 IRUN Mode: Print messages in first person\n");
939 printf(" -h Print out this message\n");
940 printf(" -d Debug metacommand execution\n");
941 printf(" -t Test mode; see accompanying documentation. Implies -r.\n");
942 printf(" -c Create test file.\n");
943 printf(" -m Force descriptions to be loaded from disk.\n");
944 #ifdef OPEN_AS_TEXT
945 printf(" -b Open data files as binary files.\n");
946 #endif
947 printf("\nTechnical options (intended for debugging AGiliTy itself).\n");
948 printf(" -p Debug parser\n");
949 printf(" -x Debug verb execution loop\n");
950 printf(" -a Debug disambiguation system\n");
951 printf(" -s Debug STANDARD message handler\n");
952 */
953 }
954
955 #if 0
956 static rbool setarg(char **optptr) {
957 if ((*optptr)[1] == '+') {
958 (*optptr)++;
959 return 1;
960 }
961 if ((*optptr)[1] == '-') {
962 (*optptr)++;
963 return 0;
964 }
965 return 1;
966 }
967 #endif
968
969 #define fixcase(c) tolower(c)
970
971 #if 0
972 void parse_options(char *opt, char *next) {
973 /*
974 if (opt[0]=='-' && opt[1]==0)
975 {end_cmd_options=1;return;}
976 for(;*opt!=0;opt++)
977 switch(fixcase(*opt))
978 {
979 case 'p': debug_parse=setarg(&opt);break;
980 case 'a': DEBUG_DISAMBIG=setarg(&opt);break;
981 case 'd': DEBUG_AGT_CMD=setarg(&opt);break;
982 case 'x':DEBUG_EXEC_VERB=setarg(&opt);break;
983 case 's':DEBUG_SMSG=setarg(&opt);break;
984 #ifdef MEM_INFO
985 case 'M': DEBUG_MEM=setarg(&opt);break;
986 #endif
987 case 'm': descr_maxmem=0; break;
988 case 'i': fix_ascii_flag=!setarg(&opt);break;
989 case 't': BATCH_MODE=setarg(&opt); break;
990 case 'c': make_test=setarg(&opt); break;
991 case '1': irun_mode=setarg(&opt);break;
992 #ifdef OPEN_FILE_AS_TEXT
993 case 'b': open_as_binary=setarg(&opt);break;
994 #endif
995 default:printf("Do not recognize option %c\n",*opt);
996 helpmsg();
997 exit(EXIT_FAILURE);
998 }
999 */
1000 }
1001 #endif
1002
1003 #ifndef REPLACE_MAIN
1004
main(int argc,char * argv[])1005 int main(int argc, char *argv[]) {
1006 int i;
1007 char *gamefile;
1008
1009 set_default_options();
1010 end_cmd_options = 0;
1011 gamefile = NULL;
1012 for (i = 1; i < argc; i++)
1013 if (argv[i][0] == '-' && !end_cmd_options)
1014 parse_options(argv[i] + 1, argv[i + 1]);
1015 else if (gamefile == NULL)
1016 gamefile = argv[i];
1017 else fatal("Please specify only one game\n");
1018 if (gamefile == NULL) {
1019 helpmsg();
1020 exit(EXIT_FAILURE);
1021 }
1022
1023 init_interface(argc, argv);
1024 /* From this point on, MUST use writestr/writeln or may
1025 cause problems w/ the interfaces on some platforms
1026 that have to keep track of cursor position */
1027
1028 run_game(init_file_context(gamefile, fDA1));
1029 return EXIT_SUCCESS;
1030 }
1031
1032 #endif /* REPLACE_MAIN */
1033
1034 } // End of namespace AGT
1035 } // End of namespace Glk
1036