Initial commit
This commit is contained in:
895
engines/glk/agt/agil.cpp
Normal file
895
engines/glk/agt/agil.cpp
Normal file
@@ -0,0 +1,895 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/agt/agility.h"
|
||||
#include "glk/agt/interp.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* Description Pointers */
|
||||
|
||||
|
||||
descr_ptr intro_ptr;
|
||||
descr_ptr title_ptr, ins_ptr; /* Only defined if agx_file is true */
|
||||
descr_ptr *err_ptr; /* [NUM_ERR];*/
|
||||
|
||||
descr_ptr *msg_ptr; /* [MAX_MSG];*/
|
||||
descr_ptr *help_ptr, *room_ptr, *special_ptr; /*[ROOM] */
|
||||
descr_ptr *noun_ptr, *text_ptr, *turn_ptr, /* [NOUN] */
|
||||
*push_ptr, *pull_ptr, *play_ptr;
|
||||
descr_ptr *talk_ptr, *ask_ptr, *creat_ptr; /* [CREAT] */
|
||||
|
||||
descr_ptr *quest_ptr, *ans_ptr; /* [MAX_QUEST] */
|
||||
tline *question, *answer; /* [MAX_QUEST] */
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Dynamically allocated data blocks (which are pointed to from elsewhere) */
|
||||
|
||||
char **dict; /* dict[n] points to the nth dictionary word */
|
||||
long dp; /* Dictionary pointer: number of words in dict */
|
||||
|
||||
#define DICT_INIT 12*1024 /* Starting size of dictstr */
|
||||
#define DICT_GRAN 1024 /* Granularity of dictstr size requests
|
||||
must be at least 4. */
|
||||
char *dictstr; /* Pointer to memory block containing dict words */
|
||||
long dictstrptr, dictstrsize;
|
||||
/* dictstrptr points to the first unused byte in dictstr.
|
||||
dictstrsize points to the end of the space currently allocated for
|
||||
dictstr.
|
||||
*/
|
||||
|
||||
char *static_str; /*Static string space */
|
||||
long ss_end; /* Pointer to end of used space in above */
|
||||
long ss_size; /* Current size of static string space */
|
||||
|
||||
word *syntbl; /* Synonym list space */
|
||||
slist synptr; /* Points to end of used space */
|
||||
long syntbl_size; /* Long so we can catch overflows */
|
||||
|
||||
long descr_maxmem;
|
||||
char *mem_descr; /* Copy of descriptor in memory */
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Data structures used internally by agtread.c */
|
||||
|
||||
/*The following are all set to NULL after agtread finishes. */
|
||||
long *cmd_ptr; /* ME only;Points to cmd start locs in gamefile.*/
|
||||
long *room_name, *noun_sdesc, *noun_pos, *creat_sdesc;
|
||||
long *t_pictlist, *t_pixlist, *t_songlist, *t_fontlist;
|
||||
|
||||
/* These are only used by agtout (to allow the AGT reading routines to
|
||||
pass back the count of nouns inside the given object) */
|
||||
integer *room_inside, *noun_inside, *creat_inside;
|
||||
|
||||
/* This is used to translate ASCII codes */
|
||||
uchar fixchar[256];
|
||||
|
||||
rbool text_file; /* Set if we are currently opening a binary file. */
|
||||
#ifdef OPEN_AS_TEXT
|
||||
rbool open_as_binary; /* Open text files as binary, anyhow. */
|
||||
#endif
|
||||
|
||||
/* The following are AGT 'purity' flags; they turn off features of */
|
||||
/* my interpreter that are not fully consistent with the original AGT */
|
||||
/* and so could break some games. Some of these are trivial improvements; */
|
||||
/* some are more radical and should be used with caution. Several are */
|
||||
/* only useful if a game was designed with them in mind. */
|
||||
/* In all cases, setting the flag to 1 more closely follows the */
|
||||
/* behavior of the original interpreters */
|
||||
/* WARNING: Most of these haven't been tested in the non-default state. */
|
||||
/* Most of these will eventually become variables settable by the user */
|
||||
/* or from a (possibly game-specific) configuration file */
|
||||
|
||||
rbool PURE_INPUT = 1; /* Is the input line bold? */
|
||||
|
||||
rbool PURE_TONE = 0; /* Is low level sound enabled? */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
/* Misc. things to support the tokenizer and the dictionry. */
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
/* The following should not be changed without also changing the
|
||||
wtype enum statement in interp.h to match */
|
||||
static const char *ext_voc[] = {
|
||||
"the", "my", "a", "an", /* These 4 are ignored in canonical AGT */
|
||||
"then", ".", ";", "and", "," , "its", "all", "undo", "look", "g",
|
||||
"pick", "go", "exits", "talk", "take", "door", "again", "but", "except",
|
||||
"scene", "everything", "listexit", "listexits", "close",
|
||||
"verb", "noun", "adjective", "prep", "object", "name", "step",
|
||||
" any", "either", "both", "everyone", "everybody",
|
||||
"he", "she", "it", "they", "him", "her", "them", "is", "are", "oops",
|
||||
"was", "were", "scream",
|
||||
/* Everything between 'in' and 'about' should be a preposition */
|
||||
"in", "out", "into", "at", "to", "across", "inside", "with", "near", "for",
|
||||
"of", "behind", "beside", "on", "off", "under", "from", "through",
|
||||
"toward", "towards", "between", "around", "upon", "thru",
|
||||
"by", "over", "up", "down",
|
||||
"about"
|
||||
};
|
||||
/* 'about' must be the last element of this list */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
/* Routines to read in and use various auxiliary files. */
|
||||
/* (.TTL, .INS, .VOC, .CFG) */
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
static rbool emptyline(unsigned char *s)
|
||||
/* Check if s consists only of white space and control characters */
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
for (p = s; *p != 0; p++)
|
||||
if (!rspace(*p) && *p > 26) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void print_title(fc_type fc) {
|
||||
int height;
|
||||
signed char center_mode; /* Center title? */
|
||||
descr_line *buff;
|
||||
char *s;
|
||||
rbool skip_line; /* Skip first line: it has COLORS */
|
||||
|
||||
if (agx_file)
|
||||
buff = read_descr(title_ptr.start, title_ptr.size);
|
||||
else
|
||||
buff = read_ttl(fc);
|
||||
|
||||
if (buff == nullptr) {
|
||||
writeln("");
|
||||
writeln("");
|
||||
s = formal_name(fc, fNONE);
|
||||
if (s != nullptr) {
|
||||
s[0] = toupper(s[0]);
|
||||
agt_center(1);
|
||||
agt_textcolor(-1);
|
||||
writeln(s);
|
||||
agt_textcolor(-2);
|
||||
agt_center(0);
|
||||
rfree(s);
|
||||
}
|
||||
writeln("");
|
||||
writeln("");
|
||||
|
||||
if (aver < AGX00)
|
||||
writeln("This game was created with Malmberg and Welch's Adventure "
|
||||
"Game Toolkit; it is being executed by");
|
||||
else writeln("This game is being executed by ");
|
||||
writeln("");
|
||||
height = 0;
|
||||
} else {
|
||||
if (buff[0] != nullptr && strncasecmp(buff[0], "COLORS", 6) == 0) {
|
||||
/* Do screen colors */
|
||||
skip_line = 1;
|
||||
} else skip_line = 0;
|
||||
/* Compute height and count the number of non-empty lines
|
||||
starting with spaces. We use height as a loop variable
|
||||
and center_mode to store the count temporarily. */
|
||||
center_mode = 0;
|
||||
for (height = skip_line; buff[height] != nullptr; height++)
|
||||
if (!emptyline((uchar *)buff[height])) {
|
||||
if (rspace(buff[height][0])) center_mode++;
|
||||
else center_mode--;
|
||||
}
|
||||
|
||||
if (box_title || aver == AGTCOS) center_mode = TB_CENTER;
|
||||
else /* includes aver==AGT135 */
|
||||
if (center_mode <= 0) center_mode = TB_CENTER;
|
||||
else center_mode = TB_NOCENT;
|
||||
|
||||
if (!bold_mode) agt_textcolor(-1);
|
||||
agt_clrscr();
|
||||
textbox(buff + skip_line, height - skip_line, center_mode |
|
||||
(bold_mode ? 0 : TB_BOLD) | TB_TTL |
|
||||
(box_title ? TB_BORDER : 0));
|
||||
if (!bold_mode) agt_textcolor(-2); /* Bold off */
|
||||
} /* End printing of title proper */
|
||||
|
||||
if (agx_file)
|
||||
free_descr(buff);
|
||||
else
|
||||
free_ttl(buff);
|
||||
|
||||
agt_textcolor(7);
|
||||
agt_center(1);
|
||||
if (buff != nullptr) {
|
||||
if (aver < AGX00 && height <= screen_height - 6)
|
||||
writeln("[Created with Malmberg and Welch's Adventure Game Toolkit]");
|
||||
if (height <= screen_height - 9) writeln("");
|
||||
if (height <= screen_height - 5) writeln("This game is being executed by");
|
||||
}
|
||||
agt_textcolor(-1);
|
||||
s = (char *)rmalloc(80);
|
||||
if (height <= screen_height - 5)
|
||||
Common::sprintf_s(s, 80, "AGiliTy: "
|
||||
"The (Mostly) Universal AGT Interpreter %s", version_str);
|
||||
else
|
||||
Common::sprintf_s(s, 80, "Being run by AGiliTy %s, "
|
||||
"Copyright (C) 1996-99,2001 Robert Masenten",
|
||||
version_str);
|
||||
writeln(s);
|
||||
rfree(s);
|
||||
agt_textcolor(-2);
|
||||
if (height <= screen_height - 5)
|
||||
writeln("Copyright (C) 1996-99,2001 by Robert Masenten");
|
||||
if (height <= screen_height - 3) writeln(portstr);
|
||||
if (height <= screen_height - 10) writeln("");
|
||||
agt_center(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* .INS reading routines -------------------------------------- */
|
||||
|
||||
void print_instructions(fc_type fc) {
|
||||
char *buffer;
|
||||
uchar *s;
|
||||
|
||||
writeln("INSTRUCTIONS:");
|
||||
if (open_ins_file(fc, 1)) { /* Instruction file exists */
|
||||
while (nullptr != (buffer = read_ins_line())) {
|
||||
for (s = (uchar *)buffer; *s != 0; s++) *s = trans_ascii[*s];
|
||||
writeln(buffer);
|
||||
}
|
||||
}
|
||||
writeln("");
|
||||
}
|
||||
|
||||
/* Routines to build the verb menu from the .VOC information */
|
||||
|
||||
static void build_verbmenu(void) {
|
||||
int i, n;
|
||||
char *p, *d;
|
||||
|
||||
verbmenu = (menuentry *)rmalloc(vm_size * sizeof(menuentry));
|
||||
vm_width = 0;
|
||||
for (i = 0; i < vm_size; i++) {
|
||||
p = verbmenu[i];
|
||||
d = dict[verbinfo[i].verb];
|
||||
n = 0;
|
||||
for (; n < MENU_WIDTH && *d != 0; p++, d++, n++) *p = *d;
|
||||
if (verbinfo[i].prep != 0 && n + 1 < MENU_WIDTH) {
|
||||
*p++ = ' ';
|
||||
d = dict[verbinfo[i].prep];
|
||||
*p++ = toupper(*d++);
|
||||
for (; n < MENU_WIDTH && *d != 0; p++, d++, n++) *p = *d;
|
||||
}
|
||||
verbmenu[i][0] = toupper(verbmenu[i][0]);
|
||||
*p = 0;
|
||||
if (n > vm_width) vm_width = n;
|
||||
}
|
||||
}
|
||||
|
||||
/* .CFG reading routines -------------------------------------------- */
|
||||
|
||||
#define opt(s) (strcasecmp(optstr[0],s)==0)
|
||||
|
||||
/* These are the interpreter specific options; this is called
|
||||
from cfg_option in agtdata.c. */
|
||||
void agil_option(int optnum, char *optstr[], rbool setflag, rbool lastpass) {
|
||||
if (opt("ibm_char")) fix_ascii_flag = !setflag;
|
||||
else if (!lastpass) return; /* On the first pass through the game specific
|
||||
file, we ignore all but the above options */
|
||||
else if (opt("tone")) PURE_TONE = setflag;
|
||||
else if (opt("input_bold")) PURE_INPUT = setflag;
|
||||
else if (opt("force_load")) FORCE_VERSION = setflag;
|
||||
else if (opt("stable_random")) stable_random = setflag;
|
||||
else if (!agt_option(optnum, optstr, setflag)) /* Platform specific options */
|
||||
rprintf("Invalid option %s\n", optstr[0]);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
/* Tokeniser: Split input into words and look them up in dictionary */
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
static rbool noise_word(word w) {
|
||||
if (w == ext_code[wthe] || w == ext_code[wa] || w == ext_code[wan]) return 1;
|
||||
if (w == ext_code[wmy]) return 1;
|
||||
if (aver >= AGT18 && aver <= AGT18MAX && w == ext_code[wis]) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static rbool check_dot(char *prevtext, int prevcnt, char *lookahead)
|
||||
/* This routine is devoted to trying to figure out whether
|
||||
we should treat '.' as punctuation or as a letter. */
|
||||
/* It returns true if '.' should be treated as punctuation. */
|
||||
/* prevtext=the current word, as far as it has been parsed.
|
||||
prevcnt=the number of letters in prevtext
|
||||
[which is *not* 0 terminated] */
|
||||
/* lookahead=the rest of the current input line *after* the period. */
|
||||
{
|
||||
int i, endword, restcnt;
|
||||
|
||||
if (!PURE_DOT) return 1; /* No words with periods in them, so it must
|
||||
be punctuation. */
|
||||
/* We just start scanning the dictionary to see if any of them
|
||||
are possible matches, looking ahead as necessary. */
|
||||
|
||||
/* Find the next unambiguous word end. This ignores possible
|
||||
word ends caused by periods. */
|
||||
for (endword = 0; lookahead[endword] != 0; endword++)
|
||||
if (isspace(lookahead[endword]) ||
|
||||
lookahead[endword] == ',' || lookahead[endword] == ';')
|
||||
break;
|
||||
|
||||
for (i = 0; i < dp; i++) {
|
||||
if (i == ext_code[wp]) continue; /* Ignore matches with the word ".". */
|
||||
|
||||
/* If it doesn't contain a '.' at the right location, there is no
|
||||
point in continuing. */
|
||||
restcnt = strlen(dict[i]);
|
||||
if (restcnt <= prevcnt || dict[i][prevcnt] != '.') continue;
|
||||
|
||||
/* Now make sure the previous characters are correct */
|
||||
if (strncasecmp(prevtext, dict[i], prevcnt) != 0) continue;
|
||||
|
||||
/* Finally, compare the trailing text. This is complicated by
|
||||
the fact that the trailing text could itself contain ambiguous '.'s */
|
||||
restcnt -= prevcnt + 1; /* Number of characters in dict entry after '.' */
|
||||
if (restcnt > endword) continue; /* Dictionary entry is longer than
|
||||
following text */
|
||||
|
||||
/* Check to see if the dictionary entry can be found in the lookahead
|
||||
buffer */
|
||||
if (strncasecmp(lookahead, dict[i] + prevcnt + 1, restcnt) != 0) continue;
|
||||
|
||||
if (restcnt == endword) return 0; /* We have a match */
|
||||
/* At this point, we know that restcnt<endword and the dictionary
|
||||
entry matches as far as restcnt. */
|
||||
/* endword ignores '.', though, so it could be we have a match
|
||||
but are missing it because it is period-terminated. Check this. */
|
||||
if (lookahead[restcnt] == '.') return 0;
|
||||
|
||||
/* Otherwise, no match... try again with the next word... */
|
||||
}
|
||||
return 1; /* No matches: treat it as punctuation. */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void tokenise(char *buff)
|
||||
/* Convert input string into vocabulary codes */
|
||||
/* 0 here denotes an unrecognized word and -1 marks the end. */
|
||||
{
|
||||
int ip_, j, k;
|
||||
rbool punctuation;
|
||||
|
||||
j = 0;
|
||||
ip_ = 0;
|
||||
k = 0; /* k is the character pointer */
|
||||
for (k = 0;; k++) {
|
||||
/* If PURE_DOT is set, then there are periods in some of the dictionary
|
||||
words, so '.' could be a letter or punctuation-- we have to examine
|
||||
context to figure out which. */
|
||||
if (buff[k] == '.' && PURE_DOT)
|
||||
/* Note: check_dot is in agtdata.c, since it needs to access
|
||||
internal implementation details of the dictionary */
|
||||
punctuation = check_dot(in_text[ip_], j, buff + k + 1);
|
||||
else
|
||||
punctuation = (buff[k] == ',' || buff[k] == ';' || buff[k] == '.');
|
||||
if (buff[k] != 0 && !isspace(buff[k]) && !punctuation) {
|
||||
if (j < WORD_LENG - 1)
|
||||
in_text[ip_][j++] = buff[k];
|
||||
} else if (j > 0) { /* End of word: add it to input */
|
||||
in_text[ip_][j] = 0;
|
||||
input[ip_] = search_dict(in_text[ip_]);
|
||||
if (input[ip_] == -1) input[ip_] = 0;
|
||||
else if (input[ip_] == 0) input[ip_] = ext_code[w_any]; /* _Real_ 'ANY' */
|
||||
if (!noise_word(input[ip_])) ip_ += 1;
|
||||
/* i.e. if not one of the four ignored words, advance */
|
||||
j = 0;
|
||||
} /* If j=0 and not punct, then no new word; just skip the whitespace */
|
||||
if (punctuation) {
|
||||
in_text[ip_][0] = buff[k];
|
||||
in_text[ip_][1] = 0;
|
||||
input[ip_] = search_dict(in_text[ip_]);
|
||||
if (input[ip_] == -1) input[ip_] = 0;
|
||||
j = 0;
|
||||
ip_++;
|
||||
}
|
||||
if (ip_ >= MAXINPUT - 1) {
|
||||
writeln("Too many words in input; ignoring rest of line.");
|
||||
break;
|
||||
}
|
||||
if (buff[k] == 0) break;
|
||||
}
|
||||
input[ip_] = -1;
|
||||
in_text[ip_][0] = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
/* Main game loop: Get player input and call the parser. */
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
static void game_end(void) {
|
||||
rbool done_flag;
|
||||
char *s;
|
||||
|
||||
if (winflag || deadflag) {
|
||||
writeln("");
|
||||
writeln("");
|
||||
agt_center(1);
|
||||
if (winflag)
|
||||
gen_sysmsg(148, "***** $You$ have won! *****", MSG_MAIN, nullptr);
|
||||
if (deadflag)
|
||||
gen_sysmsg(147, "***** $You$ have died! *****", MSG_MAIN, nullptr);
|
||||
writeln("");
|
||||
writeln("");
|
||||
agt_center(0);
|
||||
}
|
||||
if (deadflag && !endflag) {
|
||||
if (curr_lives > 1) { /* Resurrection code */
|
||||
if (curr_lives == max_lives)
|
||||
gen_sysmsg(151, "Hmmm.... so $you$'ve gotten $your$self killed. "
|
||||
"Would you like me to try a resurrection?", MSG_MAIN, nullptr);
|
||||
else gen_sysmsg(152, "<Sigh> $You$'ve died *again*. "
|
||||
"Would you like me to try another resurrection?",
|
||||
MSG_MAIN, nullptr);
|
||||
if (yesno("? ")) { /* Now do resurrection */
|
||||
curr_lives--;
|
||||
quitflag = deadflag = 0;
|
||||
gen_sysmsg(154,
|
||||
"$You$ emerge coughing from a cloud of dark green smoke.",
|
||||
MSG_MAIN, nullptr);
|
||||
writeln("");
|
||||
loc = resurrect_room - first_room;
|
||||
newlife_flag = 1;
|
||||
set_statline();
|
||||
do_look = do_autoverb = 1;
|
||||
newroom();
|
||||
return;
|
||||
} else writeln("As you wish...");
|
||||
} else if (max_lives > 1)
|
||||
gen_sysmsg(153, "$You$'ve used up all of $your$ lives.", MSG_MAIN, nullptr);
|
||||
}
|
||||
writeln("");
|
||||
print_score();
|
||||
writeln("");
|
||||
done_flag = quitflag; /* If player has QUIT, don't ask again */
|
||||
while (!done_flag && !quitflag) {
|
||||
writestr("Would you like to ");
|
||||
if (restart_state != nullptr) writestr("restart, ");
|
||||
writestr("restore");
|
||||
if (undo_state != nullptr && can_undo)
|
||||
writestr(", undo,");
|
||||
else if (restart_state != nullptr) writestr(",");
|
||||
writestr(" or quit? ");
|
||||
s = agt_readline(5);
|
||||
if (strncasecmp(s, "RESTART", 7) == 0)
|
||||
if (restart_state != nullptr) {
|
||||
restart_game();
|
||||
done_flag = 1;
|
||||
} else writeln("Sorry, I'm unable to do that because of limited memory.");
|
||||
else if (strncasecmp(s, "RESTORE", 7) == 0)
|
||||
if (g_vm->loadGame().getCode() == Common::kNoError) {
|
||||
done_flag = 1;
|
||||
} else writeln("(RESTORE failed)");
|
||||
else if (strncasecmp(s, "UNDO", 4) == 0)
|
||||
if (can_undo && undo_state != nullptr) {
|
||||
putstate(undo_state);
|
||||
done_flag = 1;
|
||||
} else writeln("Insufficiant memory to support UNDO");
|
||||
else if (toupper(s[0]) == 'Q') {
|
||||
quitflag = 1;
|
||||
done_flag = 1;
|
||||
}
|
||||
}
|
||||
set_statline();
|
||||
}
|
||||
|
||||
|
||||
static void parse_loop(void)
|
||||
/* This exists to deal with THEN lists; parse() handles the indiviudual
|
||||
commands */
|
||||
{
|
||||
for (ip = 0; ip >= 0 && ip < MAXINPUT && input[ip] != -1;) {
|
||||
if (!parse() || quitflag || winflag || deadflag || endflag) break;
|
||||
if (doing_restore) break;
|
||||
if (ip >= 0 && ip < MAXINPUT && input[ip] != -1)
|
||||
writeln(""); /* Insert blank lines between commands when dealing
|
||||
with THEN lists */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static long rm_start_size;
|
||||
static char memstr[100];
|
||||
|
||||
static void mainloop(void) {
|
||||
char *s;
|
||||
|
||||
doing_restore = 0;
|
||||
while (!quitflag) {
|
||||
if (DEBUG_MEM) {
|
||||
Common::sprintf_s(memstr,
|
||||
"A:%ld F:%ld Delta:%ld Size:%ld+%ld=%ld (%ld left)\n",
|
||||
ralloc_cnt, rfree_cnt, ralloc_cnt - rfree_cnt,
|
||||
rm_start_size, rm_size - rm_start_size, rm_size,
|
||||
rm_freesize);
|
||||
writeln(memstr);
|
||||
}
|
||||
rm_size = 0; /* Reset it to zero */
|
||||
rm_freesize = get_rm_freesize();
|
||||
if (!menu_mode) {
|
||||
prompt_out(1);
|
||||
s = agt_readline(0);
|
||||
if (g_vm->shouldQuit())
|
||||
return;
|
||||
|
||||
agt_newline();
|
||||
if (!doing_restore) tokenise(s); /* Tokenizes into input */
|
||||
rfree(s);
|
||||
if (!doing_restore) parse_loop();
|
||||
} else
|
||||
menu_cmd();
|
||||
if (doing_restore) {
|
||||
if (doing_restore == 1)
|
||||
g_vm->loadGame();
|
||||
else if (doing_restore == 2)
|
||||
restart_game();
|
||||
else if (doing_restore == 3 || doing_restore == 4)
|
||||
return; /* Quit or New game requested */
|
||||
doing_restore = 0;
|
||||
}
|
||||
if (winflag || deadflag || endflag || quitflag)
|
||||
game_end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
/* Start up and shut down: Routines to initialise the game state and */
|
||||
/* clean up after the game ends. */
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
static int init(void) {
|
||||
int i, can_save;
|
||||
uchar *tmp1, *tmp2;
|
||||
|
||||
init_vals();
|
||||
init_creat_fix();
|
||||
if (!agx_file) dict[0][0] = 0; /* Turn "ANY" into "" */
|
||||
l_stat[0] = r_stat[0] = 0; /* Clear the status line */
|
||||
/* lactor=lobj=lnoun=NULL;*/
|
||||
tscore = old_score = objscore = 0;
|
||||
turncnt = 0;
|
||||
curr_time = startup_time;
|
||||
loc = start_room - first_room;
|
||||
cmd_saveable = 0;
|
||||
first_visit_flag = newlife_flag = room_firstdesc = 1;
|
||||
curr_lives = max_lives;
|
||||
|
||||
/* Note: flag[0] is the debugging flag and is set elsewhere */
|
||||
if (FLAG_NUM < 0) FLAG_NUM = 0;
|
||||
dbgflagptr = flag = (rbool *)rrealloc(flag, sizeof(rbool) * (FLAG_NUM + 1));
|
||||
for (i = 1; i <= FLAG_NUM; i++)
|
||||
flag[i] = 0;
|
||||
dbgcntptr = agt_counter = (short *)rmalloc(sizeof(short) * (CNT_NUM + 1));
|
||||
for (i = 0; i <= CNT_NUM; i++) {
|
||||
agt_counter[i] = -1;
|
||||
}
|
||||
dbgvarptr = agt_var = (long *)rmalloc(sizeof(*agt_var) * (VAR_NUM + 1));
|
||||
for (i = 0; i <= VAR_NUM; i++)
|
||||
agt_var[i] = 0;
|
||||
|
||||
for (i = 0; i <= maxnoun - first_noun; i++) {
|
||||
if (noun[i].position == nullptr || noun[i].position[0] == '\0')
|
||||
noun[i].pos_prep = 0;
|
||||
else noun[i].pos_prep = -1;
|
||||
noun[i].pos_name = 0;
|
||||
noun[i].initpos = noun[i].position;
|
||||
}
|
||||
|
||||
nomatch_aware = 0; /* By default, not aware. */
|
||||
smart_look = 1; /* By default, LOOK <x> --> EXAMINE */
|
||||
for (i = 0; i < last_cmd; i++) {
|
||||
if (command[i].nouncmd == -1 || command[i].objcmd == -1
|
||||
|| command[i].noun_adj == -1 || command[i].obj_adj == -1
|
||||
|| command[i].prep == -1)
|
||||
nomatch_aware = 1;
|
||||
if (command[i].verbcmd == ext_code[wlook] &&
|
||||
(command[i].nouncmd > 0 || command[i].noun_adj > 0
|
||||
|| command[i].objcmd > 0 || command[i].obj_adj > 0
|
||||
|| command[i].prep > 0))
|
||||
smart_look = 0;
|
||||
}
|
||||
|
||||
pictable = (integer *)rmalloc(sizeof(int) * maxpict);
|
||||
for (i = 0; i < maxpict; i++) pictable[i] = i;
|
||||
init_state_sys(); /* Initialize the system for saving and restoring
|
||||
game states */
|
||||
tmp1 = (uchar *)rmalloc(MEM_MARGIN); /* Preserve some work space */
|
||||
|
||||
tmp2 = getstate(nullptr); /* Make sure we have space to save */
|
||||
if (tmp2 == nullptr) can_save = 0;
|
||||
else can_save = 1;
|
||||
|
||||
if (tmp2 != nullptr)
|
||||
undo_state = getstate(nullptr);
|
||||
else undo_state = nullptr;
|
||||
|
||||
if (undo_state != nullptr)
|
||||
restart_state = getstate(nullptr);
|
||||
else restart_state = nullptr;
|
||||
|
||||
rfree(tmp1);
|
||||
rfree(tmp2);
|
||||
rm_start_size = get_rm_size();
|
||||
rm_freesize = get_rm_freesize();
|
||||
return can_save;
|
||||
}
|
||||
|
||||
|
||||
static void ext_dict(void)
|
||||
/* Enter the vocabulary extensions into the dictionary */
|
||||
{
|
||||
wtype i;
|
||||
for (i = wthe; i <= wabout; i = (wtype)((int)i + 1))
|
||||
ext_code[i] = add_dict(ext_voc[i]);
|
||||
}
|
||||
|
||||
|
||||
static void fix_dummy(void) {
|
||||
int i;
|
||||
|
||||
/* At this point, all occurrences in the game file of the dictionary
|
||||
words have been converted to dictionary indices, and so as long as
|
||||
we don't change the dictionary index values, we can change the contents
|
||||
without interfering with the metacommand scanner (since it compares
|
||||
dictionary indices, not actual strings) */
|
||||
|
||||
if (!PURE_DUMMY) {
|
||||
for (i = 0; i < DUMB_VERB; i++)
|
||||
dict[ syntbl[auxsyn[i + BASE_VERB]] ][5] = ' ';
|
||||
/* Convert underscores into spaces:
|
||||
i.e. 'dummy_verb5' -> 'dummy verb5' */
|
||||
dict[ syntbl[auxsyn[21]] ][6] = ' '; /* change_locations */
|
||||
dict[ syntbl[auxsyn[55]] ][5] = ' '; /* magic_word */
|
||||
}
|
||||
|
||||
if (!PURE_SUBNAME) /* Replace the 'e' by a space */
|
||||
for (i = 0; i < MAX_SUB; i++)
|
||||
Common::sprintf_s(dict[sub_name[i]], strlen(dict[sub_name[i]]) + 1, "subroutin %d", i + 1);
|
||||
/* This must be no longer than 25 characters with the terminating null */
|
||||
|
||||
/* Now set PURE_DOT based on whether any dictionary word
|
||||
contains a period. */
|
||||
if (aver >= AGT18 && aver <= AGT18MAX) PURE_DOT = 0;
|
||||
else {
|
||||
PURE_DOT = FORCE_PURE_DOT;
|
||||
for (i = 0; i < dp && !PURE_DOT; i++)
|
||||
if (strchr(dict[i], '.') != nullptr && /* i.e. dict[i] contains period */
|
||||
i != ext_code[wp]) /* The period itself _is_ a dictionary word:
|
||||
avoid this false match */
|
||||
PURE_DOT = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This is a hack to get rid of the "What Now?" prompt. */
|
||||
static void fix_prompt(void) {
|
||||
descr_line *d;
|
||||
|
||||
if (err_ptr == nullptr) return;
|
||||
d = read_descr(err_ptr[0].start, err_ptr[0].size);
|
||||
if (d == nullptr) return;
|
||||
if (strncasecmp(d[0], "What Now?", 9) == 0)
|
||||
err_ptr[0].size = err_ptr[0].start = 0;
|
||||
free_descr(d);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void close_game(void); /* Called by setup_game, and so needs
|
||||
to be defined here. */
|
||||
|
||||
static fc_type setup_game(fc_type fc)
|
||||
/* game_name is the common filename of the AGT game files */
|
||||
{
|
||||
int can_save;
|
||||
char choice;
|
||||
rbool have_ins;
|
||||
|
||||
bold_mode = 0;
|
||||
rm_acct = 1;
|
||||
rm_trap = 1;
|
||||
rm_size = ralloc_cnt = rfree_cnt = 0;
|
||||
mars_fix = 0;
|
||||
no_auxsyn = 0;
|
||||
debug_disambig = 0;
|
||||
debug_any = 1;
|
||||
dbg_nomsg = 1; /* Suppress output of MSG arguments to metacommands */
|
||||
textbold = 0;
|
||||
debug_mode = 0;
|
||||
aver = 0;
|
||||
verboseflag = 1;
|
||||
notify_flag = 0;
|
||||
logflag = 0;
|
||||
menu_mode = 0;
|
||||
fast_replay = 0;
|
||||
stable_random = BATCH_MODE || make_test;
|
||||
if (make_test) BATCH_MODE = 0;
|
||||
hold_fc = fc;
|
||||
set_default_filenames(fc);
|
||||
|
||||
init_stack();
|
||||
read_config(agt_globalfile(0), 1); /* Global configuration file */
|
||||
|
||||
/* Now that we *have* PATH information, go looking for the games */
|
||||
/* At the very least, it creates an rmalloc'd copy of game_name */
|
||||
read_config(openfile(fc, fCFG, nullptr, 0), 0);
|
||||
text_file = 0;
|
||||
/* First pass through game specific config file */
|
||||
build_trans_ascii();
|
||||
#ifdef PROFILE
|
||||
resetwatch();
|
||||
#endif
|
||||
writeln("Loading game...");
|
||||
if (!read_agx(fc, 0) && !readagt(fc, 0))
|
||||
fatal("Unable to load game.");
|
||||
#ifdef PROFILE
|
||||
writeln(stopwatch());
|
||||
agt_waitkey();
|
||||
#endif
|
||||
if (have_opt)
|
||||
menu_mode = opt_data[5]; /* See agtread.c for discussion of OPT file
|
||||
format */
|
||||
text_file = 1;
|
||||
read_config(openfile(fc, fCFG, nullptr, 0), 1); /*Game specific config file*/
|
||||
text_file = 0;
|
||||
if (min_ver > AGIL_VERID) {
|
||||
if (FORCE_VERSION)
|
||||
agtwarn("This game requires a later version of AGiliTy.", 0);
|
||||
else
|
||||
fatal("This game requires a later version of AGiliTy.");
|
||||
}
|
||||
sort_cmd();
|
||||
ext_dict();
|
||||
build_verbmenu();
|
||||
fix_dummy(); /* Prevent player from calling dummy verbs or subroutines by
|
||||
typing 'Subroutine n' on the command line */
|
||||
can_save = init();
|
||||
if (!agx_file) open_descr(fc);
|
||||
fix_prompt(); /* Kill off 'What Now?' prompt. */
|
||||
if (BATCH_MODE || make_test)
|
||||
set_test_mode(fc);
|
||||
start_interface(fc);
|
||||
fontcmd(2, 0); /* Set initial font */
|
||||
if (intro_first && intro_ptr.size > 0) {
|
||||
agt_clrscr();
|
||||
print_descr(intro_ptr, 1);
|
||||
wait_return();
|
||||
}
|
||||
if (aver >= AGTME10)
|
||||
pictcmd(3, 0); /* Show title image, if there is one */
|
||||
print_title(fc);
|
||||
have_ins = open_ins_file(fc, 0);
|
||||
|
||||
if (have_ins) {
|
||||
do {
|
||||
writestr("Choose <I>nstructions, or <other> to start the game");
|
||||
|
||||
choice = tolower(agt_getchar()); /* Wait for keypress */
|
||||
if (g_vm->shouldQuit())
|
||||
return nullptr;
|
||||
|
||||
agt_clrscr();
|
||||
if (have_ins && choice == 'i')
|
||||
print_instructions(fc);
|
||||
} while (choice == 'i');
|
||||
}
|
||||
close_ins_file();
|
||||
|
||||
if (!intro_first && intro_ptr.size > 0) {
|
||||
print_descr(intro_ptr, 1);
|
||||
wait_return();
|
||||
agt_clrscr();
|
||||
}
|
||||
if (maxroom < first_room) {
|
||||
close_game();
|
||||
error("Invalid first room");
|
||||
}
|
||||
set_statline();
|
||||
if (can_save == 0) {
|
||||
writeln("[Insufficiant memory to support SAVE, RESTORE, or UNDO]");
|
||||
} else if (undo_state == nullptr)
|
||||
writeln("[Insufficiant memory to support UNDO]");
|
||||
do_look = do_autoverb = 1;
|
||||
newroom();
|
||||
rm_acct = 1; /* Turn on memory allocation accounting */
|
||||
return fc;
|
||||
}
|
||||
|
||||
|
||||
/* We need to import save_lnoun from exec.c so that we can free it. */
|
||||
extern parse_rec *save_lnoun;
|
||||
|
||||
void close_game(void) {
|
||||
if (agx_file)
|
||||
agx_close_descr();
|
||||
else
|
||||
close_descr();
|
||||
fontcmd(1, -1); /* Restore original font */
|
||||
musiccmd(7, -1); /* Clean up */
|
||||
close_interface();
|
||||
|
||||
/* Now free everything in sight; this _shouldn't_ be necessary,
|
||||
but why take chances? */
|
||||
free_all_agtread();
|
||||
rfree(restart_state);
|
||||
rfree(undo_state);
|
||||
rfree(pictable);
|
||||
rfree(save_lnoun);
|
||||
rfree(verbptr);
|
||||
rfree(verbend);
|
||||
rfree(agt_counter);
|
||||
rfree(agt_var);
|
||||
free_creat_fix();
|
||||
flag = (rbool *)rrealloc(flag, sizeof(rbool)); /* Preserve the debugging flag */
|
||||
|
||||
if (DEBUG_MEM)
|
||||
debug("\n\nAlloc:%ld Freed:%ld Difference:%ld\n", ralloc_cnt,
|
||||
rfree_cnt, ralloc_cnt - rfree_cnt);
|
||||
}
|
||||
|
||||
|
||||
void run_game(fc_type fc) {
|
||||
doing_restore = 0;
|
||||
rm_acct = 1;
|
||||
rm_trap = 1;
|
||||
rm_size = ralloc_cnt = rfree_cnt = 0;
|
||||
read_config(agt_globalfile(0), 1); /* Global configuration file:
|
||||
get PATH information*/
|
||||
fix_file_context(fc, fDA1);
|
||||
do {
|
||||
if (doing_restore == 3) {
|
||||
release_file_context(&fc);
|
||||
fc = setup_game(new_game());
|
||||
} else setup_game(fc);
|
||||
doing_restore = 0;
|
||||
|
||||
if (!g_vm->shouldQuit())
|
||||
mainloop();
|
||||
close_game();
|
||||
|
||||
if (g_vm->shouldQuit())
|
||||
break;
|
||||
} while (doing_restore == 3);
|
||||
release_file_context(&fc);
|
||||
}
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
1219
engines/glk/agt/agility.h
Normal file
1219
engines/glk/agt/agility.h
Normal file
File diff suppressed because it is too large
Load Diff
106
engines/glk/agt/agt.cpp
Normal file
106
engines/glk/agt/agt.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/agt/agt.h"
|
||||
#include "glk/quetzal.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "glk/agt/agility.h"
|
||||
#include "glk/agt/interp.h"
|
||||
#include "glk/agt/exec.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
AGT *g_vm;
|
||||
|
||||
extern void glk_main();
|
||||
extern int glk_startup_code();
|
||||
extern void gagt_finalizer();
|
||||
|
||||
AGT::AGT(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
|
||||
gagt_main_window(nullptr), gagt_status_window(nullptr), gagt_gamefile(nullptr),
|
||||
gagt_game_message(nullptr), gagt_delay_mode(DELAY_SHORT), gagt_font_mode(FONT_AUTOMATIC),
|
||||
gagt_transcript_stream(nullptr), gagt_inputlog_stream(nullptr),
|
||||
gagt_readlog_stream(nullptr), gagt_replacement_enabled(true),
|
||||
gagt_extended_status_enabled(true), gagt_abbreviations_enabled(true),
|
||||
gagt_commands_enabled(true), gagt_clean_exit_test(false) {
|
||||
g_vm = this;
|
||||
}
|
||||
|
||||
void AGT::runGame() {
|
||||
initialize();
|
||||
glk_main();
|
||||
|
||||
gagt_finalizer();
|
||||
}
|
||||
|
||||
void AGT::initialize() {
|
||||
_gameFile.close();
|
||||
gagt_gamefile = getFilename().c_str();
|
||||
|
||||
initializeSettings();
|
||||
glk_startup_code();
|
||||
}
|
||||
|
||||
void AGT::initializeSettings() {
|
||||
// Delay
|
||||
if (ConfMan.hasKey("delay")) {
|
||||
Common::String delay = ConfMan.get("delay");
|
||||
switch (tolower(delay.firstChar())) {
|
||||
case 'f':
|
||||
// Full
|
||||
gagt_delay_mode = DELAY_FULL;
|
||||
break;
|
||||
case 's':
|
||||
// Short
|
||||
gagt_delay_mode = DELAY_SHORT;
|
||||
break;
|
||||
case 'n':
|
||||
case 'o':
|
||||
// None/off
|
||||
gagt_delay_mode = DELAY_OFF;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Boolean flags
|
||||
if (ConfMan.hasKey("replacement"))
|
||||
gagt_replacement_enabled = ConfMan.getBool("replacement");
|
||||
if (ConfMan.hasKey("abbreviations"))
|
||||
gagt_abbreviations_enabled = ConfMan.getBool("abbreviations");
|
||||
if (ConfMan.hasKey("extended_status"))
|
||||
gagt_extended_status_enabled = ConfMan.getBool("extended_status");
|
||||
if (ConfMan.hasKey("commands"))
|
||||
gagt_commands_enabled = ConfMan.getBool("commands");
|
||||
}
|
||||
|
||||
Common::Error AGT::readSaveData(Common::SeekableReadStream *rs) {
|
||||
return loadgame(rs);
|
||||
}
|
||||
|
||||
Common::Error AGT::writeGameData(Common::WriteStream *ws) {
|
||||
return savegame(ws);
|
||||
}
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
125
engines/glk/agt/agt.h
Normal file
125
engines/glk/agt/agt.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Based on Agility interpreter version 1.1.2 */
|
||||
|
||||
#ifndef GLK_AGT
|
||||
#define GLK_AGT
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "glk/glk_api.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
enum DelayMode {
|
||||
DELAY_FULL, DELAY_SHORT, DELAY_OFF
|
||||
};
|
||||
|
||||
enum FontMode {
|
||||
FONT_AUTOMATIC, FONT_FIXED_WIDTH, FONT_PROPORTIONAL, FONT_DEBUG
|
||||
};
|
||||
|
||||
/**
|
||||
* AGT Adams game interpreter
|
||||
*/
|
||||
class AGT : public GlkAPI {
|
||||
public:
|
||||
const char *gagt_gamefile; /* Name of game file. */
|
||||
const char *gagt_game_message; /* Error message. */
|
||||
DelayMode gagt_delay_mode;
|
||||
|
||||
/**
|
||||
* We use two Glk windows; one is two lines at the top of the display area
|
||||
* for status, and the other is the remainder of the display area, used for,
|
||||
* well, everything else. Where a particular Glk implementation won't do
|
||||
* more than one window, the status window remains NULL.
|
||||
*/
|
||||
winid_t gagt_main_window, gagt_status_window;
|
||||
|
||||
/**
|
||||
* Transcript stream and input log. These are NULL if there is no current
|
||||
* collection of these strings.
|
||||
*/
|
||||
strid_t gagt_transcript_stream, gagt_inputlog_stream;
|
||||
|
||||
/**
|
||||
* Input read log stream, for reading back an input log
|
||||
*/
|
||||
strid_t gagt_readlog_stream;
|
||||
|
||||
/* Options that may be turned off or set by command line flags. */
|
||||
FontMode gagt_font_mode;
|
||||
bool gagt_replacement_enabled, gagt_extended_status_enabled,
|
||||
gagt_abbreviations_enabled, gagt_commands_enabled;
|
||||
|
||||
/**
|
||||
* Flag to set if we want to test for a clean exit. Without this it's a
|
||||
* touch tricky sometimes to corner AGiliTy into calling exit() for us; it
|
||||
* tends to require a broken game file.
|
||||
*/
|
||||
bool gagt_clean_exit_test;
|
||||
private:
|
||||
/**
|
||||
* Handles initialization
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
/**
|
||||
* Handles flag setup from configuration
|
||||
*/
|
||||
void initializeSettings();
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
AGT(OSystem *syst, const GlkGameDescription &gameDesc);
|
||||
|
||||
/**
|
||||
* Returns the running interpreter type
|
||||
*/
|
||||
InterpreterType getInterpreterType() const override {
|
||||
return INTERPRETER_AGT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the game
|
||||
*/
|
||||
void runGame() override;
|
||||
|
||||
/**
|
||||
* Load a savegame from the passed Quetzal file chunk stream
|
||||
*/
|
||||
Common::Error readSaveData(Common::SeekableReadStream *rs) override;
|
||||
|
||||
/**
|
||||
* Save the game. The passed write stream represents access to the UMem chunk
|
||||
* in the Quetzal save file that will be created
|
||||
*/
|
||||
Common::Error writeGameData(Common::WriteStream *ws) override;
|
||||
};
|
||||
|
||||
extern AGT *g_vm;
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
1744
engines/glk/agt/agtread.cpp
Normal file
1744
engines/glk/agt/agtread.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1478
engines/glk/agt/agxfile.cpp
Normal file
1478
engines/glk/agt/agxfile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
600
engines/glk/agt/auxfile.cpp
Normal file
600
engines/glk/agt/auxfile.cpp
Normal file
@@ -0,0 +1,600 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/agt/agility.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* Purity flag initialization */
|
||||
/* Logically, these belong in agtdata.c, but I wanted to keep them */
|
||||
/* near the CFG reading routines. */
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* The following are AGT 'purity' flags; they turn off features of */
|
||||
/* my interpreter that are not fully consistent with the original AGT */
|
||||
/* and so could break some games. Some of these are trivial improvements; */
|
||||
/* some are more radical and should be used with caution. Several are */
|
||||
/* only useful if a game was designed with them in mind. */
|
||||
/* In all cases, setting the flag to 1 more closely follows the */
|
||||
/* behavior of the original interpreters */
|
||||
/* WARNING: Many of these haven't been tested extenstivly in the non-default
|
||||
state. */
|
||||
|
||||
|
||||
rbool PURE_ANSWER = 0; /* For ME questions, requires that AND-separated
|
||||
answers be in the same order in the player's
|
||||
answer as they are in the game file. According
|
||||
to the AGT documentation, AND should ignore
|
||||
the order, but the original AGT interpreters
|
||||
(at least the one I've tested) don't conform
|
||||
to this. */
|
||||
|
||||
rbool PURE_TIME = 1; /* Set to 0 causes time to always be increased
|
||||
by delta_time rather than by a random amount
|
||||
between 0 and delta_time. Only really of any use
|
||||
to a game author who wanted to write a game
|
||||
explicitly for AGiliTy. */
|
||||
|
||||
/* rbool PURE_BOLD=1; Set to 0 causes the backslash to toggle bold on and
|
||||
off for all versions of AGT, not just 1.8x.
|
||||
I can think of no reason to do this unless
|
||||
you are an AGT author who wants to use the 1.8x
|
||||
bold feature with the Master's Edition compiler. */
|
||||
|
||||
rbool PURE_AND = 1; /* increment the turn counter for each noun in a
|
||||
chain of <noun> AND <noun> AND ... If 0, the turn
|
||||
counter will only be incremented by one in such a case.
|
||||
(need to do something about metacommands, as well...) */
|
||||
|
||||
rbool PURE_METAVERB = 1; /* If set, ANY and AFTER commands are run even
|
||||
if you type in a metaverb (SAVE, RESTORE,...
|
||||
that is, any verb that doesn't cause time to
|
||||
pass). Verb specific metacommands are _always_
|
||||
run. */
|
||||
|
||||
rbool PURE_ROOMTITLE = 1; /* If 0, the interpreter will print out room
|
||||
names before room descriptions even for
|
||||
pre-ME games */
|
||||
|
||||
rbool PURE_SYN = 0; /* Treats synonyms as nouns when parsing: that is, they
|
||||
must show up only as the last word and they have the
|
||||
same priority as noun matches during disambiguation.
|
||||
If this is 0, then synonyms can appear anywhere in
|
||||
the name the player types in but are still
|
||||
disambiguated as nouns. */
|
||||
|
||||
rbool PURE_NOUN = 0; /* _Requires_ a noun to end a word. This is only
|
||||
imperfectly supported: if there are no other
|
||||
possible matches the parser will take the adjective-
|
||||
only one anyhow. Frankly, I can't think of any reason
|
||||
to set this to 1, but it's included for completeness
|
||||
sake (and for any AGT Purists out there :-) ) */
|
||||
|
||||
rbool PURE_ADJ = 1; /* Picks noun/syn-matches over pure adj matches
|
||||
when disambiguating. This is redundant if PURE_NOUN=1
|
||||
since in that case pure adjective matches will
|
||||
be rejected anyhow. */
|
||||
|
||||
rbool PURE_DUMMY = 0; /* If set, the player can running dummy verbs
|
||||
in the game by typing 'dummy_verb3'; otherwise,
|
||||
this will produce an error message */
|
||||
|
||||
rbool PURE_SUBNAME = 0; /* If set, the player can run subroutines from
|
||||
the parse line by typing (e.g.) 'subroutine4'
|
||||
(yes, the original AGT interpreters actually
|
||||
allow this). If cleared, this cheat isn't
|
||||
available */
|
||||
rbool PURE_PROSUB = 0; /* If clear, then $you$ substitutions are done
|
||||
everywhere $$ substitutions are, even in
|
||||
messages written by the game author.
|
||||
If set, these substitutions are only made
|
||||
in internal game messages */
|
||||
|
||||
rbool PURE_HOSTILE = 1; /* =0 Will allow you to leave a room with a hostile
|
||||
creature if you go back the way you came */
|
||||
rbool PURE_ALL = 1; /* =0 will cause the parser to expand ALL */
|
||||
rbool PURE_DISAMBIG = 1; /* =0 will cause intelligent disambiguation */
|
||||
rbool PURE_GETHOSTILE = 1; /* =0 will prevent the player from picking things
|
||||
up in a room with a hostile creature */
|
||||
|
||||
rbool PURE_OBJ_DESC = 1; /* =0 prevents [providing light] messages
|
||||
from being shown */
|
||||
|
||||
rbool PURE_ERROR = 0; /* =1 means no GAME ERROR messages will be printed
|
||||
out */
|
||||
|
||||
rbool PURE_SIZE = 1; /* =0 eliminates size/weight limits on how many
|
||||
things the player can wear or carry. (But it's
|
||||
still impossible to pick things up that are
|
||||
in themselves larger than the player's capacity) */
|
||||
|
||||
rbool PURE_GRAMMAR = 1; /* =0 prints error messages if the player uses a
|
||||
built in verb with an extra object.
|
||||
(e.g. YELL CHAIR). Otherwise, the extra object
|
||||
will just be ignored. */
|
||||
|
||||
rbool PURE_SYSMSG = 1; /* =0 causes AGiliTy to always use the default
|
||||
messages even if the game file has its own
|
||||
standard error messages. */
|
||||
|
||||
rbool PURE_AFTER = 1; /* =0 causes LOOK and other end-of-turn events
|
||||
to happen *before* AFTER commands run. */
|
||||
|
||||
rbool PURE_PROPER = 1; /* Don't automatically treat creatures as proper nouns */
|
||||
|
||||
rbool TWO_CYCLE = 0; /* AGT 1.83-style two-cycle metacommand execution. */
|
||||
rbool FORCE_VERSION = 0; /* Load even if the version is wrong. */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* .CFG reading routines */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* The main interpreter handles configuration in this order:
|
||||
1) Global configuration file
|
||||
2) First pass through game specific CFG to get the settings for
|
||||
SLASH_BOLD and IBM_CHAR which we need to know _before_ reading
|
||||
in the game.
|
||||
3) Read in the game.
|
||||
4) Main pass through game specific CFG. Doing it here ensures that
|
||||
its settings will override those in the gamefile.
|
||||
Secondary programs (such as agt2agx) usually only call this once, for
|
||||
the game specific configuration file.
|
||||
*/
|
||||
|
||||
#define opt(s) (strcasecmp(optstr[0],s)==0)
|
||||
|
||||
static void cfg_option(int optnum, char *optstr[], rbool lastpass)
|
||||
/* This is passed each of the options; it is responsible for parsing
|
||||
them or passing them on to the platform-specific option handler
|
||||
agt_option() */
|
||||
/* lastpass is set if it is the last pass through this configuration
|
||||
file; it is false only on the first pass through the game specific
|
||||
configuration file during the run of the main interpreter */
|
||||
{
|
||||
rbool setflag;
|
||||
|
||||
if (optnum == 0 || optstr[0] == nullptr) return;
|
||||
|
||||
if (strncasecmp(optstr[0], "no_", 3) == 0) {
|
||||
optstr[0] += 3;
|
||||
setflag = 0;
|
||||
} else setflag = 1;
|
||||
|
||||
if (opt("slash_bold")) bold_mode = setflag;
|
||||
else if (!lastpass) {
|
||||
/* On the first pass, we ignore all but a few options */
|
||||
agil_option(optnum, optstr, setflag, lastpass);
|
||||
return;
|
||||
} else if (opt("irun")) irun_mode = setflag;
|
||||
else if (opt("block_hostile")) PURE_HOSTILE = setflag;
|
||||
else if (opt("get_hostile")) PURE_GETHOSTILE = setflag;
|
||||
else if (opt("debug")) {
|
||||
if (!agx_file && aver <= AGTME10) debug_mode = setflag;
|
||||
if (setflag == 0) debug_mode = 0; /* Can always turn debugging support off */
|
||||
} else if (opt("pure_answer")) PURE_ANSWER = setflag;
|
||||
else if (opt("const_time")) PURE_TIME = !setflag;
|
||||
else if (opt("fix_multinoun")) PURE_AND = !setflag;
|
||||
else if (opt("fix_metaverb")) PURE_METAVERB = !setflag;
|
||||
else if (opt("roomtitle")) PURE_ROOMTITLE = !setflag;
|
||||
else if (opt("pure_synonym")) PURE_SYN = setflag;
|
||||
else if (opt("adj_noun")) PURE_ADJ = !setflag;
|
||||
else if (opt("pure_dummy")) PURE_DUMMY = setflag;
|
||||
else if (opt("pure_subroutine")) PURE_SUBNAME = setflag;
|
||||
else if (opt("pronoun_subs")) PURE_PROSUB = !setflag;
|
||||
else if (opt("verbose")) verboseflag = setflag;
|
||||
else if (opt("fixed_font")) font_status = 1 + !setflag;
|
||||
else if (opt("alt_any")) mars_fix = setflag;
|
||||
else if (opt("smart_disambig")) PURE_DISAMBIG = !setflag;
|
||||
else if (opt("expand_all")) PURE_ALL = !setflag;
|
||||
else if (opt("object_notes")) PURE_OBJ_DESC = setflag;
|
||||
else if (opt("error")) PURE_ERROR = !setflag;
|
||||
else if (opt("ignore_size")) PURE_SIZE = !setflag;
|
||||
else if (opt("check_grammar")) PURE_GRAMMAR = !setflag;
|
||||
else if (opt("default_errors")) PURE_SYSMSG = !setflag;
|
||||
else if (opt("pure_after")) PURE_AFTER = !setflag;
|
||||
else if (opt("proper_creature")) PURE_PROPER = !setflag;
|
||||
else agil_option(optnum, optstr, setflag, lastpass);
|
||||
}
|
||||
|
||||
#undef opt
|
||||
|
||||
/* Returns false if it there are too many tokens on the line */
|
||||
rbool parse_config_line(char *buff, rbool lastpass) {
|
||||
char *opt[50], *p;
|
||||
int optc;
|
||||
|
||||
optc = 0;
|
||||
opt[0] = nullptr;
|
||||
for (p = buff; *p; p++) {
|
||||
if (isspace(*p)) { /* Whitespace */
|
||||
if (opt[optc] != nullptr) { /*... which means this is the first whitespace */
|
||||
if (optc == 50) return 0; /* Too many */
|
||||
opt[++optc] = nullptr;
|
||||
}
|
||||
*p = 0;
|
||||
} else /* No whitespace */
|
||||
if (opt[optc] == nullptr) /* ...this is the first non-whitespace */
|
||||
opt[optc] = p;
|
||||
}
|
||||
if (opt[optc] != nullptr) opt[++optc] = nullptr;
|
||||
cfg_option(optc, opt, lastpass);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* For the meaning of lastpass, see comments to cfg_option() above */
|
||||
void read_config(genfile cfgfile, rbool lastpass) {
|
||||
char buff[100];
|
||||
|
||||
if (lastpass) {
|
||||
/* Default to smart disambiguation for 1.5 onwards */
|
||||
if (aver >= AGT15) PURE_DISAMBIG = 0;
|
||||
}
|
||||
|
||||
if (!filevalid(cfgfile, fCFG)) return;
|
||||
|
||||
while (readln(cfgfile, buff, 99)) {
|
||||
if (buff[0] == '#') continue; /* Comments */
|
||||
/* Now we parse the line into words, with opt[] pointing at the words
|
||||
and optc counting how many there are. */
|
||||
if (!parse_config_line(buff, lastpass))
|
||||
rprintf("Too many tokens on configuration line.\n");
|
||||
}
|
||||
readclose(cfgfile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Read OPT file */
|
||||
/* (most of these routines used to be in agil.c) */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* .OPT reading routines */
|
||||
/* I've put the comments on the format here because they don't really
|
||||
belong anywhere else. (Maybe in agility.h, but I don't want to further
|
||||
clutter that already quite cluttered file with something as peripheral
|
||||
as this) */
|
||||
/* OPT file format: the .OPT file consists of 14 bytes. They are:
|
||||
0 Screen size(0=43/50 rows, 1=25 rows)
|
||||
1 Status line(1=top, 0=none, -1=bottom)
|
||||
2 Unknown, always seems to be 0
|
||||
3 Put box around status line?
|
||||
4 Sound on?
|
||||
5 Menus on?
|
||||
6 Fixed input line?
|
||||
7 Print transcript?
|
||||
8 Height of menus (3, 4, 5, 6, 7, or 8)
|
||||
9 Unknown, always seems to be 0
|
||||
10-13 Color scheme: output/status/input/menu, specified in DOS attribute
|
||||
format (Bbbbffff, B=blink, b=backround, f=foreground,
|
||||
MSB of foreground specifies intensity ("bold") ). */
|
||||
/* The interpreter ignores almost all of this. */
|
||||
|
||||
void read_opt(fc_type fc) {
|
||||
const char *errstr;
|
||||
genfile optfile;
|
||||
|
||||
have_opt = 0;
|
||||
optfile = openbin(fc, fOPT, nullptr, 0);
|
||||
if (filevalid(optfile, fOPT)) {
|
||||
if (!binread(optfile, opt_data, 14, 1, &errstr))
|
||||
fatal("Invalid OPT file.");
|
||||
have_opt = 1;
|
||||
readclose(optfile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Read and process TTL */
|
||||
/* (most of these routines used to be in agil.c) */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Shades of Gray uses a custom interpreter that prints out the names
|
||||
of the authors as the program loads. */
|
||||
/* Normally I wouldn't bother with this, but Shades of Gray is probably
|
||||
the best known of all AGT games */
|
||||
|
||||
#define SOGCREDIT 7
|
||||
static const char *sogauthor[SOGCREDIT] = {
|
||||
"Mark \"Sam\" Baker",
|
||||
"Steve \"Aaargh\" Bauman",
|
||||
"Belisana \"The\" Magnificent",
|
||||
"Mike \"of Locksley\" Laskey",
|
||||
"Judith \"Teela Brown\" Pintar",
|
||||
"Hercules \"The Loyal\" SysOp",
|
||||
"Cindy \"Nearly Amelia\" Yans"
|
||||
};
|
||||
|
||||
static rbool check_dollar(char *s)
|
||||
/* Determines if s consists of an empty string with a single dollar sign
|
||||
and possibly whitespace */
|
||||
{
|
||||
rbool dfound;
|
||||
dfound = 0;
|
||||
for (; *s != 0; s++)
|
||||
if (*s == '$' && !dfound) dfound = 1;
|
||||
else if (!rspace(*s)) return 0;
|
||||
return dfound;
|
||||
}
|
||||
|
||||
descr_line *read_ttl(fc_type fc) {
|
||||
genfile ttlfile;
|
||||
int i, j, height;
|
||||
descr_line *buff;
|
||||
|
||||
ttlfile = openfile(fc, fTTL, nullptr, 0);
|
||||
/* "Warning: Could not open title file '%s'." */
|
||||
if (!filevalid(ttlfile, fTTL)) return nullptr;
|
||||
build_fixchar();
|
||||
|
||||
buff = (descr_line *)rmalloc(sizeof(descr_line));
|
||||
i = 0;
|
||||
while (nullptr != (buff[i] = readln(ttlfile, nullptr, 0))) {
|
||||
if (strncmp(buff[i], "END OF FILE", 11) == 0) break;
|
||||
else if (aver >= AGT18 && aver <= AGT18MAX && check_dollar(buff[i]))
|
||||
statusmode = 4;
|
||||
else {
|
||||
for (j = 0; buff[i][j] != 0; j++)
|
||||
buff[i][j] = fixchar[(uchar)buff[i][j]];
|
||||
/* Advance i and set the next pointer to NULL */
|
||||
buff = (descr_line *)rrealloc(buff, sizeof(descr_line) * (++i + 1));
|
||||
buff[i] = nullptr;
|
||||
}
|
||||
rfree(buff[i]);
|
||||
}
|
||||
readclose(ttlfile);
|
||||
|
||||
rfree(buff[i]);
|
||||
while (buff[i] == nullptr || strlen(buff[i]) <= 1) { /* Discard 'empty' lines */
|
||||
if (i == 0) break;
|
||||
rfree(buff[i]);
|
||||
i--;
|
||||
}
|
||||
height = i;
|
||||
|
||||
if (aver == AGTCOS && ver == 4 && height >= 17) /* SOGGY */
|
||||
for (i = 0; i < SOGCREDIT; i++)
|
||||
if (strlen(sogauthor[i]) + 9 + i < strlen(buff[i + 7]))
|
||||
memcpy(buff[i + 7] + 9 + i, sogauthor[i], strlen(sogauthor[i]));
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
void free_ttl(descr_line *title) {
|
||||
int i;
|
||||
if (title == nullptr) return;
|
||||
for (i = 0; title[i] != nullptr; i++)
|
||||
rfree(title[i]);
|
||||
rfree(title);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Read and convert VOC */
|
||||
/* (most of these routines used to be in agil.c) */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static const char *newvoc[] = { "1 Menu", "1 Restart", "1 Undo" };
|
||||
static int newindex = 0; /* Points into newvoc */
|
||||
|
||||
void add_verbrec(const char *verb_line, rbool addnew) {
|
||||
char s[3];
|
||||
Common::String verbStr(verb_line);
|
||||
|
||||
while (!verbStr.empty() && rspace(verbStr.firstChar()))
|
||||
verbStr.deleteChar(0);
|
||||
|
||||
if (verbStr.empty() || verbStr.hasPrefix("!"))
|
||||
return; /* Comment or empty line */
|
||||
|
||||
/* The following guarantees automatic initialization of the verbrec structures */
|
||||
if (!addnew)
|
||||
while (newindex < 3 && strcasecmp(verbStr.c_str() + 2, newvoc[newindex] + 2) > 0)
|
||||
add_verbrec(newvoc[newindex++], 1);
|
||||
|
||||
verbinfo = (verbentry_rec *)rrealloc(verbinfo, (vm_size + 1) * sizeof(verbentry_rec));
|
||||
|
||||
s[0] = verbStr.firstChar();
|
||||
s[1] = 0;
|
||||
verbinfo[vm_size].objnum = strtol(s, nullptr, 10) - 1;
|
||||
|
||||
verbStr.deleteChar(0);
|
||||
verbStr.deleteChar(0);
|
||||
|
||||
verbinfo[vm_size].verb = verbinfo[vm_size].prep = 0;
|
||||
|
||||
uint idx = 0;
|
||||
while (idx < verbStr.size()) {
|
||||
while (idx < verbStr.size() && !rspace(verbStr[idx]))
|
||||
++idx;
|
||||
if (idx < verbStr.size()) {
|
||||
verbStr.setChar('\0', idx);
|
||||
++idx;
|
||||
}
|
||||
|
||||
verbinfo[vm_size].verb = search_dict(verbStr.c_str());
|
||||
if (verbinfo[vm_size].verb == -1) {
|
||||
verbinfo[vm_size].verb = 0;
|
||||
return;
|
||||
}
|
||||
if (idx < verbStr.size()) {
|
||||
verbinfo[vm_size].prep = search_dict(verbStr.c_str() + idx);
|
||||
if (verbinfo[vm_size].prep == -1)
|
||||
verbinfo[vm_size].prep = 0;
|
||||
}
|
||||
}
|
||||
|
||||
vm_size++;
|
||||
}
|
||||
|
||||
void init_verbrec(void)
|
||||
/* Need to insert special verbs into verbinfo */
|
||||
/* Fill in vnum field */
|
||||
/* UNDO, RESTART, MENU */
|
||||
{
|
||||
verbinfo = nullptr;
|
||||
vm_size = 0;
|
||||
newindex = 0;
|
||||
if (freeze_mode) newindex = 1; /* Don't include MENU option if we can't
|
||||
use it. */
|
||||
}
|
||||
|
||||
void finish_verbrec(void) {
|
||||
for (; newindex < 3; newindex++) add_verbrec(newvoc[newindex], 1);
|
||||
}
|
||||
|
||||
|
||||
void read_voc(fc_type fc) {
|
||||
char linbuf[80];
|
||||
genfile vocfile;
|
||||
|
||||
init_verbrec();
|
||||
vocfile = openfile(fc, fVOC, nullptr, 0);
|
||||
if (filevalid(vocfile, fVOC)) { /* Vocabulary file exists */
|
||||
while (readln(vocfile, linbuf, 79))
|
||||
add_verbrec(linbuf, 0);
|
||||
readclose(vocfile);
|
||||
finish_verbrec();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Read INS file */
|
||||
/* (most of these routines used to be in agil.c) */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static genfile insfile = BAD_TEXTFILE;
|
||||
static char *ins_buff;
|
||||
|
||||
static descr_line *ins_descr = nullptr;
|
||||
static int ins_line; /* Current instruction line */
|
||||
|
||||
|
||||
/* Return 1 on success, 0 on failure */
|
||||
rbool open_ins_file(fc_type fc, rbool report_error) {
|
||||
ins_buff = nullptr;
|
||||
ins_line = 0;
|
||||
|
||||
if (ins_descr != nullptr) return 1;
|
||||
|
||||
if (filevalid(insfile, fINS)) {
|
||||
textrewind(insfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (agx_file) {
|
||||
ins_descr = read_descr(ins_ptr.start, ins_ptr.size);
|
||||
if (ins_descr != nullptr) return 1;
|
||||
|
||||
/* Note that if the AGX file doesn't contain an INS block, we
|
||||
don't immediately give up but try opening <fname>.INS */
|
||||
}
|
||||
|
||||
insfile = openfile(fc, fINS,
|
||||
report_error
|
||||
? "Sorry, Instructions aren't available for this game"
|
||||
: nullptr,
|
||||
0);
|
||||
return (filevalid(insfile, fINS));
|
||||
}
|
||||
|
||||
char *read_ins_line(void) {
|
||||
if (ins_descr) {
|
||||
if (ins_descr[ins_line] != nullptr)
|
||||
return ins_descr[ins_line++];
|
||||
else return nullptr;
|
||||
} else {
|
||||
rfree(ins_buff);
|
||||
ins_buff = readln(insfile, nullptr, 0);
|
||||
return ins_buff;
|
||||
}
|
||||
}
|
||||
|
||||
void close_ins_file(void) {
|
||||
if (ins_descr) {
|
||||
free_descr(ins_descr);
|
||||
ins_descr = nullptr;
|
||||
} else if (filevalid(insfile, fINS)) {
|
||||
rfree(ins_buff);
|
||||
readclose(insfile);
|
||||
insfile = BAD_TEXTFILE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
descr_line *read_ins(fc_type fc) {
|
||||
descr_line *txt;
|
||||
char *buff;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
txt = nullptr;
|
||||
if (open_ins_file(fc, 0)) { /* Instruction file exists */
|
||||
while (nullptr != (buff = read_ins_line())) {
|
||||
/* Enlarge txt; we use (i+2) here to leave space for the trailing \0 */
|
||||
txt = (descr_line *)rrealloc(txt, sizeof(descr_ptr) * (i + 2));
|
||||
txt[i++] = rstrdup(buff);
|
||||
}
|
||||
if (txt != nullptr)
|
||||
txt[i] = nullptr; /* There is space for this since we used (i+2) above */
|
||||
close_ins_file();
|
||||
}
|
||||
return txt;
|
||||
}
|
||||
|
||||
|
||||
void free_ins(descr_line *instr) {
|
||||
int i;
|
||||
if (instr == nullptr) return;
|
||||
for (i = 0; instr[i] != nullptr; i++)
|
||||
rfree(instr[i]);
|
||||
rfree(instr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Character translation routines, used by agtread.c and read_ttl() */
|
||||
void build_fixchar(void) {
|
||||
int i;
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (i == '\r' || i == '\n') fixchar[i] = ' ';
|
||||
else if (i == '\\' && bold_mode) fixchar[i] = FORMAT_CODE;
|
||||
else if (i >= 0x80 && fix_ascii_flag)
|
||||
fixchar[i] = trans_ibm[i & 0x7f];
|
||||
else if (i == 0) /* Fix color and blink codes */
|
||||
fixchar[i] = FORMAT_CODE;
|
||||
else fixchar[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
287
engines/glk/agt/config.h
Normal file
287
engines/glk/agt/config.h
Normal file
@@ -0,0 +1,287 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_AGT_CONFIG
|
||||
#define GLK_AGT_CONFIG
|
||||
|
||||
#include "glk/glk_api.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
/*
|
||||
This file contains most of the configuration information
|
||||
including the platform-dependent #define statements
|
||||
It's in three major sections:
|
||||
--Platform specific defines for various platforms, each
|
||||
surrounded by "#ifdef <platform>" and "#endif"
|
||||
--Various defaults
|
||||
--Filename extensions
|
||||
|
||||
Ideally, a port to a new platform should only need to modify this
|
||||
file, the makefile, os_<whatever>.c, and possibly filename.c. (In
|
||||
practice, you may also need to tweak the high-level I/O code
|
||||
in interface.c or the memory-allocation code in util.c. If you
|
||||
find yourself needing to do more than that, get in touch with me.) */
|
||||
|
||||
#undef _WIN32 /* GARGLK */
|
||||
|
||||
|
||||
/* Default to PLAIN platform */
|
||||
/* At the moment, you can replace this with LINUX, HPUX, AMIGA, */
|
||||
/* MSDOS, SUN, or NEXT; some of these may require the correct os_... */
|
||||
/* file to work */
|
||||
/* (In particular, AMIGA requires David Kinder's os_amiga.c file) */
|
||||
/* The actual platform specific defines don't start until a few */
|
||||
/* lines down, past the #includes and the definition of global */
|
||||
#ifndef PLAIN
|
||||
#define PLAIN
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* PLATFORM SPECIFIC DEFINITIONS, ETC. */
|
||||
/* See agility.doc or porting.txt for more information. */
|
||||
/* Things you can currently define: */
|
||||
/* fix_ascii: 1=translate IBM character set, 0=don't */
|
||||
/* NEED_STR_CMP: define if strcasecmp() not defined on your system */
|
||||
/* NEED_STRN_CMP: define if strncasecmp() not defined on your system */
|
||||
/* HAVE_STRDUP: define if strdup() exists on your system */
|
||||
/* REPLACE_GETFILE: define if you replace the default get_user_file(). */
|
||||
/* REPLACE_MENU if you replace agt_menu(). */
|
||||
/* REPLACE_MAIN: define if you replace the default main(). */
|
||||
/* (replacements should be defined in the relevant os_<platform>.c file) */
|
||||
/* DA1,DA2,...DA6,DSS,pTTL: file name extensions for the various AGT
|
||||
files */
|
||||
/* HAVE_SLEEP if your platform has the sleep() function */
|
||||
/* BUFF_SIZE is the maximum size of the buffer to use when reading
|
||||
in files. Regardless, it will be made no bigger than the file
|
||||
being read in and no smaller than the record size; thus setting
|
||||
it to 0 will cause the smallest buffer to always be used and
|
||||
setting this to 1MB will in practice always use a buffer the
|
||||
sizs of the file. It defaults to 32K */
|
||||
/* CBUF_SIZE is the maximum size of the buffer used for reading in
|
||||
the Master's Edition DA6 files; the size of the buffer in bytes
|
||||
is twice this value (since an individual token is two bytes long). */
|
||||
/* DESCR_BUFFSIZE is the maximum size of the description text block before
|
||||
the interpreter will read it from disk rather than storing it in
|
||||
memory during play. At the moment this only affects AGX games;
|
||||
original AGT games always use the disk. */
|
||||
/* DOHASH to use a hash table for dictionary searches; the only
|
||||
reason not to have this would be memory */
|
||||
/* HASHBITS determines the size of the hash table: (2^HASHBITS)*sizeof(word);
|
||||
the hash table must be at least as large as the dictionary.
|
||||
In practice this means HASHBITS should be at least 12;
|
||||
this is the current default. */
|
||||
/* MAXSTRUC The maximum size (in chars) which a single data structure can
|
||||
be on this platform. This defaults to 1MB (i.e. no limit for
|
||||
practical purposes). In practice I know of no game files that
|
||||
require any structures bigger than about 30K. */
|
||||
/* LOWMEM Define this if you are low on memory. At the moment this
|
||||
only saves a few K.*/
|
||||
/* PORTSTR Is the string describing this particular port.
|
||||
e.g. #define PORTSTR "OrfDOS Port by R.J. Wright" */
|
||||
/* UNIX_IO if you have Unix-like low level file I/O functions.
|
||||
(MS-DOS, for example, does). This speeds up the reading
|
||||
of the large game data files on some platforms. If this is
|
||||
defined, READFLAG, WRITEFLAG, and FILE_PERM also need to
|
||||
be defined. (Giving the flags needed for opening a file for
|
||||
reading or writing, and the file permissions to be given to newly
|
||||
created files. */
|
||||
/* OPEN_AS_TEXT Define to cause text files to be opened as text files. */
|
||||
/* PREFIX_EXT Add filename extensions at the beginning of the name,
|
||||
rather than at the end. */
|
||||
/* PATH_SEP, if defined, is a string containing all characters which
|
||||
can be used to separate the path from the filename. */
|
||||
/* pathtest(s) is a macro that should check whether the given string
|
||||
is an absolute path. If this is left undefined, then _all_
|
||||
paths will be treated as absolute. You don't need to define
|
||||
this if you are replacing filename.c. */
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
/* force16 is used purely for debugging purposes, to make sure that
|
||||
everything works okay even with 16-bit ints */
|
||||
/* #define force16 */
|
||||
|
||||
#define DOHASH
|
||||
|
||||
/*
|
||||
* The Glk port is very similar to plain ASCII, to give it the best
|
||||
* chance at success on multiple Glk platforms. The only basic change
|
||||
* is to turn off IBM character translations; Glk works in ISO 8859
|
||||
* Latin-1, which can offer slightly closer translation of the IBM
|
||||
* code page 437 characters that the simpler mappings in the core
|
||||
* AGiliTy code. The os_glk.c module handles the translations.
|
||||
*/
|
||||
#ifdef GARGLK
|
||||
#define NEED_STR_CMP /* Inherited from PLAIN. */
|
||||
#define NEED_STRN_CMP /* Inherited from PLAIN. */
|
||||
#define BUFF_SIZE 0 /* Inherited from PLAIN. */
|
||||
#define CBUF_SIZE (5000L) /* Inherited from PLAIN. */
|
||||
#define INBUFF_SIZE (1024) /* Inherited from PLAIN. */
|
||||
#define fix_ascii 0 /* os_glk.c does translations. */
|
||||
#define MAXSTRUC (1024L*1024L) /* 32Kb from PLAIN is too small for
|
||||
several games (including Soggy). */
|
||||
#define PORTSTR "Glk version" /* Identify ourselves discreetly. */
|
||||
#define REPLACE_GETFILE /* Override get_user_file. */
|
||||
#define REPLACE_MAIN /* Override main. */
|
||||
#define fnamecmp strcasecmp /* Case insensitive filename compare. */
|
||||
#undef PLAIN
|
||||
|
||||
#endif
|
||||
|
||||
/* PLAIN should always come last, giving everyone else a chance
|
||||
to #undef it. */
|
||||
#ifdef PLAIN /* This should work if nothing else does */
|
||||
#define NEED_STR_CMP
|
||||
#define NEED_STRN_CMP
|
||||
#define BUFF_SIZE 0
|
||||
#define CBUF_SIZE (5000L)
|
||||
#define INBUFF_SIZE (1024) /* Used by Magx */
|
||||
#define MAXSTRUC (32L*1024L) /* IIRC, 32K is the minimum required by
|
||||
the ANSI standard */
|
||||
#define PORTSTR "Pure ANSI C version"
|
||||
#endif
|
||||
|
||||
|
||||
/* __GNUC__ */
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* DEFAULTS FOR "PLATFORM SPECIFIC" DEFINES */
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define NEED_STR_CMP
|
||||
#define NEED_STRN_CMP
|
||||
#endif
|
||||
|
||||
#ifndef fix_ascii
|
||||
#define fix_ascii 1 /* Translate IBM character set by default */
|
||||
#endif
|
||||
|
||||
#ifndef BUFF_SIZE
|
||||
#ifdef LOWMEM
|
||||
#define BUFF_SIZE 0 /* i.e. unbuffered */
|
||||
#else
|
||||
#define BUFF_SIZE (32L*1024L) /* 32K */
|
||||
#endif
|
||||
#endif /* BUFF_SIZE */
|
||||
|
||||
#ifndef MAXSTRUC
|
||||
#define MAXSTRUC (1024L*1024L)
|
||||
#endif
|
||||
|
||||
#ifndef DESCR_BUFFSIZE
|
||||
#define DESCR_BUFFSIZE 0 /* Always load descriptions from disk */
|
||||
#endif
|
||||
|
||||
#ifndef HASHBITS
|
||||
#ifdef LOWMEM
|
||||
#define HASHBITS 12 /* 4K entries */
|
||||
#else
|
||||
#define HASHBITS 13 /* 8K entries in hash table */
|
||||
#endif
|
||||
#endif /* HASHBITS */
|
||||
|
||||
#ifndef fnamecmp /* Used to compare filenames */
|
||||
#define fnamecmp strcmp
|
||||
#endif
|
||||
|
||||
#ifndef fnamencmp /* Also used to compare filenames */
|
||||
#define fnamencmp strncmp
|
||||
#endif
|
||||
|
||||
/* If DOSFARDATA hasn't been defined, define it as the empty string. */
|
||||
#ifndef DOSFARDATA
|
||||
#define DOSFARDATA
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* FILENAME EXTENSIONS */
|
||||
/* These are the various filename extensions for the different data files.*/
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/* The following are only used by the interpreter, agtout, and agt2agx */
|
||||
#ifndef DA1
|
||||
#define DA1 ".da1" /* General info (text file) */
|
||||
#define DA2 ".da2" /* Rooms */
|
||||
#define DA3 ".da3" /* Items */
|
||||
#define DA4 ".da4" /* Creatures */
|
||||
#define DA5 ".da5" /* Commands, headers */
|
||||
#define DA6 ".da6" /* Commands, code (Master's Ed only) */
|
||||
#define DSS ".d$$" /* Description strings */
|
||||
#define pHNT ".hnt" /* Popup hint file; not used yet. */
|
||||
#define pOPT ".opt" /* Interface specification file */
|
||||
#endif
|
||||
|
||||
/* The following are only used by the Magx compiler */
|
||||
#ifndef pAGT
|
||||
#define pAGT ".agt"
|
||||
#define pDAT ".dat"
|
||||
#define pMSG ".msg"
|
||||
#define pCMD ".cmd"
|
||||
#define pSTD ".std"
|
||||
#define AGTpSTD "agt.std" /* Default error message file */
|
||||
#endif
|
||||
|
||||
/* The following are used by both the interpreter and the compiler */
|
||||
#ifndef pAGX
|
||||
#define pAGX ".agx" /* Extension for new Adventure Game eXecutable format */
|
||||
#define pTTL ".ttl" /* Title file */
|
||||
#define pINS ".ins" /* Instruction file */
|
||||
#define pVOC ".voc" /* Menu vocabulary file */
|
||||
#define pCFG ".cfg" /* Game configuration file */
|
||||
#define pEXT "." /* Separator between extension and base of filename */
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef pSAV
|
||||
#define pSAV ".sav" /* Extension for save files */
|
||||
#endif
|
||||
|
||||
#ifndef pSCR
|
||||
#define pSCR ".scr" /* Script file */
|
||||
#endif
|
||||
|
||||
#ifndef pLOG
|
||||
#define pLOG ".log" /* LOG/REPLAY file */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Finally, two potentially platform dependent type defintions,
|
||||
for binary and text files respectively. Don't change these
|
||||
unless you are also changing filename.c */
|
||||
|
||||
typedef Common::Stream *genfile;
|
||||
typedef char *file_id_type; /* i.e. the filename */
|
||||
|
||||
#define NO_FILE_ID NULL
|
||||
#define BAD_TEXTFILE NULL
|
||||
#define BAD_BINFILE NULL
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
873
engines/glk/agt/debugcmd.cpp
Normal file
873
engines/glk/agt/debugcmd.cpp
Normal file
@@ -0,0 +1,873 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/agt/agility.h"
|
||||
#include "glk/agt/interp.h"
|
||||
#include "glk/agt/exec.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
static void d_moveobj(int obj, int dest)
|
||||
/* 1=the player, -1=unknown: ask */
|
||||
{
|
||||
if (obj == -1) {
|
||||
writestr("Which object? ");
|
||||
obj = read_number();
|
||||
if (obj != 1 && !tnoun(obj) && !tcreat(obj)) {
|
||||
writeln("Invalid object");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (dest == -1) {
|
||||
writestr("To where? ");
|
||||
dest = read_number();
|
||||
if (dest != 1 && dest != 0 && !tnoun(dest) && !tcreat(dest) && !troom(dest)) {
|
||||
writeln("Invalid object");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (obj != 1)
|
||||
it_move(obj, dest);
|
||||
else {
|
||||
if (!troom(dest)) {
|
||||
writeln("Player can only be moved to a room");
|
||||
return;
|
||||
}
|
||||
goto_room(dest - first_room);
|
||||
}
|
||||
}
|
||||
|
||||
static int print_objid(int obj) {
|
||||
char buff[10];
|
||||
char *s;
|
||||
int n;
|
||||
|
||||
Common::sprintf_s(buff, "%4d: ", obj);
|
||||
writestr(buff);
|
||||
s = objname(obj);
|
||||
for (n = 0; s[n] != 0; n++)
|
||||
if (s[n] <= 8 || (uchar)s[n] == 0xFF) s[n] = ' '; /* Strip out format codes */
|
||||
writestr(s);
|
||||
n = strlen(s);
|
||||
rfree(s);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void d_listroom() {
|
||||
int i;
|
||||
|
||||
writeln(" ROOM");
|
||||
writeln(" ------");
|
||||
writeln("");
|
||||
for (i = 0; i <= maxroom - first_room; i++) {
|
||||
print_objid(i + first_room);
|
||||
writeln("");
|
||||
}
|
||||
}
|
||||
|
||||
#define SEPLENG 27 /* Width between beginning of object column and
|
||||
location column */
|
||||
|
||||
static void d_listnoun() {
|
||||
int i;
|
||||
int len;
|
||||
|
||||
writestr(" NOUN ");
|
||||
padout(SEPLENG - 6);
|
||||
writeln(" LOCATION ");
|
||||
writestr(" ------");
|
||||
padout(SEPLENG - 6);
|
||||
writeln(" ----------");
|
||||
writeln("");
|
||||
len = SEPLENG - print_objid(1);
|
||||
padout(len);
|
||||
writestr("[");
|
||||
print_objid(loc);
|
||||
writeln("]");
|
||||
|
||||
nounloop(i) {
|
||||
len = print_objid(i + first_noun);
|
||||
len = SEPLENG - len;
|
||||
if (len > 0) padout(len);
|
||||
writestr("[");
|
||||
print_objid(noun[i].location);
|
||||
writeln("]");
|
||||
}
|
||||
}
|
||||
|
||||
static void d_listcreat() {
|
||||
int i;
|
||||
int len;
|
||||
|
||||
writestr(" CREATURE ");
|
||||
padout(SEPLENG - 11);
|
||||
writeln(" LOCATION ");
|
||||
writestr(" ----------");
|
||||
padout(SEPLENG - 11);
|
||||
writeln(" ----------");
|
||||
writeln("");
|
||||
|
||||
creatloop(i) {
|
||||
len = print_objid(i + first_creat);
|
||||
len = SEPLENG - len;
|
||||
if (len > 0) padout(len);
|
||||
writestr(" [");
|
||||
print_objid(creature[i].location);
|
||||
writeln("]");
|
||||
}
|
||||
}
|
||||
|
||||
static void writetbl(const char *s, int width)
|
||||
/* This writes out s and then prints out any additional spaces needed
|
||||
to make the output string *width* wide. */
|
||||
{
|
||||
writestr(s);
|
||||
width = width - strlen(s);
|
||||
if (width > 0) padout(width);
|
||||
}
|
||||
|
||||
static void var_edit(int vtype)
|
||||
/* vtype=0 for variable, 1 for counter, 2 for flag */
|
||||
{
|
||||
long n;
|
||||
int i;
|
||||
int imax;
|
||||
char sbuff[30];
|
||||
|
||||
switch (vtype) {
|
||||
case 0:
|
||||
imax = VAR_NUM;
|
||||
break;
|
||||
case 1:
|
||||
imax = CNT_NUM;
|
||||
break;
|
||||
case 2:
|
||||
imax = FLAG_NUM;
|
||||
break;
|
||||
default:
|
||||
writeln("INTERNAL ERROR: Invalid vtype.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
agt_clrscr();
|
||||
writeln("");
|
||||
switch (vtype) {
|
||||
case 0:
|
||||
writeln("Variables");
|
||||
break;
|
||||
case 1:
|
||||
writeln("Counters (-1 means the counter is off)");
|
||||
break;
|
||||
case 2:
|
||||
writeln("Flags ( f=false [OFF] and t=true [ON] )");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
writeln("");
|
||||
for (i = 0; i <= imax; i++) {
|
||||
switch (vtype) {
|
||||
case 0:
|
||||
Common::sprintf_s(sbuff, "[Var%3d]=%4ld", i, (long)agt_var[i]);
|
||||
break;
|
||||
case 1:
|
||||
Common::sprintf_s(sbuff, "[Cnt%3d]=%4ld", i, (long)agt_counter[i]);
|
||||
break;
|
||||
case 2:
|
||||
Common::sprintf_s(sbuff, "%3d%c", i, flag[i] ? 't' : 'f');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
writetbl(sbuff, (vtype == 2) ? 5 : 20);
|
||||
}
|
||||
writeln("");
|
||||
writeln("");
|
||||
for (;;) {
|
||||
switch (vtype) {
|
||||
case 0:
|
||||
writestr("Variable to change");
|
||||
break;
|
||||
case 1:
|
||||
writestr("Counter to change");
|
||||
break;
|
||||
case 2:
|
||||
writestr("Flag to toggle");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
writestr(" (-1 to quit): ");
|
||||
i = read_number();
|
||||
if (i < 0) return;
|
||||
if (i <= imax) {
|
||||
if (vtype != 2) {
|
||||
if (vtype == 0)
|
||||
Common::sprintf_s(sbuff, "[Var%d]=%ld", i, (long)agt_var[i]);
|
||||
else Common::sprintf_s(sbuff, "[Cnt%d]=%ld (-1 means it's off)",
|
||||
i, (long)agt_counter[i]);
|
||||
writestr(sbuff);
|
||||
writestr("; new value = ");
|
||||
n = read_number();
|
||||
if (vtype == 0)
|
||||
agt_var[i] = n;
|
||||
else if (n < -1 || n > (((long)1) << 15) - 1)
|
||||
writeln("Invalid value for a counter.");
|
||||
else agt_counter[i] = n;
|
||||
} else flag[i] = !flag[i];
|
||||
break;
|
||||
} else
|
||||
writeln("Invalid index.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Routines to edit user strings */
|
||||
static void edit_str() {
|
||||
int i, j;
|
||||
char buff[10];
|
||||
char *tmpstr;
|
||||
|
||||
if (MAX_USTR == 0 || userstr == nullptr) {
|
||||
writeln("This game doesn't contain any user strings");
|
||||
return;
|
||||
}
|
||||
for (;;) {
|
||||
agt_clrscr();
|
||||
writeln("User Definable Strings");
|
||||
writeln("");
|
||||
for (i = 0; i < MAX_USTR; i++) {
|
||||
Common::sprintf_s(buff, "%2d:", i + 1);
|
||||
writestr(buff);
|
||||
writeln(userstr[i]);
|
||||
}
|
||||
writestr(" (0 to quit): ");
|
||||
i = read_number();
|
||||
if (i == 0) return;
|
||||
if (i > 0 && i <= MAX_USTR) {
|
||||
writeln("Enter new string:");
|
||||
tmpstr = agt_readline(3);
|
||||
j = strlen(tmpstr) - 1;
|
||||
if (j > 0 && tmpstr[j] == '\n') tmpstr[j] = 0;
|
||||
strncpy(userstr[i - 1], tmpstr, 80);
|
||||
} else writeln("Invalid string number");
|
||||
}
|
||||
}
|
||||
|
||||
static uchar attrcol; /* Determines which column the attribute is put in */
|
||||
static uchar attrwidth; /* Number of attribute columns */
|
||||
|
||||
static void next_col() {
|
||||
if (++attrcol == attrwidth) {
|
||||
writeln("");
|
||||
attrcol = 0;
|
||||
} else
|
||||
padout(10);
|
||||
}
|
||||
|
||||
static void writeattr(const char *attrname, rbool attrval) {
|
||||
writestr(attrname);
|
||||
padout(15 - strlen(attrname));
|
||||
if (attrval) writestr("yes");
|
||||
else writestr("no ");
|
||||
next_col();
|
||||
}
|
||||
|
||||
static void writegender(const char *gendername, uchar genderval) {
|
||||
writestr(gendername);
|
||||
padout(15 - strlen(gendername) - 3);
|
||||
switch (genderval) {
|
||||
case 2:
|
||||
writestr("Male ");
|
||||
break;
|
||||
case 1:
|
||||
writestr("Female");
|
||||
break;
|
||||
case 0:
|
||||
writestr("Thing");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
next_col();
|
||||
}
|
||||
|
||||
static void writeprop(const char *propname, int obj) {
|
||||
writestr(propname);
|
||||
writestr(" [");
|
||||
print_objid(obj);
|
||||
writeln("]");
|
||||
}
|
||||
|
||||
static int writedir(int index, int dir, int obj) {
|
||||
char sbuff[40];
|
||||
|
||||
Common::sprintf_s(sbuff, "%2d.%-2s %d", index, exitname[dir], obj);
|
||||
writestr(sbuff);
|
||||
return strlen(sbuff);
|
||||
}
|
||||
|
||||
void writenum(const char *propname, int n) {
|
||||
char sbuff[20];
|
||||
|
||||
writestr(propname);
|
||||
Common::sprintf_s(sbuff, "%4d", n);
|
||||
writeln(sbuff);
|
||||
}
|
||||
|
||||
static void writeflags(const char *flagname, int32 flags) {
|
||||
int i;
|
||||
char sbuff[5];
|
||||
|
||||
writestr(flagname);
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (flags & 1) {
|
||||
Common::sprintf_s(sbuff, "%2d ", i);
|
||||
writestr(sbuff);
|
||||
} else
|
||||
writestr(" ");
|
||||
flags >>= 1;
|
||||
if (i % 12 == 11) {
|
||||
writeln("");
|
||||
padout(strlen(flagname));
|
||||
}
|
||||
}
|
||||
writeln("");
|
||||
}
|
||||
|
||||
static void readflags(int32 *flags) {
|
||||
long n;
|
||||
|
||||
writestr("Room flag to toggle (0-31)? ");
|
||||
n = read_number();
|
||||
if (n <= 31 && n >= 0)
|
||||
*flags ^= (((long)1) << n);
|
||||
}
|
||||
|
||||
static long readval(const char *prompt, int type) {
|
||||
long val;
|
||||
|
||||
for (;;) {
|
||||
writestr(prompt);
|
||||
writestr(" ");
|
||||
val = read_number();
|
||||
if (argvalid(type, val)) return val;
|
||||
writeln("Invalid value.");
|
||||
}
|
||||
}
|
||||
|
||||
static uchar readgender() {
|
||||
char c;
|
||||
|
||||
writestr("Gender (M/F/N): ");
|
||||
for (;;) {
|
||||
c = tolower(agt_getchar());
|
||||
switch (c) {
|
||||
case 'm':
|
||||
return 2;
|
||||
case 'w':
|
||||
case 'f':
|
||||
return 1;
|
||||
case 'n':
|
||||
case 't':
|
||||
return 0;
|
||||
default: ;/* Do nothing */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void edit_objattr(int obj) {
|
||||
int i, k, kprop, n;
|
||||
long v;
|
||||
|
||||
for (;;) {
|
||||
k = 1;
|
||||
agt_clrscr();
|
||||
print_objid(obj);
|
||||
writeln("");
|
||||
if (oflag_cnt > 0) {
|
||||
writeln("ObjFlags:");
|
||||
for (i = 0; i < oflag_cnt; i++)
|
||||
if (have_objattr(0, obj, i)) {
|
||||
v = op_objflag(2, obj, i);
|
||||
rprintf("%2d. ObjProp%2d:%c %-40s\n", k++, i, (v ? '+' : '-'),
|
||||
get_objattr_str(AGT_OBJFLAG, i, v));
|
||||
}
|
||||
writeln("");
|
||||
}
|
||||
kprop = k;
|
||||
if (oprop_cnt > 0) {
|
||||
writeln("ObjProps:");
|
||||
for (i = 0; i < oprop_cnt; i++)
|
||||
if (have_objattr(1, obj, i)) {
|
||||
v = op_objprop(2, obj, i, 0);
|
||||
rprintf("%2d. ObjFlag%2d: [%3ld] %-40s\n", k++, i, v,
|
||||
get_objattr_str(AGT_OBJPROP, i, v));
|
||||
}
|
||||
writeln("");
|
||||
}
|
||||
writestr("Field to change (0 to return to main view)? ");
|
||||
n = read_number();
|
||||
if (n == 0) return;
|
||||
if (n < 1 || n >= k) continue;
|
||||
k = 0;
|
||||
if (n < kprop) { /* Attribute */
|
||||
for (i = 0; i < oflag_cnt; i++)
|
||||
if (have_objattr(0, obj, i))
|
||||
if (n == ++k) break;
|
||||
if (n == k && have_objattr(0, obj, i))
|
||||
op_objflag(3, obj, i); /* Toggle it */
|
||||
} else { /* Property */
|
||||
for (i = 0; i < oprop_cnt; i++)
|
||||
if (have_objattr(1, obj, i))
|
||||
if (n == ++k) break;
|
||||
if (n == k && have_objattr(1, obj, i))
|
||||
op_objprop(1, obj, i, readval("New value:", AGT_NUM));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void room_edit(int i) {
|
||||
int n, j;
|
||||
|
||||
for (;;) {
|
||||
agt_clrscr();
|
||||
writestr("ROOM ");
|
||||
print_objid(i + first_room);
|
||||
writeln("");
|
||||
writeln("");
|
||||
attrcol = 0;
|
||||
attrwidth = 2;
|
||||
writeattr("1.*WinGame:", room[i].win);
|
||||
writeattr("4. Seen:", room[i].seen);
|
||||
writeattr("2.*EndGame:", room[i].end);
|
||||
writeattr("5. LockedDoor:", room[i].locked_door);
|
||||
writeattr("3.*Die:", room[i].killplayer);
|
||||
writeln("");
|
||||
writeln("");
|
||||
writeprop("6.*Key =", room[i].key);
|
||||
writeprop("7. Light =", room[i].light);
|
||||
writenum("8. Points =", room[i].points);
|
||||
writeprop("9. Class = ", room[i].oclass);
|
||||
writeln("");
|
||||
writeln("EXITS:");
|
||||
for (j = 0; j < 12; j++) {
|
||||
n = writedir(j + 10, j, room[i].path[j]);
|
||||
if (j % 4 == 3) writeln("");
|
||||
else padout(15 - n);
|
||||
}
|
||||
writeprop("22. SPECIAL:", room[i].path[12]);
|
||||
writeflags("23. Room Flags:", room[i].flag_noun_bits);
|
||||
writeln("24. Object properties and attributes.");
|
||||
writeln("");
|
||||
writeln("(Fields marked with an * are not saved or restored.)");
|
||||
/* writeln(""); */
|
||||
writestr("Field to change (0 to exit)? ");
|
||||
n = read_number();
|
||||
if (n == 0) return;
|
||||
switch (n) {
|
||||
case 1:
|
||||
room[i].win = !room[i].win;
|
||||
break;
|
||||
case 2:
|
||||
room[i].end = !room[i].end;
|
||||
break;
|
||||
case 3:
|
||||
room[i].killplayer = !room[i].killplayer;
|
||||
break;
|
||||
case 4:
|
||||
room[i].seen = !room[i].seen;
|
||||
break;
|
||||
case 5:
|
||||
room[i].locked_door = !room[i].locked_door;
|
||||
break;
|
||||
case 6:
|
||||
room[i].key = readval("Key = ", AGT_ITEM | AGT_NONE);
|
||||
break;
|
||||
case 7:
|
||||
room[i].light = readval("Light = ", AGT_ITEM | AGT_NONE | AGT_SELF);
|
||||
break;
|
||||
case 8:
|
||||
room[i].points = readval("Points = ", AGT_NUM);
|
||||
break;
|
||||
case 9:
|
||||
room[i].oclass = readval("Class = ", AGT_ROOM | AGT_NONE);
|
||||
break;
|
||||
case 22:
|
||||
room[i].path[12] = readval("SPECIAL: ", AGT_NUM);
|
||||
break;
|
||||
case 23:
|
||||
readflags(&room[i].flag_noun_bits);
|
||||
break;
|
||||
case 24:
|
||||
edit_objattr(i + first_room);
|
||||
break;
|
||||
default:
|
||||
if (n >= 10 && n < 22) { /* Direction */
|
||||
room[i].path[n - 10] = readval(exitname[n - 10], AGT_NUM);
|
||||
} else writeln("Invalid field");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define tog(x) {x=!x;break;}
|
||||
|
||||
static void noun_edit(int i) {
|
||||
int n;
|
||||
|
||||
for (;;) {
|
||||
agt_clrscr();
|
||||
/* writeln("");*/
|
||||
writestr("NOUN ");
|
||||
print_objid(i + first_noun);
|
||||
/* writeln("");*/
|
||||
/* writeln("");*/
|
||||
writeprop(" Location=", noun[i].location);
|
||||
writeln("");
|
||||
attrcol = 0;
|
||||
attrwidth = 3;
|
||||
writeattr(" 1.*Pushable:", noun[i].pushable);
|
||||
writeattr(" 8.*Lockable:", noun[i].lockable);
|
||||
writeattr("15.*Drinkable:", noun[i].drinkable);
|
||||
writeattr(" 2.*Pullable:", noun[i].pullable);
|
||||
writeattr(" 9.*Light:", noun[i].light);
|
||||
writeattr("16.*Poisonous:", noun[i].poisonous);
|
||||
writeattr(" 3.*Turnable:", noun[i].turnable);
|
||||
writeattr("10.*Plural:", noun[i].plural);
|
||||
writeattr("17. Open:", noun[i].open);
|
||||
writeattr(" 4.*Playable:", noun[i].playable);
|
||||
writeattr("11. Movable:", noun[i].movable);
|
||||
writeattr("18. Locked:", noun[i].locked);
|
||||
writeattr(" 5.*Readable:", noun[i].readable);
|
||||
writeattr("12.*Shootable:", noun[i].shootable);
|
||||
writeattr("19.*Win Game:", noun[i].win);
|
||||
writeattr(" 6.*Wearable:", noun[i].wearable);
|
||||
writeattr("13. On:", noun[i].on);
|
||||
writeattr("20.*Global:", noun[i].isglobal);
|
||||
writeattr(" 7.*Closable:", noun[i].closable);
|
||||
writeattr("14.*Edible:", noun[i].edible);
|
||||
writeattr("21.*Proper:", noun[i].proper);
|
||||
|
||||
writeln("");
|
||||
writenum("22. Shots =", noun[i].num_shots);
|
||||
writenum("23. Points =", noun[i].points);
|
||||
writenum("24. Weight =", noun[i].weight);
|
||||
writenum("25. Size =", noun[i].size);
|
||||
writeprop("26.*Key =", noun[i].key);
|
||||
writeprop("27. Class =", noun[i].oclass);
|
||||
writenum("28. Flag =", noun[i].flagnum);
|
||||
writeln("");
|
||||
/* writeln(""); */
|
||||
writeln("29. Object properties and attributes.");
|
||||
writeln("");
|
||||
writeln("(Fields marked with an * are not saved or restored.)");
|
||||
writestr("Field to change (0 to exit)? ");
|
||||
n = read_number();
|
||||
if (n == 0) return;
|
||||
switch (n) {
|
||||
case 1:
|
||||
tog(noun[i].pushable); /* tog() macro includes break */
|
||||
case 2:
|
||||
tog(noun[i].pullable);
|
||||
case 3:
|
||||
tog(noun[i].turnable);
|
||||
case 4:
|
||||
tog(noun[i].playable);
|
||||
case 5:
|
||||
tog(noun[i].readable);
|
||||
case 6:
|
||||
tog(noun[i].wearable);
|
||||
case 7:
|
||||
tog(noun[i].closable);
|
||||
case 8:
|
||||
tog(noun[i].lockable);
|
||||
case 9:
|
||||
tog(noun[i].light);
|
||||
case 10:
|
||||
tog(noun[i].plural);
|
||||
case 11:
|
||||
tog(noun[i].movable);
|
||||
case 12:
|
||||
tog(noun[i].shootable);
|
||||
case 13:
|
||||
tog(noun[i].on);
|
||||
case 14:
|
||||
tog(noun[i].edible);
|
||||
case 15:
|
||||
tog(noun[i].drinkable);
|
||||
case 16:
|
||||
tog(noun[i].poisonous);
|
||||
case 17:
|
||||
tog(noun[i].open);
|
||||
case 18:
|
||||
tog(noun[i].locked);
|
||||
case 19:
|
||||
tog(noun[i].win);
|
||||
case 20:
|
||||
tog(noun[i].isglobal);
|
||||
case 21:
|
||||
tog(noun[i].proper);
|
||||
|
||||
case 22:
|
||||
noun[i].num_shots = readval("Shots =", AGT_NUM);
|
||||
break;
|
||||
case 23:
|
||||
noun[i].points = readval("Points =", AGT_NUM);
|
||||
break;
|
||||
case 24:
|
||||
noun[i].weight = readval("Weight =", AGT_NUM);
|
||||
break;
|
||||
case 25:
|
||||
noun[i].size = readval("Size =", AGT_NUM);
|
||||
break;
|
||||
case 26:
|
||||
noun[i].key = readval("Key =", AGT_ITEM | AGT_NONE);
|
||||
break;
|
||||
case 27:
|
||||
noun[i].oclass = readval("Class =", AGT_ITEM | AGT_NONE);
|
||||
break;
|
||||
case 28:
|
||||
noun[i].flagnum = readval("Flag Number=", AGT_ROOMFLAG);
|
||||
break;
|
||||
case 29:
|
||||
edit_objattr(i + first_noun);
|
||||
break;
|
||||
default:
|
||||
writeln("Invalid field");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void creat_edit(int i) {
|
||||
int n;
|
||||
|
||||
for (;;) {
|
||||
agt_clrscr();
|
||||
writestr("CREATURE ");
|
||||
print_objid(i + first_creat);
|
||||
writeln("");
|
||||
writeln("");
|
||||
writeprop("Location =", creature[i].location);
|
||||
writeln("");
|
||||
attrcol = 0;
|
||||
attrwidth = 2;
|
||||
writeattr(" 1. Hostile:", creature[i].hostile);
|
||||
writeattr(" 4. Global:", creature[i].isglobal);
|
||||
writeattr(" 2. Grp member:", creature[i].groupmemb);
|
||||
writeattr(" 5.*Proper:", creature[i].proper);
|
||||
writegender(" 3.*Gender:", creature[i].gender);
|
||||
writeln("");
|
||||
writeln("");
|
||||
writeprop(" 6.*Weapon = ", creature[i].weapon);
|
||||
writenum(" 7. Points = ", creature[i].points);
|
||||
writenum(" 8.*Attack Threshold = ", creature[i].threshold);
|
||||
writenum(" 9. Attack counter = ", creature[i].counter);
|
||||
writenum("10.*Attack Time Limit = ", creature[i].timethresh);
|
||||
writenum("11. Attack timer = ", creature[i].timecounter);
|
||||
writeprop("12. Class = ", creature[i].oclass);
|
||||
writenum("13. Flag = ", creature[i].flagnum);
|
||||
writeln("");
|
||||
writeln("14. Object properties and attributes.");
|
||||
writeln("");
|
||||
writeln("(Fields marked with an * are not saved or restored.)");
|
||||
writeln("");
|
||||
writestr("Field to change (0 to exit)? ");
|
||||
n = read_number();
|
||||
if (n == 0) return;
|
||||
switch (n) {
|
||||
case 1:
|
||||
tog(creature[i].hostile);
|
||||
case 2:
|
||||
tog(creature[i].groupmemb);
|
||||
case 3:
|
||||
tog(creature[i].isglobal);
|
||||
case 4:
|
||||
tog(creature[i].proper);
|
||||
|
||||
case 5:
|
||||
creature[i].gender = readgender();
|
||||
break;
|
||||
case 6:
|
||||
creature[i].weapon = readval("Weapon =", AGT_ITEM | AGT_NONE);
|
||||
break;
|
||||
case 7:
|
||||
creature[i].points = readval("Points =", AGT_NUM);
|
||||
break;
|
||||
case 8:
|
||||
creature[i].threshold = readval("Threshold =", AGT_NUM);
|
||||
break;
|
||||
case 9:
|
||||
creature[i].counter = readval("Attack counter =", AGT_NUM);
|
||||
break;
|
||||
case 10:
|
||||
creature[i].timethresh = readval("Time limit =", AGT_NUM);
|
||||
break;
|
||||
case 11:
|
||||
creature[i].timecounter = readval("Timer =", AGT_NUM);
|
||||
break;
|
||||
case 12:
|
||||
creature[i].oclass = readval("Class =", AGT_ITEM | AGT_NONE);
|
||||
break;
|
||||
case 13:
|
||||
noun[i].flagnum = readval("Flag Number=", AGT_ROOMFLAG);
|
||||
break;
|
||||
case 14:
|
||||
edit_objattr(i + first_creat);
|
||||
break;
|
||||
default:
|
||||
writeln("Invalid field");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef tog
|
||||
|
||||
|
||||
static void obj_edit() {
|
||||
int n;
|
||||
|
||||
for (;;) {
|
||||
writeln("");
|
||||
do {
|
||||
writestr("Enter object number (0 to exit)? ");
|
||||
n = read_number();
|
||||
if (n <= 0) return;
|
||||
} while (!troom(n) && !tnoun(n) && !tcreat(n));
|
||||
|
||||
if (troom(n)) room_edit(n - first_room);
|
||||
else if (tnoun(n)) noun_edit(n - first_noun);
|
||||
else if (tcreat(n)) creat_edit(n - first_creat);
|
||||
else writeln("[Not yet implemented]");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static const char *yesnostr[] = { "No", "Yes" };
|
||||
|
||||
static void set_debug_options() {
|
||||
char buff[80];
|
||||
int n;
|
||||
|
||||
for (;;) {
|
||||
agt_clrscr();
|
||||
writeln("DEBUGGING OPTIONS:");
|
||||
writeln("");
|
||||
Common::sprintf_s(buff, " 1. Trace metacommands: %s", yesnostr[DEBUG_AGT_CMD]);
|
||||
writeln(buff);
|
||||
Common::sprintf_s(buff, " 2. Trace ANY metacommands: %s", yesnostr[debug_any]);
|
||||
writeln(buff);
|
||||
Common::sprintf_s(buff, " 3. Trace during disambiguation: %s",
|
||||
yesnostr[debug_disambig]);
|
||||
writeln(buff);
|
||||
writeln("");
|
||||
writeln("(<2> and <3> are ignored if <1> is not set; option <1> can"
|
||||
" also be changed from the main debugging menu)");
|
||||
writeln("");
|
||||
writestr("Option to toggle (0 to exit): ");
|
||||
n = read_number();
|
||||
switch (n) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
DEBUG_AGT_CMD = !DEBUG_AGT_CMD;
|
||||
break;
|
||||
case 2:
|
||||
debug_any = !debug_any;
|
||||
break;
|
||||
case 3:
|
||||
debug_disambig = !debug_disambig;
|
||||
break;
|
||||
default:
|
||||
writeln("Not a valid option");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_debugcmd() {
|
||||
int n;
|
||||
|
||||
for (;;) {
|
||||
writeln("DEBUGGING COMMANDS");
|
||||
writeln("");
|
||||
writeln("1. Move player 8. List Rooms");
|
||||
writeln("2. Get Noun 9. List Nouns");
|
||||
writeln("3. Move object 10. List Creatures");
|
||||
writeln("4. View/Edit object 11. List/Set Flags");
|
||||
writeln("5. Toggle Trace 12. List/Set Variables");
|
||||
writeln("6. Set Debug Options 13. List/Set Counters");
|
||||
writeln("7. Edit User Strings");
|
||||
writeln("");
|
||||
writestr("Enter choice (0 to exit): ");
|
||||
n = read_number();
|
||||
switch (n) {
|
||||
case -1:
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
d_moveobj(1, -1);
|
||||
break;
|
||||
case 2:
|
||||
d_moveobj(-1, 1);
|
||||
break;
|
||||
case 3:
|
||||
d_moveobj(-1, -1);
|
||||
break;
|
||||
case 4:
|
||||
obj_edit();
|
||||
break;
|
||||
case 5:
|
||||
DEBUG_AGT_CMD = !DEBUG_AGT_CMD;
|
||||
break;
|
||||
case 6:
|
||||
set_debug_options();
|
||||
break;
|
||||
case 7:
|
||||
edit_str();
|
||||
break;
|
||||
case 8:
|
||||
d_listroom();
|
||||
break;
|
||||
case 9:
|
||||
d_listnoun();
|
||||
break;
|
||||
case 10:
|
||||
d_listcreat();
|
||||
break;
|
||||
case 11:
|
||||
var_edit(2);
|
||||
break;
|
||||
case 12:
|
||||
var_edit(0);
|
||||
break;
|
||||
case 13:
|
||||
var_edit(1);
|
||||
break;
|
||||
default:
|
||||
writeln("Not a valid option");
|
||||
}
|
||||
writeln("");
|
||||
};
|
||||
}
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
96
engines/glk/agt/detection.cpp
Normal file
96
engines/glk/agt/detection.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/agt/detection.h"
|
||||
#include "glk/agt/detection_tables.h"
|
||||
#include "glk/blorb.h"
|
||||
#include "common/file.h"
|
||||
#include "common/md5.h"
|
||||
#include "engines/game.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
void AGTMetaEngine::getSupportedGames(PlainGameList &games) {
|
||||
for (const PlainGameDescriptor *pd = AGT_GAME_LIST; pd->gameId; ++pd)
|
||||
games.push_back(*pd);
|
||||
}
|
||||
|
||||
const GlkDetectionEntry* AGTMetaEngine::getDetectionEntries() {
|
||||
return AGT_GAMES;
|
||||
}
|
||||
|
||||
GameDescriptor AGTMetaEngine::findGame(const char *gameId) {
|
||||
for (const PlainGameDescriptor *pd = AGT_GAME_LIST; pd->gameId; ++pd) {
|
||||
if (!strcmp(gameId, pd->gameId))
|
||||
return *pd;
|
||||
}
|
||||
|
||||
return GameDescriptor::empty();
|
||||
}
|
||||
|
||||
bool AGTMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) {
|
||||
// Loop through the files of the folder
|
||||
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
|
||||
// Check for a recognised filename
|
||||
if (file->isDirectory())
|
||||
continue;
|
||||
|
||||
Common::String filename = file->getName();
|
||||
if (!filename.hasSuffixIgnoreCase(".d$$") && !filename.hasSuffixIgnoreCase(".agx"))
|
||||
continue;
|
||||
|
||||
Common::File gameFile;
|
||||
if (!gameFile.open(*file))
|
||||
continue;
|
||||
Common::String md5 = Common::computeStreamMD5AsString(gameFile, 5000);
|
||||
size_t filesize = (size_t)gameFile.size();
|
||||
|
||||
// Scan through the AGT game list for a match
|
||||
const GlkDetectionEntry *p = AGT_GAMES;
|
||||
while (p->_md5 && ((p->_filesize != filesize) || (md5 != p->_md5)))
|
||||
++p;
|
||||
|
||||
if (!p->_gameId) {
|
||||
const PlainGameDescriptor &desc = AGT_GAME_LIST[0];
|
||||
gameList.push_back(GlkDetectedGame(desc.gameId, desc.description, filename, md5, filesize));
|
||||
} else {
|
||||
// Found a match
|
||||
PlainGameDescriptor gameDesc = findGame(p->_gameId);
|
||||
DetectedGame gd("glk", p->_gameId, gameDesc.description, p->_language, Common::kPlatformUnknown, p->_extra);
|
||||
gd.addExtraEntry("filename", filename);
|
||||
gameList.push_back(gd);
|
||||
}
|
||||
}
|
||||
|
||||
return !gameList.empty();
|
||||
}
|
||||
|
||||
void AGTMetaEngine::detectClashes(Common::StringMap &map) {
|
||||
for (const PlainGameDescriptor *pd = AGT_GAME_LIST; pd->gameId; ++pd) {
|
||||
if (map.contains(pd->gameId))
|
||||
error("Duplicate game Id found - %s", pd->gameId);
|
||||
map[pd->gameId] = "";
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
64
engines/glk/agt/detection.h
Normal file
64
engines/glk/agt/detection.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_AGT_DETECTION
|
||||
#define GLK_AGT_DETECTION
|
||||
|
||||
#include "common/fs.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "engines/game.h"
|
||||
#include "glk/detection.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
class AGTMetaEngine {
|
||||
public:
|
||||
/**
|
||||
* Get a list of supported games
|
||||
*/
|
||||
static void getSupportedGames(PlainGameList &games);
|
||||
|
||||
/**
|
||||
* Get the detection entries
|
||||
*/
|
||||
static const GlkDetectionEntry* getDetectionEntries();
|
||||
|
||||
/**
|
||||
* Returns a game description for the given game Id, if it's supported
|
||||
*/
|
||||
static GameDescriptor findGame(const char *gameId);
|
||||
|
||||
/**
|
||||
* Detect supported games
|
||||
*/
|
||||
static bool detectGames(const Common::FSList &fslist, DetectedGames &gameList);
|
||||
|
||||
/**
|
||||
* Check for game Id clashes with other sub-engines
|
||||
*/
|
||||
static void detectClashes(Common::StringMap &map);
|
||||
};
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
292
engines/glk/agt/detection_tables.h
Normal file
292
engines/glk/agt/detection_tables.h
Normal file
@@ -0,0 +1,292 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/game.h"
|
||||
#include "common/language.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
const PlainGameDescriptor AGT_GAME_LIST[] = {
|
||||
{ "agt", "AGT IF Game" },
|
||||
|
||||
{ "abloodylife", "A Bloody Life" },
|
||||
{ "alandria", "The Search for Princess Alandria" },
|
||||
{ "alchemistcastle", "Castle of the Alchemists" },
|
||||
{ "advalice", "The Adventures of Alice Who Went Through the Looking-Glass" },
|
||||
{ "apprenticetesting", "Apprentice - The Testing of a Magical Novice" },
|
||||
{ "sirarthur", "Sir Arthur" },
|
||||
{ "cercla", "Cercla" },
|
||||
{ "cardigan1", "Space Aliens Laughed at My Cardigan" },
|
||||
{ "cardigan2", "Still Laughing at my Cardigan" },
|
||||
{ "curse", "Curse of ManorLand" },
|
||||
{ "sanityclause", "Sanity Clause or, Why Santa Didn't Make It to YOUR House that Year" },
|
||||
{ "cliffdiver1", "Cliff Diver: Investigator for Hire - Case 1" },
|
||||
{ "cliffdiver2", "Cliff Diver: Investigator for Hire - Case 2" },
|
||||
{ "cosmoserve", "CosmoServe" },
|
||||
{ "crusade", "Crusade" },
|
||||
{ "agtdetective", "Detective" },
|
||||
{ "dragonschocolate", "Dragons in Chocolate Land" },
|
||||
{ "disenchanted", "Disenchanted" },
|
||||
{ "ducksoup", "Duck Soup" },
|
||||
{ "cavesofdyanty", "Caves of Dyanty" },
|
||||
{ "destinationearth", "Destination: Earth" },
|
||||
{ "dudleydilemma", "A Dudley Dilemma" },
|
||||
{ "80days", "Around the World in Eighty Days" },
|
||||
{ "easteregghunt", "Heather's Easter Egg Hunt" },
|
||||
{ "electrabot", "Electrabot" },
|
||||
{ "elf20", "The Elf's Christmas Adventure" },
|
||||
{ "elfquest", "Elf Quest" },
|
||||
{ "eliescape", "Escape from the ELI" },
|
||||
{ "emailbox", "E-MAILBOX" },
|
||||
{ "escapeprisonisland", "Escape from Prison Island" },
|
||||
{ "agtfable", "A Fable" },
|
||||
{ "firststupidgame", "My First Stupid Game" },
|
||||
{ "ccfirstadv", "Colossal Cave - The First Adventure" },
|
||||
{ "ggollek", "Ggollek I : The Dissolution" },
|
||||
{ "ghosttown_rm", "Ghost Town (by Robert Masenten)" },
|
||||
{ "giganticsecrets", "Secrets of the Gigantic" },
|
||||
{ "newenglandgothic", "New England Gothic" },
|
||||
{ "grailmisadventure", "The Misadventure of the Holy Grail" },
|
||||
{ "hardestadv", "The World's Hardest Adventure" },
|
||||
{ "helvera", "Helvera, Mistress of the Park" },
|
||||
{ "highe", "Highe, the Adventures of Elizabeth(\"El\") Highe" },
|
||||
{ "sirramichobbs", "Sir Ramic Hobbs and the High Level Gorilla" },
|
||||
{ "holmescasebook", "The Casebook of Sherlock Holmes" },
|
||||
{ "hotelnotell", "Hotel Notell" },
|
||||
{ "house2house", "House 2 House" },
|
||||
{ "agthugecave", "Adventure in Humongous Cave" },
|
||||
{ "hurryhurry", "Hurry!Hurry!Hurry!!" },
|
||||
{ "jackofhartz", "Jack of Hartz" },
|
||||
{ "jubileeroad", "Jubilee Road" },
|
||||
{ "killjustin", "Kill Justin" },
|
||||
{ "klaustrophobia1", "Klaustrophobia - Part I" },
|
||||
{ "klaustrophobia2", "Klaustrophobia - Part II" },
|
||||
{ "klaustrophobia3", "Klaustrophobia - Part III" },
|
||||
{ "klingonrpg", "In the Year 2366, Klingon Role Playing Game" },
|
||||
{ "deadlylabyrinth", "The Deadly Labyrinth" },
|
||||
{ "library", "Library - Library of Guilford College" },
|
||||
{ "lostgold", "Lost Gold" },
|
||||
{ "lostinspace", "Lost in Space : Dr.Smith Goes Home" },
|
||||
{ "agtlottery", "Lottery" },
|
||||
{ "loststonemansion", "Lost Stone Mansion" },
|
||||
{ "agtpyramids", "The Pyramids of Mars" },
|
||||
{ "mdthief", "The Multi-Dimensional Thief" },
|
||||
{ "agtmhpquest", "Quest for the Magic Healing Plant" },
|
||||
{ "mopandmurder", "Mop and Murder" },
|
||||
{ "agtmst3k1", "Detective, An Interactive MiSTing (Mystery Science Theater 3000)" },
|
||||
{ "agtmst3k2", "Mystery Science Theater 3000, Adventure 102" },
|
||||
{ "spacemule", "Space Mule" },
|
||||
{ "myopia", "Myopia" },
|
||||
{ "nmr1", "Adventures in NMR" },
|
||||
{ "nmr2", "Adventures in NMR II : The Adventure Continues" },
|
||||
{ "oceana", "Oceana" },
|
||||
{ "agtodieus", "Odieus's Quest for the Magic Flingshot" },
|
||||
{ "oklib", "Oklib's Revenge" },
|
||||
{ "ovanpelt", "Orientation to Van Pelt Library of the University of Pennsylvania" },
|
||||
{ "peterpatzer", "The Adventures of Peter Patzer" },
|
||||
{ "blackpearl", "Quest for the Black Pearl" },
|
||||
{ "battleofphilip", "The Battle of Philip against the Forces of Creation" },
|
||||
{ "flightintofantasy", "The Pilot or A Flight into Fantasy" },
|
||||
{ "pork1", "PORK I : The Great Underground Sewer System" },
|
||||
{ "pork2", "PORK II, The Gizzard of Showbiz" },
|
||||
{ "starportal", "The Star Portal" },
|
||||
{ "pastoralpitfalls", "Pastoral Pitfalls" },
|
||||
{ "personalizedsample", "Personalized Adventure Game Sample" },
|
||||
{ "lostproperty", "Lost Property" },
|
||||
{ "gameofrecovery", "The Game of Recovery" },
|
||||
{ "rerunsagain", "Reruns Again version" },
|
||||
{ "derring", "Der Ring des Nibelungen" },
|
||||
{ "sherwoodadv", "Adventures in Sherwood" },
|
||||
{ "shapeshifteradv", "Shape Shifter Adventure!" },
|
||||
{ "sirguygallant", "Sir Guy Gallant and the Deadly Warning" },
|
||||
{ "shadesofgray", "Shades of Gray" },
|
||||
{ "sonofstagefright", "Son of Stagefright" },
|
||||
{ "spatent", "The Spatent Obstruction" },
|
||||
{ "squynchia", "The Squynchia Adventure" },
|
||||
{ "agtstiffy", "The Incredible Erotic Adventures of Stiffy Makane!" },
|
||||
{ "storms1", "Storms I" },
|
||||
{ "susan", "Susan (A Lustful Game)" },
|
||||
{ "tamoret", "Tamoret" },
|
||||
{ "tarabithia", "Escape from Tarabithia" },
|
||||
{ "tarksimmons", "The Adventure of Tark Simmons" },
|
||||
{ "tarotia", "The Books of Tarotia : Book 1" },
|
||||
{ "tempest", "The Tempest" },
|
||||
{ "thegame", "Whatever We Decide To Call This Game" },
|
||||
{ "therift", "The Rift" },
|
||||
{ "tja", "The Jeweled Arena" },
|
||||
{ "toho", "Toho Academy" },
|
||||
{ "tombpharaohs", "The Tomb of the Ancient Pharaohs" },
|
||||
{ "tossedintospace", "Tossed into Space : Dr.Schmidt Goes Home" },
|
||||
{ "timesquared", "TimeSquared" },
|
||||
{ "folkestone", "Murder at the Folkestone Inn" },
|
||||
{ "void", "VOID:CORPORATION" },
|
||||
{ "wanderer1", "Black Wanderer 1 - The Darkest Road" },
|
||||
{ "wanderer2", "Black Wanderer 2 - The Unborn One" },
|
||||
{ "wanderer3", "Black Wanderer 3 - Twas a Time of Dread" },
|
||||
{ "weekendsurvival", "Weekend Survival" },
|
||||
{ "witchfinder", "Witchfinder" },
|
||||
{ "agtwizardscastle", "The Wizard's Castle" },
|
||||
{ "hobbswok", "Sir Ramic Hobbs and the Oriental Wok" },
|
||||
{ "wraithblaster", "Wraith Blaster" },
|
||||
{ "journeyintoxanth", "A Journey into Xanth" },
|
||||
{ "zanfar", "Zanfar" },
|
||||
|
||||
// Dutch games
|
||||
{ "querido", "Querido" },
|
||||
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const GlkDetectionEntry AGT_GAMES[] = {
|
||||
DT_ENTRY0("abloodylife", "c492e0ae0647d3a4835012ca864b99d5", 157221),
|
||||
DT_ENTRY0("alandria", "0dcaff32c55dd2c1898da7893500de34", 53946),
|
||||
DT_ENTRY0("alchemistcastle", "7822dfaf1ae31b3e508e7b0a267d054b", 192051),
|
||||
DT_ENTRY0("advalice", "0aaafb897b46baa28023bbbaf4091fd8", 23004),
|
||||
DT_ENTRY0("apprenticetesting", "4e4244649dc1cd39546f3d10dc85acb5", 131868),
|
||||
DT_ENTRY0("sirarthur", "46956e2d28f6b926fc6831d60f891ffc", 120204),
|
||||
DT_ENTRY0("cardigan1", "301509b196fd27c87d5d176f895b94ea", 103356),
|
||||
DT_ENTRY0("cardigan2", "f17a9d5401cb5cb1be4cb2719d0c9d34", 97767),
|
||||
DT_ENTRY0("cercla", "a56219015b70f507d9a1f74e0a92db1f", 136080),
|
||||
DT_ENTRY0("curse", "b09a74de6081e4d56e0348c9951623e9", 79139),
|
||||
DT_ENTRY0("sanityclause", "a7ea1c9ae6200511af71dfcebb5d55ff", 246159),
|
||||
DT_ENTRY0("cliffdiver1", "14ce6a122a061f2b361e725fe2c0c0e4", 120042),
|
||||
DT_ENTRY0("cliffdiver2", "9cc68e22a0ba03fe13bd4bfb413e08df", 155682),
|
||||
DT_ENTRY1("cosmoserve", "Final", "fce21feb3a6dfda1298d3eb3b46ef0b2", 377460),
|
||||
DT_ENTRY0("cosmoserve", "e677a308c446af4e076a26ef0ca235ad", 365229),
|
||||
DT_ENTRY0("crusade", "d7df6bc394d225ab023e4f099d982156", 50463),
|
||||
DT_ENTRY0("agtdetective", "b17f780a90fa4e0e30e5bbf590f78cd5", 17901),
|
||||
DT_ENTRY0("dragonschocolate", "6cb0714d337ed45ae03e6a54ed60fdc4", 143208),
|
||||
DT_ENTRY0("disenchanted", "7003a85672bbfa067dc6a28a295a1ad1", 99630),
|
||||
DT_ENTRY0("ducksoup", "e3c609c2a78e89b03c8cdefa19a50293", 83187),
|
||||
DT_ENTRY1("dudleydilemma", "1.2", "2ff4de040b7cee9592bc8dc2e020d937", 111294),
|
||||
DT_ENTRY1("dudleydilemma", "3.0", "4cdea9d3acc19f9a02072517e4bc463d", 190188),
|
||||
DT_ENTRY0("cavesofdyanty", "267e8a2812d58e140be8582914d9cefb", 40662),
|
||||
DT_ENTRY0("destinationearth", "d00cfa53e2b3315f0ee6813c064be74f", 12474),
|
||||
DT_ENTRY0("80days", "0086c0151760c59aa4d9e8ca055de84d", 30294),
|
||||
DT_ENTRY0("easteregghunt", "6ef9fb84ec755b88f1f7c2cc3c47db2e", 55647),
|
||||
DT_ENTRY0("electrabot", "1c7096e4a9a0579526e9b5084aa27701", 8748),
|
||||
DT_ENTRY0("elf20", "0fa1e888a452fec59bb4a5a6ffa43d78", 101088),
|
||||
DT_ENTRY0("elfquest", "5419ab5d7a19037a5971c7e2de59cee4", 16929),
|
||||
DT_ENTRY0("eliescape", "8d604abcccccbc0064b7488497f6242d", 72414),
|
||||
DT_ENTRY0("emailbox", "f90b34f0f2d7dfb3c7f29fbae9897671", 55908),
|
||||
DT_ENTRY0("escapeprisonisland", "8f6cf9b1f46e968b353bd00a48c2bd6b", 48762),
|
||||
DT_ENTRY0("agtfable", "9acb005ddd793da7898eda2bbc79a9d3", 15147),
|
||||
DT_ENTRY0("ccfirstadv", "8a8ff26cd6a396c193d865fa6e37594d", 83754),
|
||||
DT_ENTRY0("firststupidgame", "859933f151a301f64f88a8101853f432", 21222),
|
||||
DT_ENTRY0("ggollek", "e02fa5e1ddff57e89231481574218834", 75573),
|
||||
DT_ENTRY0("ghosttown_rm", "33aa534de04a978c50f8a038a6bec3e7", 35235),
|
||||
DT_ENTRY0("giganticsecrets", "66d6b6b5bf43149a8ad5578c45ad4731", 21627),
|
||||
DT_ENTRY0("newenglandgothic", "10898900c3b872282a4298b32e851dfc", 104895),
|
||||
DT_ENTRY0("grailmisadventure", "f7b0447cc01d1f4629e734952deccf98", 107487),
|
||||
DT_ENTRY0("hardestadv", "326aaac9509503829e2b350b867c4ca5", 115263),
|
||||
DT_ENTRY0("helvera", "aa1ba7a1f1726a90eec90b0eb998cce8", 104642),
|
||||
DT_ENTRY0("highe", "8c08f8e0e215d1293398b0d652578baf", 15471),
|
||||
DT_ENTRY0("sirramichobbs", "ba008ad6016d8302dd4311dd20ccb4e0", 132597),
|
||||
DT_ENTRY0("holmescasebook", "391e0bd51cbf8bc4cfffe751a1a659b2", 256446),
|
||||
DT_ENTRY0("hotelnotell", "0c54347ebbcfe32bbf143a1574cdb445", 111132),
|
||||
DT_ENTRY0("house2house", "9e5ee1005108afc247063e5f770ab1cc", 78246),
|
||||
DT_ENTRY0("agthugecave", "0364693bb31fb2e9a45927f9e542b1fa", 260415),
|
||||
DT_ENTRY0("hurryhurry", "040ca0ed40cb4732b66c2ab9b68bca97", 165564),
|
||||
DT_ENTRY0("jackofhartz", "74d754d8ce9bb7dca6f70b60c72ee27d", 97038),
|
||||
DT_ENTRY0("klingonrpg", "93811c560f0c78f470f65dbe62834aa1", 15066),
|
||||
DT_ENTRY0("deadlylabyrinth", "3a5d3ad2f80fb8c02baf5eb9894eb9b6", 113643),
|
||||
DT_ENTRY0("library", "f23d106273f6e5fdb50f65d2acd4e4fc", 133407),
|
||||
DT_ENTRY0("lostgold", "ff08d607b3a1a787b5d9e369264ae7f8", 67959),
|
||||
DT_ENTRY0("lostinspace", "322c226f26768b6962c2b3b147450410", 49410),
|
||||
DT_ENTRY0("agtlottery", "7c0890c420d6585e4629f1cc228bf259", 24948),
|
||||
DT_ENTRY0("loststonemansion", "f0ef6d965533e67b29acb130dd0f1213", 39933),
|
||||
DT_ENTRY0("jubileeroad", "f24fef5bc936c22fbd84c0929d727cbf", 105543),
|
||||
DT_ENTRY0("killjustin", "94d50b925733e70cf39079a8816b199c", 65043),
|
||||
DT_ENTRY0("klaustrophobia1", "cbcc82df28e67d89399139e5f234d8fc", 242838),
|
||||
DT_ENTRY0("klaustrophobia2", "b535015af4fece71c9f120730cb453dc", 292329),
|
||||
DT_ENTRY0("klaustrophobia3", "47aad0cb89ebe10e54172db55124b8d1", 366039),
|
||||
DT_ENTRY0("mdthief", "e62d36630c8a301a5da4192dfd28d650", 243729),
|
||||
DT_ENTRY0("agtpyramids", "cb2aa53dea87209fee2e300cd5396e4a", 126522),
|
||||
DT_ENTRY0("mopandmurder", "23c4a7ee63dbfb78871b7040a011cd89", 86913),
|
||||
DT_ENTRY0("agtmhpquest", "5d657aac27f1dc150d74c50251584af0", 29646),
|
||||
DT_ENTRY0("agtmst3k1", "53552013cadf6b62a5c8dcbb7f2af4a8", 127737),
|
||||
DT_ENTRY0("agtmst3k2", "973cf89bf1cea65ebd8df72c6d01354d", 107001),
|
||||
DT_ENTRY0("spacemule", "96cc0630552bc6a343e022777b40d9fd", 79056),
|
||||
DT_ENTRY0("myopia", "b3f3d0ae4fe3bf1181fa437c69b90016", 69859),
|
||||
DT_ENTRY0("nmr1", "c1758cd84fceade19866007f8d7c397f", 49734),
|
||||
DT_ENTRY0("nmr2", "979ffa08dc3b102b59f6893e4a4dede9", 55485),
|
||||
DT_ENTRY0("oceana", "63a163d87abf793a5e5c2f98f0d4c469", 178200),
|
||||
DT_ENTRY0("agtodieus", "aef479600d4fb82f8eedbeda855a9706", 28512),
|
||||
DT_ENTRY0("oklib", "d833679f11041ab1155b5207aabfc873", 166374),
|
||||
DT_ENTRY0("ovanpelt", "60a49ce4b7f99968cf92ccef5ad403f7", 53298),
|
||||
DT_ENTRY0("peterpatzer", "6a1be7e416f66c54b22e1305165fd7ee", 62842),
|
||||
DT_ENTRY0("blackpearl", "12419db6d6088e66394ecf5f28baa68d", 80109),
|
||||
DT_ENTRY0("battleofphilip", "8bbfd3d06b9eb4df0565e158e41312d8", 97443),
|
||||
DT_ENTRY0("flightintofantasy", "063f4f434b64c25f2ca816a564edbe35", 100521),
|
||||
DT_ENTRY0("pork1", "389deffc77cc58cce1ad8c0c57a5cfa8", 105948),
|
||||
DT_ENTRY0("pork2", "13911c59cbe70ae877c87aa0ded89e47", 28269),
|
||||
DT_ENTRY0("starportal", "0bf0f86fdeea607083c22a5cb41c6885", 172935),
|
||||
DT_ENTRY0("pastoralpitfalls", "c35d440286c6bf67cd6ee1e5947c3483", 206469),
|
||||
DT_ENTRY0("personalizedsample", "c590a3c5116ee2fa786e8f511ef85c8e", 69174),
|
||||
DT_ENTRY0("lostproperty", "8acf3d6994a3b39911827d5040e8873a", 30375),
|
||||
DT_ENTRY0("gameofrecovery", "b497bb0e1e93023a892f0fa54d78a1c0", 108459),
|
||||
DT_ENTRY0("rerunsagain", "d263341c871a2f52e0052c313bf3e525", 81648),
|
||||
DT_ENTRY0("derring", "5553e1a6966525da7ab2d874090d3758", 52893),
|
||||
DT_ENTRY0("sherwoodadv", "270be7ce551c615d4c34bc64acd4c190", 313551),
|
||||
DT_ENTRY0("shapeshifteradv", "8a45a92074747edf8882ea2eaf6cfa54", 137862),
|
||||
DT_ENTRY0("sirguygallant", "c4376d121b26bc691b6a43b9f77eb22a", 125698),
|
||||
DT_ENTRY1("shadesofgray", "Final", "e93ed21cdafc1b998ee2ccab557f0649", 433350),
|
||||
DT_ENTRY0("shadesofgray", "677753739047deb5ccf72f1b6555c677", 431568),
|
||||
DT_ENTRY0("sonofstagefright", "9527fa27e910470deac8ffbcb29e2427", 116640),
|
||||
DT_ENTRY0("spatent", "acc4c60cbb9d0239ab9b1900b239771a", 85455),
|
||||
DT_ENTRY0("squynchia", "e9e5c99ee87f3b38a9ea8e7fdd1ed79f", 81000),
|
||||
DT_ENTRY0("agtstiffy", "a7f1902ab7aa9972ca46d5b36d06d2b1", 32805),
|
||||
DT_ENTRY0("storms1", "8567c2db37c80f015a950ef80d299a0a", 111942),
|
||||
DT_ENTRY0("susan", "cb71705848aabcac90e7ea9e911ceee9", 15633),
|
||||
DT_ENTRY0("tamoret", "3de37497ed763a58093e556a963ca14e", 156816),
|
||||
DT_ENTRY0("tarabithia", "6734a6889d825dae528d2a7efaf6dee2", 83430),
|
||||
DT_ENTRY0("tarksimmons", "cf6945fc43e8a3062a27fc39e01c3d6e", 116397),
|
||||
DT_ENTRY0("tarotia", "fbeac90159dc88e82240b4201b6231d5", 61479),
|
||||
DT_ENTRY0("tempest", "114b5224e7bb8def06a87c3910d7c4f3", 52650),
|
||||
DT_ENTRY0("thegame", "af6e39aadf8dced6f29d03650125a6d6", 139968),
|
||||
DT_ENTRY0("therift", "1c30da9b9a55d691226c45b8b53c11c3", 41877),
|
||||
DT_ENTRY0("tja", "6699e867df8263dd7858d2f6fb84acde", 517185),
|
||||
DT_ENTRY0("toho", "58a6fdf89b29966774beaca80f505fff", 228744),
|
||||
DT_ENTRY0("tombpharaohs", "2d10501417f28ee1dc5be8479f6e88a3", 46251),
|
||||
DT_ENTRY0("tossedintospace", "515f06782c5b11108a719a20e182166c", 49491),
|
||||
DT_ENTRY0("timesquared", "55e36771d5e1fe184cce8f5be666ff9f", 105300),
|
||||
DT_ENTRY0("folkestone", "7e949a7376b0a64cee0d9412b0203611", 64557),
|
||||
DT_ENTRY0("wanderer1", "e1d707c9deaf02a4b28c9041a4009cb6", 53946),
|
||||
DT_ENTRY0("wanderer2", "89dd16629022c75f3ffc171a6b126da6", 46980),
|
||||
DT_ENTRY0("wanderer3", "839ab34bce5c82ec6194675f0186b15b", 45765),
|
||||
DT_ENTRY0("weekendsurvival", "e770c0e75b7257eae9d4677340beca10", 91044),
|
||||
DT_ENTRY0("witchfinder", "9acecd1803d2e99282970db1ef6ff344", 186300),
|
||||
DT_ENTRY0("agtwizardscastle", "3adecad94b61babdadfbe20242e86b24", 18792),
|
||||
DT_ENTRY0("hobbswok", "3178e271e8259a889df99545d6c65362", 198369),
|
||||
DT_ENTRY0("wraithblaster", "392f507d42c006a30c55a20ec9e75f44", 194643),
|
||||
DT_ENTRY0("void", "b6818cc6396e1357c3c551bc338c653d", 53784),
|
||||
DT_ENTRY0("journeyintoxanth", "2b073d48a8a01f91d7bca5db482e3ecd", 147177),
|
||||
DT_ENTRY0("zanfar", "5fc6914fe02c0235f8a5343db8b6359e", 83106),
|
||||
|
||||
// Dutch games
|
||||
DT_ENTRYL0("querido", Common::NL_NLD, "e52fe3a44d7b511bb362ce08a48435ef", 104166),
|
||||
|
||||
DT_END_MARKER
|
||||
};
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
316
engines/glk/agt/disassemble.cpp
Normal file
316
engines/glk/agt/disassemble.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/agt/agility.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
void dbgprintf(const char *fmt, ...) {
|
||||
va_list vp;
|
||||
char buff[300];
|
||||
|
||||
va_start(vp, fmt);
|
||||
Common::vsprintf_s(buff, fmt, vp);
|
||||
va_end(vp);
|
||||
|
||||
debugout(buff);
|
||||
}
|
||||
|
||||
|
||||
static void print_msg(descr_ptr dptr) {
|
||||
int j;
|
||||
descr_line *txt;
|
||||
|
||||
txt = read_descr(dptr.start, dptr.size);
|
||||
if (txt != nullptr) {
|
||||
for (j = 0; txt[j] != nullptr; j++) {
|
||||
dbgprintf("\n");
|
||||
debugout(txt[j]);
|
||||
}
|
||||
}
|
||||
free_descr(txt);
|
||||
}
|
||||
|
||||
|
||||
static char *getname(int inum)
|
||||
/* Name should be 20 chars or less */
|
||||
{
|
||||
if (inum == 0) return rstrdup("* 0 *");
|
||||
return objname(inum);
|
||||
}
|
||||
|
||||
|
||||
extern integer dobj, iobj, actor;
|
||||
|
||||
void print_special_obj(int i)
|
||||
/* This is called by the disassembler in agtdbg.c */
|
||||
/* i=0 NOUN, 1 OBJECT, 2 NAME */
|
||||
{
|
||||
int dval;
|
||||
char *s;
|
||||
switch (i) {
|
||||
case 0:
|
||||
dval = dobj;
|
||||
dbgprintf("NOUN");
|
||||
break;
|
||||
case 1:
|
||||
dval = iobj;
|
||||
dbgprintf("OBJECT");
|
||||
break;
|
||||
case 2:
|
||||
dval = actor;
|
||||
dbgprintf("NAME");
|
||||
break;
|
||||
default:
|
||||
dval = 0; /* Silence compiler warnings. */
|
||||
fatal("INTERNAL ERROR: Invalid *dval* in print_special_obj.");
|
||||
}
|
||||
if (dbgflagptr == nullptr)
|
||||
/* This determines whether we are linked with agtout or agil */
|
||||
return;
|
||||
s = getname(dval);
|
||||
dbgprintf("(%d:%s)", dval, s);
|
||||
rfree(s);
|
||||
}
|
||||
|
||||
#define printval(str,index,ptr) {dbgprintf("[%s%d",str,index);\
|
||||
if (ptr==NULL) dbgprintf("]");\
|
||||
else dbgprintf("=%ld]",(long)ptr[index]);}
|
||||
|
||||
int argout(int dtype, int dval, int optype) {
|
||||
char *s;
|
||||
|
||||
if (dtype & AGT_VAR) dtype = AGT_VAR;
|
||||
|
||||
if ((optype & 3) == 1) /* variable */
|
||||
dtype = AGT_VAR;
|
||||
if (optype & 2) { /* NOUN or OBJECT */
|
||||
if (dtype >= 64 && dtype != AGT_NUM)
|
||||
dbgprintf("ILL:");
|
||||
if (optype == 2)
|
||||
print_special_obj(0); /* NOUN */
|
||||
else
|
||||
print_special_obj(1); /* OBJECT */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!interp_arg)
|
||||
dbgprintf("%d", dval);
|
||||
else {
|
||||
if (dtype < 64) {
|
||||
if (dval == -1)
|
||||
print_special_obj(2); /* NAME */
|
||||
else {
|
||||
s = getname(dval);
|
||||
if (dtype & (AGT_ITEM | AGT_CREAT | AGT_SELF | AGT_WORN))
|
||||
dbgprintf("<%d:%s>", dval, s);
|
||||
else
|
||||
dbgprintf("{%d:%s}", dval, s);
|
||||
rfree(s);
|
||||
}
|
||||
} else if ((dtype & AGT_VAR) != 0) {
|
||||
if (dval == -1)
|
||||
print_tos();
|
||||
else
|
||||
printval("Var", dval, dbgvarptr);
|
||||
} else switch (dtype) {
|
||||
case AGT_TIME:
|
||||
dbgprintf("%2d:%2d", dval / 100, dval % 100);
|
||||
break;
|
||||
case AGT_NUM: /* Numeric */
|
||||
dbgprintf("%d", dval);
|
||||
break;
|
||||
case AGT_FLAG: /* Flag */
|
||||
printval("Flg", dval, dbgflagptr);
|
||||
break;
|
||||
case AGT_ROOMFLAG: /* Roomflag */
|
||||
dbgprintf("RoomFlag%d", dval);
|
||||
break;
|
||||
case AGT_QUEST: /* Question */
|
||||
if (dval <= MaxQuestion && dval >= 1 && question != nullptr) {
|
||||
dbgprintf("\nQ%d:%s\n", dval, question[dval - 1]);
|
||||
dbgprintf("[A:%s]", answer[dval - 1]);
|
||||
} else if (quest_ptr != nullptr) {
|
||||
dbgprintf("\nQ%d: ", dval);
|
||||
print_msg(quest_ptr[dval - 1]);
|
||||
dbgprintf("[A:");
|
||||
print_msg(ans_ptr[dval - 1]);
|
||||
}
|
||||
break;
|
||||
case AGT_MSG: /* Message */
|
||||
if (dval > last_message || dval < 1 || msg_ptr == nullptr)
|
||||
dbgprintf("ILLEGAL MESSAGE");
|
||||
else {
|
||||
dbgprintf("(Msg%d)", dval);
|
||||
if (!dbg_nomsg)
|
||||
print_msg(msg_ptr[dval - 1]);
|
||||
}
|
||||
break;
|
||||
case AGT_ERR: /* Message */
|
||||
if (dval > NUM_ERR || dval < 1 || err_ptr == nullptr)
|
||||
dbgprintf("ILLEGAL MESSAGE");
|
||||
else {
|
||||
dbgprintf("(Std%d)", dval);
|
||||
if (!dbg_nomsg)
|
||||
print_msg(err_ptr[dval - 1]);
|
||||
}
|
||||
break;
|
||||
case AGT_STR: /* String */
|
||||
if (dval - 1 >= MAX_USTR || userstr == nullptr)
|
||||
dbgprintf("ILLEGAL STRING");
|
||||
else
|
||||
dbgprintf("\nStr%d:%s", dval, userstr[dval]);
|
||||
break;
|
||||
case AGT_CNT: /* Counter */
|
||||
printval("Cnt", dval, dbgcntptr);
|
||||
break;
|
||||
case AGT_DIR: /* Direction */
|
||||
if (dval >= 1 && dval <= 13)
|
||||
dbgprintf("%s", exitname[dval - 1]);
|
||||
else dbgprintf("ILL_DIR(%d)", dval);
|
||||
break;
|
||||
case AGT_SUB: /* Subroutine */
|
||||
dbgprintf("Subroutine %d", dval);
|
||||
break;
|
||||
case AGT_PIC: /* Picture */
|
||||
case AGT_PIX:
|
||||
dbgprintf("Picture #%d", dval);
|
||||
break;
|
||||
case AGT_FONT: /* Font */
|
||||
dbgprintf("Font #%d", dval);
|
||||
break;
|
||||
case AGT_SONG: /* Song */
|
||||
dbgprintf("Song #%d", dval);
|
||||
break;
|
||||
case AGT_OBJFLAG:
|
||||
dbgprintf("ObjFlag%d", dval);
|
||||
break;
|
||||
case AGT_OBJPROP:
|
||||
dbgprintf("ObjProp%d", dval);
|
||||
break;
|
||||
case AGT_ATTR:
|
||||
if (dval < 0 || dval >= NUM_ATTR)
|
||||
dbgprintf("UnkownAttr%d", dval);
|
||||
else
|
||||
dbgprintf("%s", attrlist[dval].name);
|
||||
break;
|
||||
case AGT_PROP:
|
||||
if (dval < 0 || dval >= NUM_PROP)
|
||||
dbgprintf("UnknownProp%d", dval);
|
||||
else
|
||||
dbgprintf("%s", proplist[dval].name);
|
||||
break;
|
||||
case AGT_EXIT:
|
||||
if (dval >= exitmsg_base)
|
||||
argout(AGT_MSG, dval - exitmsg_base, 0);
|
||||
else
|
||||
argout(AGT_ROOM, dval, 0);
|
||||
break;
|
||||
default:
|
||||
dbgprintf("?+%d", dval);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void debug_newline(integer op, rbool first_nl) {
|
||||
rbool early_nl;
|
||||
|
||||
if (!dbg_nomsg) return;
|
||||
early_nl = (op == 1008 || op == 1027 || op == 1083 || op == 1105
|
||||
|| (op >= 1126 && op <= 1131));
|
||||
if (early_nl == first_nl)
|
||||
debugout("\n");
|
||||
}
|
||||
|
||||
|
||||
void debug_cmd_out(int ip, integer op, int arg1, int arg2, int optype) {
|
||||
int j;
|
||||
const opdef *opdata;
|
||||
rbool save_dbg_nomsg;
|
||||
|
||||
dbgprintf(" %2d:", ip);
|
||||
save_dbg_nomsg = 0; /* Just to silence compiler warnings. */
|
||||
|
||||
opdata = get_opdef(op);
|
||||
if (opdata == &illegal_def)
|
||||
dbgprintf("ILLEGAL %d\n", op);
|
||||
else {
|
||||
if (op >= END_ACT) dbgprintf("!"); /* "Terminal" Actions */
|
||||
else if (op <= MAX_COND) dbgprintf("?"); /* Condition */
|
||||
if (op == 1063) { /* RandomMessage needs special handling */
|
||||
save_dbg_nomsg = dbg_nomsg;
|
||||
dbg_nomsg = 1;
|
||||
}
|
||||
dbgprintf("%s", opdata->opcode);
|
||||
for (j = 0; j < opdata->argnum; j++) {
|
||||
dbgprintf("\t");
|
||||
argout(j == 0 ? opdata->arg1 : opdata->arg2 , j == 0 ? arg1 : arg2,
|
||||
optype >> 2);
|
||||
optype <<= 2;
|
||||
}
|
||||
if (op == 1063)
|
||||
dbg_nomsg = save_dbg_nomsg;
|
||||
}
|
||||
debug_newline(op, 1);
|
||||
}
|
||||
|
||||
|
||||
void debug_head(int i) {
|
||||
int v, w, a;
|
||||
|
||||
v = verb_code(command[i].verbcmd);
|
||||
if (v >= BASE_VERB && v < BASE_VERB + DUMB_VERB && syntbl[synlist[v]] != 0)
|
||||
w = syntbl[synlist[v]];
|
||||
else w = command[i].verbcmd;
|
||||
if (command[i].actor > 0) {
|
||||
dbgprintf("CMD %d: ", i);
|
||||
a = command[i].actor;
|
||||
} else {
|
||||
dbgprintf("REDIR: ");
|
||||
a = -command[i].actor;
|
||||
}
|
||||
|
||||
if (a == 2)
|
||||
dbgprintf("anybody, ");
|
||||
else if (a > 2) {
|
||||
char *name;
|
||||
name = objname(a);
|
||||
name[0] = toupper(name[0]);
|
||||
dbgprintf("%s, ", name);
|
||||
rfree(name);
|
||||
}
|
||||
|
||||
dbgprintf("%s ", w == 0 ? "any" : dict[w]);
|
||||
if (command[i].noun_adj != 0)
|
||||
dbgprintf("%s ", gdict(command[i].noun_adj));
|
||||
dbgprintf("%s %s ", gdict(command[i].nouncmd),
|
||||
(ver == 3) ? gdict(command[i].prep) : "->");
|
||||
if (command[i].obj_adj != 0)
|
||||
dbgprintf("%s ", gdict(command[i].obj_adj));
|
||||
dbgprintf("%s\n", gdict(command[i].objcmd));
|
||||
|
||||
}
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
1386
engines/glk/agt/exec.cpp
Normal file
1386
engines/glk/agt/exec.cpp
Normal file
File diff suppressed because it is too large
Load Diff
271
engines/glk/agt/exec.h
Normal file
271
engines/glk/agt/exec.h
Normal file
@@ -0,0 +1,271 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
#ifndef global /* Don't touch this */
|
||||
#define global extern
|
||||
#define global_defined_exec
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* This contains the decoding of the current instruction */
|
||||
struct op_rec {
|
||||
integer op;
|
||||
int arg1;
|
||||
int arg2;
|
||||
int optype;
|
||||
int argcnt; /* Actual number of argument words present */
|
||||
const opdef *opdata;
|
||||
const char *errmsg;
|
||||
rbool disambig; /* Trigger disambiguation? */
|
||||
rbool negate; /* NOT? (cond token only) */
|
||||
rbool failmsg; /* Run only on failure? */
|
||||
rbool endor; /* End any OR blocks? (action tokens, mainly) */
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
/* The following determines if we are doing disambiguation
|
||||
or actually executing a verb */
|
||||
global uchar do_disambig; /* 0= execution
|
||||
1= disambiguating noun
|
||||
2= disambiguating object */
|
||||
|
||||
|
||||
/* Flags used during turn execution */
|
||||
global rbool beforecmd; /* Only used by 1.8x games */
|
||||
global rbool suppress_debug; /* Causes debugging info to _not_ be printed
|
||||
even if debugging is on; used by disambiguator
|
||||
and to suppress ANY commands */
|
||||
global rbool was_metaverb; /* Was the verb that just executed a metaverb? */
|
||||
/* Metaverbs are commands that should not take game time
|
||||
to execute: SAVE, RESTORE, RESTART, QUIT, SCRIPT, UNSCRIPT,
|
||||
NOTIFY, SCORE, etc. */
|
||||
global integer oldloc; /* Save old location for NO_BLOCK_HOSTILE purposes */
|
||||
|
||||
/* This is a hack to pass the subroutine number from exec_token
|
||||
back to scan_metacommand when a DoSubroutine is done */
|
||||
global integer subcall_arg;
|
||||
|
||||
/* This fixes a bug in the original AGT spec, causing "actor, verb ..."
|
||||
commands to misfire if there is more than one creature of the same
|
||||
name. */
|
||||
global integer *creat_fix;
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Defined in EXEC.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
extern void raw_lineout(const char *s, rbool do_repl,
|
||||
int context, const char *pword);
|
||||
extern void msgout(int msgnum, rbool add_nl);
|
||||
extern void sysmsg(int msgid, const char *s);
|
||||
extern void alt_sysmsg(int msgid, const char *s, parse_rec *new_dobjrec,
|
||||
parse_rec *new_iobjrec);
|
||||
extern void sysmsgd(int msgid, const char *s, parse_rec *new_dobj_rec);
|
||||
|
||||
rbool ask_question(int qnum);
|
||||
extern void increment_turn(void);
|
||||
|
||||
/* Warning: the following function rfrees <ans> */
|
||||
extern rbool match_answer(char *ans, int anum);
|
||||
|
||||
extern void look_room(void);
|
||||
extern void runptr(int i, descr_ptr dp[], const char *msg, int msgid,
|
||||
parse_rec *nounrec, parse_rec *objrec);
|
||||
|
||||
extern int normalize_time(int tnum); /* Convert hhmm so mm<60 */
|
||||
extern void add_time(int dt);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Defined in OBJECT.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
extern parse_rec *make_parserec(int obj, parse_rec *rec);
|
||||
extern parse_rec *copy_parserec(parse_rec *rec);
|
||||
extern void free_all_parserec(void); /* Freeds doj_rec, iobj_rec, and actor_rec */
|
||||
|
||||
extern rbool in_scope(int item);
|
||||
extern rbool islit(void);
|
||||
extern rbool it_possess(int item);
|
||||
extern rbool it_proper(int item);
|
||||
extern rbool it_isweapon(int item);
|
||||
extern rbool it_door(int obj, word noun); /* Is obj a door? */
|
||||
extern rbool is_within(integer obj1, integer obj2, rbool stop_if_closed);
|
||||
|
||||
extern integer it_room(int item); /* Returns the room that the item is in */
|
||||
|
||||
extern int lightcheck(int parent, int roomlight, rbool active);
|
||||
/* If active is false, we don't care if the light is actually working. */
|
||||
|
||||
#define it_move(a,b) it_reposition(a,b,0)
|
||||
#define it_destroy(item) it_move(item,0)
|
||||
#define get_obj(dobj) it_move(dobj,1)
|
||||
#define drop_obj(dobj) it_move(dobj,loc+first_room)
|
||||
|
||||
extern void it_reposition(int item, int newloc, rbool save_pos);
|
||||
extern void goto_room(int newroom);
|
||||
|
||||
extern void it_describe(int dobj);
|
||||
extern int print_contents(int obj, int ind_lev);
|
||||
|
||||
extern void recompute_score(void);
|
||||
|
||||
extern int check_fit(int obj1, int obj2);
|
||||
|
||||
/* And its possible return values: */
|
||||
|
||||
#define FIT_OK 0 /* Fits */
|
||||
#define FIT_WEIGHT 1 /* Too heavy [*] */
|
||||
#define FIT_NETWEIGHT 2 /* With other stuff is too heavy [*] */
|
||||
#define FIT_SIZE 3 /* Too big */
|
||||
#define FIT_NETSIZE 4 /* With other stuff is too big */
|
||||
/* [*]-- These can only occur if obj2==1 or for ME/1.5-1.7 */
|
||||
|
||||
|
||||
extern long getprop(int obj, int prop);
|
||||
extern void setprop(int obj, int prop, long val);
|
||||
extern rbool getattr(int obj, int prop);
|
||||
extern void setattr(int obj, int prop, rbool val);
|
||||
|
||||
extern rbool matchclass(int obj, int oclass);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Define in RUNVERB.C */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/* Verbs actually used elsewhere in th interpreter */
|
||||
extern void v_inventory(void);
|
||||
extern void v_look(void);
|
||||
extern void v_listexit(void);
|
||||
|
||||
/* The routine that actually runs the current player command */
|
||||
extern void exec_verb(void);
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* In METACOMMAND.C */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* The main routine to search the metacommand list and run the appropriate
|
||||
meta-commands */
|
||||
extern int scan_metacommand(integer m_actor, int vcode,
|
||||
integer m_dobj, word m_prep, integer m_iobj,
|
||||
int *redir_flag);
|
||||
|
||||
/* The type checking routine */
|
||||
rbool argvalid(int argtype, int arg);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* In TOKEN.C */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
extern int exec_instr(op_rec *oprec); /* Execute instruction */
|
||||
extern long pop_expr_stack(void); /* Wrapper around routine to access TOS */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Defined in DEBUGCMD.C */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
extern void get_debugcmd(void); /* Get and execute debugging commands */
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* Macros for getting information about items */
|
||||
/* (mainly used to blackbox the difference between nouns and creatures) */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/* A note on object codes:
|
||||
<0 obj is a 'virtual' object, existing only as the word
|
||||
dict[-obj], e.g. DOOR, flag nouns, global nouns
|
||||
0 No object (or any object)
|
||||
1 Self(i.e. the player)
|
||||
first_room..last_room Rooms
|
||||
first_noun..last_noun Nouns
|
||||
first_creat..last_creat Creatures
|
||||
1000 Being worn by the player */
|
||||
|
||||
|
||||
/* The following macro loops over the contents of an object */
|
||||
#define contloop(i,obj) for(i=it_contents(obj);i!=0;i=it_next(i))
|
||||
#define safecontloop(i,j,obj) for(i=it_contents(obj),j=it_next(i); \
|
||||
i!=0;i=j,j=it_next(i))
|
||||
|
||||
#define cnt_val(c) ((c)==-1 ? 0 : (c))
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* These are the macros that should usually be used to determine */
|
||||
/* information about the objects in the game, unless the object type */
|
||||
/* is definitely known */
|
||||
/* ------------------------------------------------------------------- */
|
||||
|
||||
#define it_on(item) nounattr(item,on)
|
||||
#define it_group(item) creatattr(item,groupmemb)
|
||||
#define it_adj(item) objattr(item,adj)
|
||||
#define it_pushable(item) nounattr(item,pushable)
|
||||
#define it_pullable(item) nounattr(item,pullable)
|
||||
#define it_turnable(item) nounattr(item,turnable)
|
||||
#define it_playable(item) nounattr(item,playable)
|
||||
#define it_plur(item) nounattr(item,plural)
|
||||
#define it_gender(item) creatattr(item,gender)
|
||||
|
||||
#define it_pict(item) objattr(item,pict)
|
||||
#define it_class(item) anyattr(item,oclass)
|
||||
#define it_next(item) objattr(item,next)
|
||||
#define it_isglobal(item) objattr(item,isglobal)
|
||||
#define it_flagnum(item) objattr(item,flagnum)
|
||||
#define it_seen(item) anyattr(item,seen)
|
||||
|
||||
|
||||
#define it_name(item) objattr2(item,name,(item<0) ? -item : 0)
|
||||
#define it_open(item) nounattr2(item,open, tcreat(item) || \
|
||||
(tdoor(item) && !room[loc].locked_door))
|
||||
|
||||
/* This checks to make sure the object isn't unmovable. */
|
||||
/* (As such, all non-nouns automatically pass) */
|
||||
#define it_canmove(item) (!tnoun(item) || noun[(item)-first_noun].movable)
|
||||
|
||||
|
||||
#ifdef IT_MACRO
|
||||
#define it_contents(item) objattr2(item,contents,\
|
||||
roomattr2(item,contents,\
|
||||
(item==1) ? player_contents : \
|
||||
(item==1000) ? player_worn : 0))
|
||||
#define it_lockable(item) nounattr2(item,lockable, (tdoor(item) ? 1 : 0) )
|
||||
#define it_locked(item,name) nounattr2(item,locked,\
|
||||
(tdoor(item) && room[loc].locked_door ? \
|
||||
1 : 0))
|
||||
#else
|
||||
extern int it_contents(integer obj);
|
||||
extern rbool it_lockable(integer obj, word noun);
|
||||
extern rbool it_locked(integer obj, word noun);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef global_defined_exec
|
||||
#undef global
|
||||
#undef global_defined_exec
|
||||
#endif
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
544
engines/glk/agt/filename.cpp
Normal file
544
engines/glk/agt/filename.cpp
Normal file
@@ -0,0 +1,544 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/agt/agility.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
#ifdef force16
|
||||
#undef int
|
||||
#define int short
|
||||
#endif
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Filetype Data */
|
||||
/*----------------------------------------------------------------------*/
|
||||
const char *extname[] = {
|
||||
"",
|
||||
DA1, DA2, DA3, DA4, DA5, DA6, DSS,
|
||||
pHNT, pOPT, pTTL,
|
||||
pSAV, pSCR, pLOG,
|
||||
pAGX, pINS, pVOC, pCFG,
|
||||
pAGT, pDAT, pMSG, pCMD, pSTD, AGTpSTD
|
||||
};
|
||||
|
||||
|
||||
#ifdef PATH_SEP
|
||||
static const char *path_sep = PATH_SEP;
|
||||
#else
|
||||
static const char *path_sep = nullptr;
|
||||
#endif
|
||||
|
||||
/* This returns the options to use when opening the given file type */
|
||||
/* rw is true if we are writing, false if we are reading. */
|
||||
const char *filetype_info(filetype ft, rbool rw) {
|
||||
if (ft < fTTL) return "rb";
|
||||
if (ft == fAGX) return rw ? "wb" : "rb";
|
||||
if (ft == fSAV) return (rw ? "wb" : "rb");
|
||||
if (ft == fTTL || ft == fINS || ft == fVOC) return "rb";
|
||||
#ifdef OPEN_AS_TEXT
|
||||
if (ft >= fCFG) return (open_as_binary ? "rb" : "r");
|
||||
#else
|
||||
if (ft >= fCFG) return "rb";
|
||||
#endif
|
||||
if (ft == fSCR) {
|
||||
if (rw)
|
||||
return (BATCH_MODE || make_test) ? "w" : "a";
|
||||
else return "r";
|
||||
}
|
||||
if (ft == fLOG) return rw ? "w" : "r";
|
||||
fatal("INTERNAL ERROR: Invalid filetype.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/* Returns true if ft is a possible extension in general context ft_base */
|
||||
static rbool compat_ext(filetype ft, filetype ft_base) {
|
||||
if (ft_base == fNONE || ft_base == fDA1 || ft_base == fAGX) { /* Game file */
|
||||
return (ft >= fDA1 && ft <= fDSS)
|
||||
|| ft == fOPT || ft == fTTL
|
||||
|| (ft >= fAGX && ft <= fCFG);
|
||||
}
|
||||
|
||||
if (ft_base == fSAV || ft_base == fSCR || ft_base == fLOG)
|
||||
return (ft == ft_base);
|
||||
|
||||
if (ft_base == fAGT) { /* Source code */
|
||||
return (ft >= fAGT && ft <= fCMD)
|
||||
|| ft == fTTL || ft == fCFG;
|
||||
}
|
||||
|
||||
fatal("INTERNAL ERROR: Invalid file class.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Misc. utilities */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
char *assemble_filename(const char *path, const char *root,
|
||||
const char *ext) {
|
||||
int len1, len2, len3;
|
||||
char *name;
|
||||
|
||||
len1 = len2 = len3 = 0;
|
||||
if (path != nullptr) len1 = strlen(path);
|
||||
if (root != nullptr) len2 = strlen(root);
|
||||
if (ext != nullptr) len3 = strlen(ext);
|
||||
name = (char *)rmalloc(len1 + len2 + len3 + 1);
|
||||
if (path != nullptr) memcpy(name, path, len1);
|
||||
#ifdef PREFIX_EXT
|
||||
if (ext != NULL) memcpy(name + len1, ext, len3);
|
||||
if (root != NULL) memcpy(name + len1 + len3, root, len2);
|
||||
#else
|
||||
if (root != nullptr) memcpy(name + len1, root, len2);
|
||||
if (ext != nullptr) memcpy(name + len1 + len2, ext, len3);
|
||||
#endif
|
||||
name[len1 + len2 + len3] = 0;
|
||||
return name;
|
||||
}
|
||||
|
||||
#ifdef PATH_SEP
|
||||
/* This works for binary files; we don't care about non-binary
|
||||
files since this only used to search for game files. */
|
||||
static rbool file_exist(const char *fname) {
|
||||
return Common::File::exists(fname);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This checks to see if c matches any of the characters in matchset */
|
||||
static rbool smatch(char c, const char *matchset) {
|
||||
for (; *matchset != 0; matchset++)
|
||||
if (*matchset == c) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Taking Apart the Filename */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
static int find_path_sep(const char *name) {
|
||||
int i;
|
||||
|
||||
if (path_sep == nullptr)
|
||||
return -1;
|
||||
for (i = strlen(name) - 1; i >= 0; i--)
|
||||
if (smatch(name[i], path_sep)) break;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/* Checks to see if the filename (which must be path-free)
|
||||
has an extension. Returns the length of the extensions
|
||||
and writes the extension type in pft */
|
||||
static int search_for_ext(const char *name, filetype base_ft,
|
||||
filetype *pft) {
|
||||
filetype t;
|
||||
int xlen, len;
|
||||
|
||||
*pft = fNONE;
|
||||
len = strlen(name);
|
||||
if (len == 0) return 0;
|
||||
for (t = (filetype)(fNONE + 1); t <= fSTD; t = (filetype)((int)t + 1))
|
||||
if (compat_ext(t, base_ft)) {
|
||||
xlen = strlen(extname[t]);
|
||||
if (xlen == 0 || xlen > len) continue;
|
||||
#ifdef PREFIX_EXT
|
||||
if (strncasecmp(name, extname[t], xlen) == 0)
|
||||
#else
|
||||
if (fnamecmp(name + len - xlen, extname[t]) == 0)
|
||||
#endif
|
||||
{
|
||||
*pft = t;
|
||||
return xlen;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Extract root filename or extension from
|
||||
pathless name, given that the extension is of length extlen. */
|
||||
/* If isext is true, extract the extension. If isext is false,
|
||||
then extrac the root. */
|
||||
static char *extract_piece(const char *name, int extlen, rbool isext) {
|
||||
char *root;
|
||||
int len, xlen;
|
||||
rbool first; /* If true, extract from beginning; if false, extract
|
||||
from end */
|
||||
|
||||
len = strlen(name) - extlen;
|
||||
xlen = extlen;
|
||||
if (isext) {
|
||||
int tmp;
|
||||
tmp = len;
|
||||
len = xlen;
|
||||
xlen = tmp;
|
||||
}
|
||||
if (len == 0) return nullptr;
|
||||
root = (char *)rmalloc((len + 1) * sizeof(char));
|
||||
#ifdef PREFIX_EXT
|
||||
first = isext ? 1 : 0;
|
||||
#else
|
||||
first = isext ? 0 : 1;
|
||||
#endif
|
||||
if (first) {
|
||||
memcpy(root, name, len);
|
||||
root[len] = 0;
|
||||
} else {
|
||||
memcpy(root, name + xlen, len);
|
||||
root[len] = 0;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
/* This returns true if "path" is absolute, false otherwise.
|
||||
This is _very_ platform dependent. */
|
||||
static rbool absolute_path(char *path) {
|
||||
#ifdef pathtest
|
||||
return pathtest(path);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Basic routines for dealing with file contexts */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
#define FC(x) ((file_context_rec*)(x))
|
||||
|
||||
/* formal_name is used to get filenames for diagnostic messages, etc. */
|
||||
char *formal_name(fc_type fc, filetype ft) {
|
||||
if (FC(fc)->special) return FC(fc)->gamename;
|
||||
if (ft == fNONE)
|
||||
return rstrdup(FC(fc)->shortname);
|
||||
if (ft == fAGT_STD)
|
||||
return rstrdup(AGTpSTD);
|
||||
return assemble_filename("", FC(fc)->shortname, extname[ft]);
|
||||
}
|
||||
|
||||
#ifdef PATH_SEP
|
||||
static rbool test_file(const char *path, const char *root, const char *ext) {
|
||||
char *name;
|
||||
rbool tmp;
|
||||
|
||||
name = assemble_filename(path, root, ext);
|
||||
tmp = file_exist(name);
|
||||
rfree(name);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* This does a path search for the game files. */
|
||||
static void fix_path(file_context_rec *fc) {
|
||||
char **ppath;
|
||||
|
||||
|
||||
if (gamepath == NULL) return;
|
||||
for (ppath = gamepath; *ppath != NULL; ppath++)
|
||||
if (test_file(*ppath, fc->shortname, fc->ext)
|
||||
|| test_file(*ppath, fc->shortname, pAGX)
|
||||
|| test_file(*ppath, fc->shortname, DA1)) {
|
||||
fc->path = rstrdup(*ppath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* This creates a new file context based on gamename. */
|
||||
/* ft indicates the rough use it will be put towards:
|
||||
ft=fNONE indicates it's the first pass read, before PATH has been
|
||||
read in, and so the fc shouldn't be filled out until
|
||||
fix_file_context() is called.
|
||||
ft=pDA1 indicates that name refers to the game files.
|
||||
ft=pAGX indicates the name of the AGX file to be written to.
|
||||
ft=pSAV,pLOG,pSCR all indicate that name corresponds to the
|
||||
related type of file. */
|
||||
fc_type init_file_context(const char *name, filetype ft) {
|
||||
file_context_rec *fc;
|
||||
int p, x; /* Path and extension markers */
|
||||
|
||||
fc = (file_context_rec *)rmalloc(sizeof(file_context_rec));
|
||||
fc->special = 0;
|
||||
|
||||
fc->gamename = rstrdup(name);
|
||||
|
||||
p = find_path_sep(fc->gamename);
|
||||
if (p < 0)
|
||||
fc->path = nullptr;
|
||||
else {
|
||||
fc->path = (char *)rmalloc((p + 2) * sizeof(char));
|
||||
memcpy(fc->path, fc->gamename, p + 1);
|
||||
fc->path[p + 1] = '\0';
|
||||
}
|
||||
x = search_for_ext(fc->gamename + p + 1, ft, &fc->ft);
|
||||
fc->shortname = extract_piece(fc->gamename + p + 1, x, 0);
|
||||
fc->ext = extract_piece(fc->gamename + p + 1, x, 1);
|
||||
|
||||
#ifdef PATH_SEP
|
||||
if (fc->path == NULL && ft == fDA1)
|
||||
fix_path(fc);
|
||||
#endif
|
||||
return fc;
|
||||
}
|
||||
|
||||
|
||||
void fix_file_context(fc_type fc, filetype ft) {
|
||||
#ifdef PATH_SEP
|
||||
if (FC(fc)->path == NULL && ft == fDA1)
|
||||
fix_path(FC(fc));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* This creates new file contexts from old. */
|
||||
/* This is used to create save/log/script filenames from the game name,
|
||||
and to create include files in the same directory as the source file. */
|
||||
fc_type convert_file_context(fc_type fc, filetype ft, const char *name) {
|
||||
file_context_rec *nfc;
|
||||
rbool local_ftype; /* Indicates file should be in working directory,
|
||||
not game directory. */
|
||||
|
||||
local_ftype = (ft == fSAV || ft == fSCR || ft == fLOG);
|
||||
if (BATCH_MODE || make_test) local_ftype = 0;
|
||||
|
||||
if (name == nullptr) {
|
||||
nfc = (file_context_rec *)rmalloc(sizeof(file_context_rec));
|
||||
nfc->gamename = nullptr;
|
||||
nfc->path = nullptr;
|
||||
nfc->shortname = rstrdup(fc->shortname);
|
||||
nfc->ext = nullptr;
|
||||
nfc->ft = fNONE;
|
||||
nfc->special = 0;
|
||||
} else {
|
||||
nfc = init_file_context(name, ft);
|
||||
}
|
||||
|
||||
/* If path already defined, then combine paths. */
|
||||
if (!local_ftype && nfc->path != nullptr && !absolute_path(nfc->path)) {
|
||||
char *newpath;
|
||||
newpath = nfc->path;
|
||||
newpath = assemble_filename(fc->path, nfc->path, "");
|
||||
rfree(nfc->path);
|
||||
nfc->path = newpath;
|
||||
}
|
||||
|
||||
/* scripts, save-games and logs should go in the working directory,
|
||||
not the game directory, so leave nfc->path equal to NULL for them. */
|
||||
if (!local_ftype && nfc->path == nullptr)
|
||||
nfc->path = rstrdup(fc->path); /* Put files in game directory */
|
||||
return nfc;
|
||||
}
|
||||
|
||||
void release_file_context(fc_type *pfc) {
|
||||
file_context_rec *fc;
|
||||
fc = FC(*pfc);
|
||||
rfree(fc->gamename);
|
||||
rfree(fc->path);
|
||||
rfree(fc->shortname);
|
||||
rfree(fc->ext);
|
||||
rfree(fc);
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Routines for Finding Files */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
static genfile try_open_file(const char *path, const char *root,
|
||||
const char *ext, const char *how,
|
||||
rbool nofix) {
|
||||
char *name = assemble_filename(path, root, ext);
|
||||
genfile f = fopen(name, how);
|
||||
rfree(name);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
static genfile findread(file_context_rec *fc, filetype ft) {
|
||||
genfile f;
|
||||
|
||||
f = nullptr;
|
||||
|
||||
if (ft == fAGT_STD) {
|
||||
f = try_open_file(fc->path, AGTpSTD, "", filetype_info(ft, 0), 0);
|
||||
return f;
|
||||
}
|
||||
if (ft == fAGX || ft == fNONE) /* Try opening w/o added extension */
|
||||
f = try_open_file(fc->path, fc->shortname, fc->ext, filetype_info(ft, 0), 0);
|
||||
if (f == nullptr)
|
||||
f = try_open_file(fc->path, fc->shortname, extname[ft], filetype_info(ft, 0), 0);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* File IO Routines */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
genfile readopen(fc_type fc, filetype ft, const char **errstr) {
|
||||
genfile f;
|
||||
|
||||
*errstr = nullptr;
|
||||
f = findread(fc, ft);
|
||||
if (f == nullptr) {
|
||||
*errstr = "Cannot open file";
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
rbool fileexist(fc_type fc, filetype ft) {
|
||||
genfile f;
|
||||
|
||||
if (fc->special) return 0;
|
||||
f = try_open_file(fc->path, fc->shortname, extname[ft], filetype_info(ft, 0), 1);
|
||||
if (f != nullptr) { /* File already exists */
|
||||
readclose(f);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
genfile writeopen(fc_type fc, filetype ft,
|
||||
file_id_type *pfileid, const char **errstr) {
|
||||
char *name;
|
||||
genfile f;
|
||||
|
||||
*errstr = nullptr;
|
||||
name = nullptr;
|
||||
|
||||
{
|
||||
name = assemble_filename(FC(fc)->path, FC(fc)->shortname, extname[ft]);
|
||||
f = fopen(name, filetype_info(ft, 1));
|
||||
}
|
||||
if (f == nullptr) {
|
||||
*errstr = "Cannot open file";
|
||||
}
|
||||
if (pfileid == nullptr)
|
||||
rfree(name);
|
||||
else
|
||||
*pfileid = name;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
rbool filevalid(genfile f, filetype ft) {
|
||||
return (f != nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void binseek(genfile f, long offset) {
|
||||
Common::SeekableReadStream *rs = dynamic_cast<Common::SeekableReadStream *>(f);
|
||||
assert(rs);
|
||||
|
||||
rs->seek(offset);
|
||||
}
|
||||
|
||||
|
||||
/* This returns the number of bytes read, or 0 if there was an error. */
|
||||
long varread(genfile f, void *buff, long recsize, long recnum, const char **errstr) {
|
||||
long num;
|
||||
|
||||
*errstr = nullptr;
|
||||
assert(f != nullptr);
|
||||
|
||||
num = fread(buff, recsize, recnum, f);
|
||||
if (num != recnum)
|
||||
*errstr = "varread";
|
||||
num = num * recsize;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
rbool binread(genfile f, void *buff, long recsize, long recnum, const char **errstr) {
|
||||
long num;
|
||||
|
||||
num = varread(f, buff, recsize, recnum, errstr);
|
||||
if (num < recsize * recnum && *errstr == nullptr)
|
||||
*errstr = rstrdup("Unexpected end of file.");
|
||||
return (*errstr == nullptr);
|
||||
}
|
||||
|
||||
|
||||
rbool binwrite(genfile f, void *buff, long recsize, long recnum, rbool ferr) {
|
||||
assert(f != nullptr);
|
||||
|
||||
if (fwrite(buff, recsize, recnum, f) != (size_t)recnum) {
|
||||
if (ferr) fatal("binwrite");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void readclose(genfile f) {
|
||||
assert(f != nullptr);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void writeclose(genfile f, file_id_type fileid) {
|
||||
assert(f != nullptr);
|
||||
rfree(fileid);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
long binsize(genfile f)
|
||||
/* Returns the size of a binary file */
|
||||
{
|
||||
long pos, leng;
|
||||
|
||||
assert(f != nullptr);
|
||||
|
||||
pos = ftell(f);
|
||||
fseek(f, 0, SEEK_END);
|
||||
leng = ftell(f);
|
||||
fseek(f, pos, SEEK_SET);
|
||||
|
||||
return leng;
|
||||
}
|
||||
|
||||
rbool textrewind(genfile f) {
|
||||
Common::SeekableReadStream *rs = dynamic_cast<Common::SeekableReadStream *>(f);
|
||||
assert(rs);
|
||||
rs->seek(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
genfile badfile(filetype ft) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
1654
engines/glk/agt/gamedata.cpp
Normal file
1654
engines/glk/agt/gamedata.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1036
engines/glk/agt/interface.cpp
Normal file
1036
engines/glk/agt/interface.cpp
Normal file
File diff suppressed because it is too large
Load Diff
539
engines/glk/agt/interp.h
Normal file
539
engines/glk/agt/interp.h
Normal file
@@ -0,0 +1,539 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#ifndef GLK_AGT_INTERP
|
||||
#define GLK_AGT_INTERP
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
/* This file contains variables and data structures used
|
||||
by the interpreter but not read in from the gamefile.
|
||||
For the rest of the data structures, see agility.h and
|
||||
agtdata.c */
|
||||
|
||||
#ifndef global
|
||||
#define uagt_defined_global
|
||||
#define global extern
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* The following are debugging and diagnostic flags. */
|
||||
/* They are mainly intended for debugging the interpreter, but */
|
||||
/* they could concievable be used for debugging games under the */
|
||||
/* interpreter */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
global rbool stable_random;
|
||||
/* --Force random numbers to be repeatable. */
|
||||
|
||||
|
||||
global rbool DEBUG_MEM; /* prints out information on memory allocation */
|
||||
|
||||
global rbool debug_parse; /* Prints out long parse diagnostic information
|
||||
after the sentence has been parse but before
|
||||
disambiguation */
|
||||
global rbool DEBUG_EXEC_VERB; /* This prints out a line indicating each command
|
||||
that exec_verb() is asked to run */
|
||||
global rbool DEBUG_DISAMBIG; /* Print out dismabiguation debugging info */
|
||||
global rbool DEBUG_SMSG; /* Print out STANDARD message info */
|
||||
|
||||
#define DEBUG_AGT_CMD flag[0] /* This sends metacommand execution information
|
||||
to either the screen or debugfile, depending on
|
||||
whether DEBUG_OUT is true or false. */
|
||||
|
||||
global rbool debug_disambig, debug_any;
|
||||
/* These determine if metacommands are traced during disambiguation
|
||||
or during the scanning of ANY commands */
|
||||
|
||||
global rbool DEBUG_OUT; /* True if debugging output is redirected somewhere
|
||||
other than the screen */
|
||||
global Common::DumpFile *debugfile; /* Where debugging output should be sent */
|
||||
|
||||
#define def_DEBUG_MEM 1 /* parser.c */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* The following are AGT 'purity' flags; they turn off features of */
|
||||
/* my interpreter that are not fully consistent with the original AGT.*/
|
||||
/* More are defined in agility.h, and you should look there for general */
|
||||
/* notes */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/* The following are defined (and described) in agil.c */
|
||||
extern rbool PURE_INPUT, PURE_TONE;
|
||||
|
||||
#define PURE_WEAR 1 /* If this is cleared, then things taken off
|
||||
still stay in the player's inventory.
|
||||
The support for this isn't quite complete yet
|
||||
(there are one or two checks that need to be done
|
||||
but aren't) and so right now this should be 1. */
|
||||
|
||||
global rbool PURE_DOT; /* Treats period as a letter-character and not
|
||||
as punctuation. This should be set automatically
|
||||
during initialization based on whether any words
|
||||
in the dictionary have dots. */
|
||||
|
||||
#define FORCE_PURE_DOT 0 /* This forces the period to be treated as a letter
|
||||
even if there are no words in the dictionary
|
||||
containing periods. The only reason to set
|
||||
this was if you were concerned that knowledge
|
||||
about the presence or absence of periods in the
|
||||
dictionary would give puzzles away. */
|
||||
|
||||
|
||||
|
||||
|
||||
#define MEM_MARGIN (16*1024) /* 16K should be enough (SOGGY, the largest AGT
|
||||
game, uses around 12K) */
|
||||
#define PICT_SUPPORT 0 /* Graphics not supported */
|
||||
#define TAB_SIZE 3 /* Number of spaces in a tab */
|
||||
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Variables and Flags related to Metaverbs */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
global rbool notify_flag, listexit_flag, menu_mode;
|
||||
|
||||
global rbool cmd_saveable; /* set indicates that this command can be repeated
|
||||
with AGAIN. */
|
||||
global rbool can_undo; /* Can we UNDO the last turn? */
|
||||
|
||||
global uchar *restart_state, *undo_state; /* Store old game states for
|
||||
RESTART and UNDO */
|
||||
global char doing_restore; /* Have we been asked to RESTORE? */
|
||||
|
||||
global rbool do_look; /* True if we should print a room description */
|
||||
global rbool do_autoverb; /* True if we should run the autoexec verb
|
||||
for the current room */
|
||||
|
||||
/* The following are used for scripting and logging */
|
||||
global rbool script_on;
|
||||
global genfile scriptfile;
|
||||
global signed char logflag; /* 1=logging, 2=replaying, 0=neither, 3=both */
|
||||
global int logdelay; /* -1=wait for keypress, >=0 is numerical delay */
|
||||
global genfile log_in, log_out;
|
||||
|
||||
global rbool fast_replay; /* If true, don't print MORE prompts. */
|
||||
|
||||
global rbool sound_on; /* Manipulated by music_cmd; can be used by interface
|
||||
to determine if a tone should be made */
|
||||
|
||||
global integer *pictable; /* Used to decode picture numbers */
|
||||
global fc_type hold_fc; /* Needed to print instructions on demand */
|
||||
|
||||
global unsigned short compass_rose; /* Used to pass compass info to
|
||||
the os layer */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Game State */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
global rbool quitflag, deadflag, winflag, endflag;
|
||||
global rbool first_visit_flag, newlife_flag, room_firstdesc;
|
||||
|
||||
global rbool start_of_turn; /* True if running the command on the first
|
||||
noun in the list */
|
||||
global rbool end_of_turn; /* True if running command on last noun in
|
||||
the list. */
|
||||
|
||||
global rbool actor_in_scope; /* Used to determine if the actor was in
|
||||
scope when the command was originally
|
||||
given */
|
||||
|
||||
global integer loc; /* Player's location */
|
||||
global integer player_contents, player_worn; /* Worn and carried objects*/
|
||||
|
||||
global long totwt, totsize; /* Size and wt player is carrying around */
|
||||
|
||||
global integer curr_lives; /* Number of lives left. */
|
||||
|
||||
global long tscore, old_score; /* Total score */
|
||||
global long objscore; /* Portion of tscore that comes from the POINTS
|
||||
field of nouns and creatures. */
|
||||
|
||||
global integer turncnt; /* Number of turns that have passed */
|
||||
global integer curr_time; /* The time in the game; in the format
|
||||
1243==12:43 */
|
||||
|
||||
global rbool *flag; /* AGT Flags */
|
||||
global short *agt_counter; /* AGT counters */
|
||||
#ifdef AGT_16BIT
|
||||
global short *agt_var; /*AGT variables */
|
||||
#else
|
||||
global long *agt_var;
|
||||
#endif
|
||||
|
||||
global long agt_number; /* The number entered by the player */
|
||||
global rbool agt_answer; /* Did the player get the answer to the last question
|
||||
right? */
|
||||
|
||||
global tline l_stat, r_stat; /* Left and right parts of status line */
|
||||
/* If r_stat is the empty string, l_stat should be
|
||||
centered to create a Trinity-like status line */
|
||||
|
||||
global rbool nomatch_aware; /* Does the game use the nomatch extension
|
||||
to the metacommand format?
|
||||
(which allow <none> and ANY to be
|
||||
distingused) */
|
||||
|
||||
global rbool smart_look; /* If true, then LOOK <object> will be converted
|
||||
to EXAMINE. This is set automatically in agil.c,
|
||||
based on whether the game file uses
|
||||
LOOK <object> in any of the metacommands; if it
|
||||
does, then smart_look is set to 0. */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Menu data structures */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
#define MENU_WIDTH 50
|
||||
typedef char menuentry[MENU_WIDTH];
|
||||
|
||||
global int vm_width; /* Width of widest element */
|
||||
global menuentry *verbmenu;
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Parser Data Structures */
|
||||
/* This also includes "parser-related" variables like dobj and iobj */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/* This extracts the object number from a parse rec */
|
||||
#define p_obj(objrec) ((objrec) ? (objrec)->obj : 0)
|
||||
|
||||
/* The following data structures are used for disambiguation of nouns */
|
||||
struct parse_rec {
|
||||
long num; /* Numeric value of object; 0 if object doesn't have one */
|
||||
int obj; /* Object number; negative values point into the dictionary */
|
||||
int info; /* Disambiguation info */
|
||||
/* -1=last record; ignore obj field. */
|
||||
word noun, adj; /* Used for printing out error messages */
|
||||
short score; /* Disambiguation score */
|
||||
}; /* Stores objects that have been found during parse */
|
||||
|
||||
|
||||
/* In an ideal world, the following would all be local variables. */
|
||||
/* Unfortunately, they're used in too many different places for this
|
||||
to be practical */
|
||||
|
||||
global int vb;
|
||||
global integer actor, dobj, iobj;
|
||||
global parse_rec *actor_rec, *dobj_rec, *iobj_rec;
|
||||
global word prep;
|
||||
global parse_rec *curr_creat_rec;
|
||||
/* Creature currently behaving in a hostile way:
|
||||
used to fill in $c_name$ messages */
|
||||
|
||||
global int disambig_score; /* Used to rank objects during disambiguation */
|
||||
|
||||
#define DISAMBIG_SUCC 1000 /* Score given to an object that triggers a
|
||||
built-in verb or an action token */
|
||||
|
||||
|
||||
#define MAXINPUT 200 /* Max number of words input */
|
||||
|
||||
global word input[MAXINPUT]; /* 200 words of input should be enough */
|
||||
global words in_text[MAXINPUT];
|
||||
/* The corrospoinding strings, for error reporting purposes */
|
||||
|
||||
global short ip, ep; /* input pointer and error pointer */
|
||||
global short ap, vp, np, pp, op; /* Points to first word in actor, verb, noun,
|
||||
and object resp. */
|
||||
|
||||
|
||||
|
||||
/* The following needs to be kept consistent with ext_voc[] in
|
||||
agil.c */
|
||||
typedef enum {wthe, wmy, wa, wan, wthen, wp, wsc, wand, wc, wits, wall, wundo, wlook, wg,
|
||||
wpick, wgo, wexits, wtalk, wtake, wdoor, wagain, wbut, wexcept,
|
||||
wscene, weverything, wlistexit, wlistexits, wclose,
|
||||
wdverb, wdnoun, wdadjective, wdprep, wdobject, wdname,
|
||||
wstep, w_any, weither, wboth, weveryone, weverybody,
|
||||
whe, wshe, wit, wthey, whim, wher, wthem, wis, ware, woops,
|
||||
wwas, wwere, wscream,
|
||||
win, wout, winto, wat, wto, wacross, winside, wwith, wnear, wfor,
|
||||
wof, wbehind, wbeside, won, woff, wunder, wfrom, wthrough,
|
||||
wtoward, wtowards, wbetween, waround, wupon, wthru,
|
||||
wby, wover, wup, wdown,
|
||||
wabout
|
||||
} wtype;
|
||||
global word ext_code[wabout + 1]; /* Codes for the above */
|
||||
global short last_he, last_she, last_it, last_they;
|
||||
/* Used for pronoun support */
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Noun List Data structures and constants */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
|
||||
/* The following are used in noun lists */
|
||||
#define AND_MARK (-ext_code[wand])
|
||||
#define ALL_MARK (-ext_code[wall])
|
||||
|
||||
#define D_END 50 /* Marks end of disambiguation list */
|
||||
#define D_AND 51 /* Used to separate multiple objects during disambig */
|
||||
#define D_NOUN 0 /* Noun match */
|
||||
#define D_SYN 1 /* Adjective/synonym only match */
|
||||
#define D_ADJ 2 /* Adj only match */
|
||||
#define D_FLAG 3 /* Flag noun */
|
||||
#define D_GLOBAL 4 /* Global noun */
|
||||
#define D_PIX 5 /* PIX name */
|
||||
#define D_PRO 6 /* Pronoun */
|
||||
#define D_ALL 7 /* ALL, or a header to an ALL EXCEPT _ AND _ ... list */
|
||||
#define D_INTERN 8 /* Internal nouns: DOOR, SCENE */
|
||||
#define D_NUM 9 /* A number, value is in obj */
|
||||
#define D_EITHER 10 /* EITHER or ANY, used only to resolve disambiguation */
|
||||
|
||||
#define D_MARK 0x80 /* Used as a temporary marker, usually to indicate
|
||||
this noun is being considered for elimination */
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* These are used for text boxes (quotes and the title) */
|
||||
/* -------------------------------------------------------------------- */
|
||||
#define TB_TTL 1 /* We're printing the title */
|
||||
#define TB_BOLD 2 /* Print it bold */
|
||||
#define TB_BORDER 4 /* Give it a border */
|
||||
#define TB_CENTER 8 /* Center the text inside */
|
||||
#define TB_NOCENT 16 /* Don't center the whole box */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* In AGIL.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
extern void print_instructions(fc_type fc);
|
||||
extern void run_game(fc_type fc);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* In PARSER.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
extern rbool parse(void); /* Returns true unless there is ambiguity */
|
||||
extern void menu_cmd(void);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* In EXEC.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/* Legal values for gen_sysmsg context; they indicate who is calling it */
|
||||
#define MSG_PARSE 0 /* The parser */
|
||||
#define MSG_MAIN 1 /* The main execution loop */
|
||||
#define MSG_RUN 2 /* The routines that execute the player's commands */
|
||||
#define MSG_DESC 3 /* Printing out description. */
|
||||
|
||||
extern void gen_sysmsg(int msgid, const char *s, int context, const char *pword);
|
||||
/* Prints either STANDARD message <msgid> or default msg <s>;
|
||||
<context> determines what $$ substitutions are meaningful
|
||||
<parseword> gives the $pword$ substitution for MSG_PARSE messages */
|
||||
|
||||
extern void exec(parse_rec *actor, int vnum, parse_rec *lnoun,
|
||||
word prep, parse_rec *iobj);
|
||||
extern void set_statline(void);
|
||||
extern void newroom(void);
|
||||
extern void print_descr(descr_ptr dp, rbool nl);
|
||||
extern void quote(int msgnum);
|
||||
extern void print_score(void);
|
||||
extern long read_number(void);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* In TOKEN.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
extern void init_stack(void); /* Set up expression stack */
|
||||
extern void clear_stack(void); /* Set stack back to empty state */
|
||||
extern void reset_random(void); /* Reset random number generator state */
|
||||
extern int get_random(int a, int b); /* Return random number from a to b, inclusive */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* In OBJECT.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
extern rbool player_has(int item);
|
||||
extern rbool visible(int item);
|
||||
extern rbool genvisible(parse_rec *dobj);
|
||||
extern int *get_nouns(void); /* Returns list of in scope nouns */
|
||||
extern void add_object(int loc, int item); /* Adds item to loc's contents list */
|
||||
extern void tmpobj(parse_rec *objrec);
|
||||
extern void compute_scope(void); /* Sets scope flags for all of the objects */
|
||||
extern void compute_seen(void); /* Determine HAS_SEEN flag for nouns and creatures */
|
||||
|
||||
extern void init_creat_fix(void);
|
||||
extern void free_creat_fix(void);
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* The following are intended as building blocks to construct macros */
|
||||
/* to extract information about general objects, regardless of whether */
|
||||
/* they are nouns, creatures, or virtual nouns with no associated */
|
||||
/* data structure. */
|
||||
/* ------------------------------------------------------------------- */
|
||||
/* nounattr(item,attr) -- returns 0 if not noun.
|
||||
creatattr(item,attr) -- returns 0 if not creature
|
||||
objattr(item,attr) -- Returns attribute for noun or creature, 0 otherwise
|
||||
anyattr(item,attr) -- Returns attribute for noun, creature, or room,
|
||||
0 otherwise.
|
||||
*/
|
||||
|
||||
#define creatattr2(item,attr,op3) (tcreat(item)? \
|
||||
creature[(item)-first_creat].attr:\
|
||||
(op3))
|
||||
#define creatattr(item,attr) creatattr2(item,attr,0)
|
||||
#define nounattr2(item,attr,alt) (tnoun(item)? \
|
||||
noun[(item)-first_noun].attr:(alt))
|
||||
#define nounattr(item,attr) nounattr2(item,attr,0)
|
||||
#define objattr(item,attr) nounattr2(item,attr,creatattr(item,attr))
|
||||
#define objattr2(item,attr,op3) nounattr2(item,attr,creatattr2(item,attr,op3))
|
||||
#define roomattr2(item,attr,op3) (troom(item)?\
|
||||
room[(item)-first_room].attr:(op3))
|
||||
#define anyattr(item,attr) roomattr2(item,attr,objattr(item,attr))
|
||||
|
||||
#define it_scratch(item) objattr(item,scratch)
|
||||
#define it_loc(item) objattr2(item,location,\
|
||||
(tdoor(item)) ? loc+first_room : 0)
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* In RUNVERB.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
extern int check_obj(parse_rec *act, int verbid,
|
||||
parse_rec *donum, word prep, parse_rec *ionum);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* In AGTDBG.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
extern void debug_cmd_out(int ip, integer op, int arg1, int arg2, int optype);
|
||||
extern void debug_head(int);
|
||||
extern void debug_newline(integer op, rbool first_nl);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* In SAVEGAME.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
extern Common::Error savegame(Common::WriteStream *savefile);
|
||||
extern Common::Error loadgame(Common::SeekableReadStream *loadfile);
|
||||
extern void init_state_sys(void); /* Must be called before either of the following */
|
||||
extern uchar *getstate(uchar *gs);
|
||||
/* Returns malloc'd block containing game state. */
|
||||
extern void putstate(uchar *gs); /* Restores games state. */
|
||||
extern void init_vals(void); /* Compute dependent variables
|
||||
such as totwt, totsize, etc. */
|
||||
extern void restart_game(void);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* In OS_<whatever>.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
global volatile int screen_width, status_width;
|
||||
global int screen_height;
|
||||
global volatile int curr_x;
|
||||
|
||||
extern void init_interface();
|
||||
extern void start_interface(fc_type fc);
|
||||
extern char *agt_input(int in_type); /* read line, return malloc'd string */
|
||||
extern char agt_getkey(rbool echo_char);
|
||||
extern void agt_clrscr(void);
|
||||
extern void agt_textcolor(int c);
|
||||
extern void agt_delay(int n); /* n in seconds */
|
||||
extern int agt_rand(int a, int b); /* Return random number from a to b, inclusive */
|
||||
extern void agt_newline(void);
|
||||
extern void agt_puts(const char *s); /* Output string */
|
||||
extern void agt_statline(const char *s); /* Prints s out on status line */
|
||||
extern void agt_tone(int hz, int ms);
|
||||
extern void agt_makebox(int width, int height, unsigned long flags);
|
||||
extern void agt_qnewline(void);
|
||||
extern void agt_endbox(void);
|
||||
extern genfile agt_globalfile(int fid); /* When fid=0, return global config file */
|
||||
extern rbool agt_option(int optnum, char *optstr[], rbool setflag);
|
||||
|
||||
/* These have stubs defined in interface.c that would need to be
|
||||
commented out if you actually wanted to support these */
|
||||
extern void fontcmd(int cmd, int font); /* fontlist[font] */
|
||||
extern void pictcmd(int cmd, int pict); /* pictlist[pict] or pixlist[pict] */
|
||||
extern int musiccmd(int cmd, int song); /* songlist[song] */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* In INTERFACE.C */
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* init_interface() (in os_?????.c) is responsible for initializing these */
|
||||
global rbool par_fill_on, center_on;
|
||||
global rbool textbold; /* Is the text currently bold? */
|
||||
|
||||
extern void wait_return(void);
|
||||
extern void agt_waitkey(void);
|
||||
|
||||
extern void agt_center(rbool b); /* 1=turn on text centering, 0=turn off */
|
||||
extern void agt_par(rbool b); /* 1=turn on "paragraph" mode, 0=turn off */
|
||||
extern char *agt_readline(int in_type); /* Front end for agt_input */
|
||||
extern char agt_getchar(void); /* Front end for some uses of agt_getkey */
|
||||
extern void prompt_out(int); /* 1=standard prompt, 2=question prompt */
|
||||
extern genfile get_user_file(int ft); /* 0=script, 1=save, 2=restore */
|
||||
extern void set_default_filenames(fc_type fc);
|
||||
extern void script(uchar); /* 0=turn off, 1=turn on */
|
||||
extern void logon(void); /* Turn on logging */
|
||||
extern int close_pfile(genfile f, int ft); /* ft is the same as for get_user_file */
|
||||
extern void replay(int delay); /* REPLAY */
|
||||
extern rbool yesno(const char *);
|
||||
extern void textbox(char *(txt[]), int len, unsigned long flags);
|
||||
extern void padout(int padleng); /* Outputs padleng spaces */
|
||||
extern int agt_menu(const char *header, int size, int width, menuentry *menu);
|
||||
extern fc_type new_game(void);
|
||||
|
||||
extern void set_test_mode(fc_type fc);
|
||||
/* This sets up scripting and replaying for testing mode */
|
||||
|
||||
/* These are intended to be called by the os layer */
|
||||
extern void print_statline(void);
|
||||
|
||||
extern void agt_save(void);
|
||||
extern void agt_restore(void);
|
||||
extern void agt_restart(void);
|
||||
extern void agt_quit(void);
|
||||
extern void agt_newgame(fc_type fc);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Object manipulation macros */
|
||||
/* -------------------------------------------------------------------- */
|
||||
#define objloop(i) for(i=first_noun; i<=maxnoun || i<=maxcreat; \
|
||||
(i<=maxnoun || i>=first_creat) ? (i++) : (i=first_creat) )
|
||||
#define nounloop(i) for(i=0;i<=maxnoun-first_noun;i++)
|
||||
#define creatloop(i) for(i=0;i<=maxcreat-first_creat;i++)
|
||||
|
||||
#define tdoor(x) ((x)==-ext_code[wdoor])
|
||||
|
||||
#ifdef uagt_defined_global
|
||||
#undef global
|
||||
#undef uagt_define_global
|
||||
#endif
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
1154
engines/glk/agt/metacommand.cpp
Normal file
1154
engines/glk/agt/metacommand.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1063
engines/glk/agt/object.cpp
Normal file
1063
engines/glk/agt/object.cpp
Normal file
File diff suppressed because it is too large
Load Diff
5872
engines/glk/agt/os_glk.cpp
Normal file
5872
engines/glk/agt/os_glk.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1622
engines/glk/agt/parser.cpp
Normal file
1622
engines/glk/agt/parser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1673
engines/glk/agt/runverb.cpp
Normal file
1673
engines/glk/agt/runverb.cpp
Normal file
File diff suppressed because it is too large
Load Diff
428
engines/glk/agt/savegame.cpp
Normal file
428
engines/glk/agt/savegame.cpp
Normal file
@@ -0,0 +1,428 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "glk/agt/agility.h"
|
||||
#include "glk/agt/interp.h"
|
||||
#include "glk/agt/exec.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
#define SAVE_UNDO
|
||||
#define DEBUG_SAVE_SIZE 0
|
||||
|
||||
long state_size;
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
/* INITIALISATION ROUTINES */
|
||||
/* These initialize all of the values that can be derived from */
|
||||
/* other data in the game file or that are reset when a game */
|
||||
/* is restored */
|
||||
/* See parser.c for the interpreter's main initialisation routines */
|
||||
|
||||
void init_vals(void)
|
||||
/* Compute quantities that can be deduced from existing data */
|
||||
{
|
||||
int i;
|
||||
|
||||
quitflag = winflag = deadflag = endflag = 0;
|
||||
cmd_saveable = 0;
|
||||
last_he = last_she = last_it = 0;
|
||||
totwt = totsize = 0;
|
||||
for (i = 0; i <= maxroom - first_room; i++)
|
||||
room[i].contents = 0;
|
||||
player_contents = player_worn = 0;
|
||||
for (i = 0; i <= maxnoun - first_noun; i++) {
|
||||
if (player_has(i + first_noun)) totwt += noun[i].weight;
|
||||
if (noun[i].location == 1) totsize += noun[i].size;
|
||||
noun[i].something_pos_near_noun = 0;
|
||||
noun[i].contents = noun[i].next = 0;
|
||||
}
|
||||
for (i = 0; i <= maxcreat - first_creat; i++)
|
||||
creature[i].contents = creature[i].next = 0;
|
||||
for (i = 0; i <= maxnoun - first_noun; i++) {
|
||||
add_object(noun[i].location, i + first_noun);
|
||||
if (noun[i].nearby_noun >= first_noun &&
|
||||
noun[i].nearby_noun <= maxnoun)
|
||||
noun[noun[i].nearby_noun - first_noun].something_pos_near_noun = 1;
|
||||
}
|
||||
for (i = 0; i <= maxcreat - first_creat; i++)
|
||||
add_object(creature[i].location, i + first_creat);
|
||||
objscore = 0; /* Will need to recompute this ... */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
/* ROUTINES TO SAVE/RESTORE THE GAME STATE */
|
||||
/* These are used by RESTART and UNDO as well as SAVE and RESTORE */
|
||||
|
||||
/* Game State format: */
|
||||
/* The first two bytes indicate the length of the block (unsigned).*/
|
||||
/* The next two bytes indicate the game file somehow (so we don't try to */
|
||||
/* restore to a different game). */
|
||||
/* After this comes the game information itself. */
|
||||
/* All values are still little-endian (that is, LSB first) */
|
||||
|
||||
/* These are the macros for writing game information to the state block */
|
||||
/* There is no difference between signed and unsigned when storing them;
|
||||
there will be problems when recovering them again. */
|
||||
|
||||
#define g(ft,var) {ft,DT_DEFAULT,&var,0}
|
||||
#define r(ft,str,f) {ft,DT_DEFAULT,NULL,offsetof(str,f)}
|
||||
#define dptype {FT_DESCPTR,DT_DESCPTR,NULL,0}
|
||||
|
||||
static file_info fi_savehead[] = {
|
||||
g(FT_INT16, loc), g(FT_INT32, tscore), g(FT_INT16, turncnt),
|
||||
g(FT_BYTE, statusmode),
|
||||
g(FT_BOOL, first_visit_flag), g(FT_BOOL, newlife_flag),
|
||||
g(FT_BOOL, room_firstdesc), g(FT_BOOL, verboseflag),
|
||||
g(FT_BOOL, notify_flag), g(FT_BOOL, listexit_flag),
|
||||
g(FT_BOOL, menu_mode), g(FT_BOOL, sound_on),
|
||||
g(FT_BOOL, agt_answer), g(FT_INT32, agt_number),
|
||||
g(FT_INT16, curr_time), g(FT_INT16, curr_lives),
|
||||
g(FT_INT16, delta_time),
|
||||
endrec
|
||||
};
|
||||
|
||||
static file_info fi_saveroom[] = {
|
||||
dptype,
|
||||
r(FT_BOOL, room_rec, seen),
|
||||
r(FT_BOOL, room_rec, locked_door),
|
||||
r(FT_INT16, room_rec, oclass),
|
||||
r(FT_INT16, room_rec, points),
|
||||
r(FT_INT16, room_rec, light),
|
||||
r(FT_PATHARRAY, room_rec, path),
|
||||
r(FT_UINT32, room_rec, flag_noun_bits),
|
||||
endrec
|
||||
};
|
||||
|
||||
static file_info fi_savenoun[] = {
|
||||
dptype,
|
||||
r(FT_INT16, noun_rec, location),
|
||||
r(FT_INT16, noun_rec, nearby_noun),
|
||||
r(FT_INT16, noun_rec, num_shots),
|
||||
r(FT_INT16, noun_rec, initdesc),
|
||||
r(FT_INT16, noun_rec, oclass),
|
||||
r(FT_INT16, noun_rec, points),
|
||||
r(FT_INT16, noun_rec, weight),
|
||||
r(FT_INT16, noun_rec, size),
|
||||
r(FT_BOOL, noun_rec, on),
|
||||
r(FT_BOOL, noun_rec, open),
|
||||
r(FT_BOOL, noun_rec, locked),
|
||||
r(FT_BOOL, noun_rec, movable),
|
||||
r(FT_BOOL, noun_rec, seen),
|
||||
r(FT_WORD, noun_rec, pos_prep),
|
||||
r(FT_WORD, noun_rec, pos_name),
|
||||
endrec
|
||||
};
|
||||
|
||||
static file_info fi_savecreat[] = {
|
||||
dptype,
|
||||
r(FT_INT16, creat_rec, location),
|
||||
r(FT_INT16, creat_rec, counter),
|
||||
r(FT_INT16, creat_rec, timecounter),
|
||||
r(FT_INT16, creat_rec, initdesc),
|
||||
r(FT_INT16, creat_rec, oclass),
|
||||
r(FT_INT16, creat_rec, points),
|
||||
r(FT_BOOL, creat_rec, groupmemb),
|
||||
r(FT_BOOL, creat_rec, hostile),
|
||||
r(FT_BOOL, creat_rec, seen),
|
||||
endrec
|
||||
};
|
||||
|
||||
static file_info fi_saveustr[] = {
|
||||
{FT_TLINE, DT_DEFAULT, nullptr, 0},
|
||||
endrec
|
||||
};
|
||||
|
||||
|
||||
|
||||
uchar *getstate(uchar *gs)
|
||||
/* Returns block containing game state.
|
||||
If gs!=NULL, uses that space as a buffer;
|
||||
if gs==NULL, we malloc a new block and return it */
|
||||
{
|
||||
rbool new_block; /* True if we allocate a new block */
|
||||
long bp;
|
||||
|
||||
if (gs == nullptr) {
|
||||
rm_trap = 0; /* Don't exit on out-of-memory condition */
|
||||
gs = (uchar *)rmalloc(state_size); /* This should be enough. */
|
||||
rm_trap = 1;
|
||||
if (gs == nullptr) /* This is why we set rm_trap to 0 before calling rmalloc */
|
||||
return nullptr;
|
||||
new_block = 1;
|
||||
} else new_block = 0;
|
||||
|
||||
/* First two bytes reserved for block size, which we don't know yet.*/
|
||||
gs[4] = game_sig & 0xFF;
|
||||
gs[5] = (game_sig >> 8) & 0xFF;
|
||||
|
||||
tscore -= objscore; /* Only include "permanent" part of score;
|
||||
objscore we can recompute on RESTORE */
|
||||
|
||||
/* Need to setup here */
|
||||
set_internal_buffer(gs);
|
||||
fi_saveroom[0].ptr = room_ptr;
|
||||
fi_savenoun[0].ptr = noun_ptr;
|
||||
fi_savecreat[0].ptr = creat_ptr;
|
||||
|
||||
bp = 6;
|
||||
bp += write_globalrec(fi_savehead, bp);
|
||||
bp += write_recblock(flag, FT_BYTE, FLAG_NUM + 1, bp);
|
||||
bp += write_recblock(agt_counter, FT_INT16, CNT_NUM + 1, bp);
|
||||
bp += write_recblock(agt_var, FT_INT32, VAR_NUM + 1, bp);
|
||||
bp += write_recarray(room, sizeof(room_rec), rangefix(maxroom - first_room + 1),
|
||||
fi_saveroom, bp);
|
||||
bp += write_recarray(noun, sizeof(noun_rec), rangefix(maxnoun - first_noun + 1),
|
||||
fi_savenoun, bp);
|
||||
bp += write_recarray(creature, sizeof(creat_rec),
|
||||
rangefix(maxcreat - first_creat + 1),
|
||||
fi_savecreat, bp);
|
||||
if (userstr != nullptr)
|
||||
bp += write_recarray(userstr, sizeof(tline), MAX_USTR, fi_saveustr, bp);
|
||||
if (objflag != nullptr)
|
||||
bp += write_recblock(objflag, FT_BYTE, objextsize(0), bp);
|
||||
if (objprop != nullptr)
|
||||
bp += write_recblock(objprop, FT_INT32, objextsize(1), bp);
|
||||
set_internal_buffer(nullptr);
|
||||
gs[0] = bp & 0xFF;
|
||||
gs[1] = (bp >> 8) & 0xFF;
|
||||
gs[2] = (bp >> 16) & 0xFF;
|
||||
gs[3] = (bp >> 24) & 0x7F; /* Don't trust top bit */
|
||||
if (new_block)
|
||||
gs = (uchar *)rrealloc(gs, bp);
|
||||
tscore += objscore;
|
||||
return gs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void putstate(uchar *gs) { /* Restores games state. */
|
||||
long size, bp, numrec, i;
|
||||
|
||||
|
||||
size = gs[0] + (((long)gs[1]) << 8) + (((long)gs[2]) << 16) + (((long)gs[3]) << 24);
|
||||
if (size != state_size) {
|
||||
writeln("Size difference in save files!");
|
||||
agt_delay(3);
|
||||
return;
|
||||
}
|
||||
if (gs[4] + (((long)gs[5]) << 8) != game_sig) {
|
||||
writestr("This appears to be a save file for a different game. Is this"
|
||||
" from an earlier chapter in a multi-part game such as"
|
||||
" Klaustrophobia");
|
||||
if (yesno("?"))
|
||||
skip_descr = 1; /* We don't want to overwrite the descriptions
|
||||
with the pointers from the save file. */
|
||||
else {
|
||||
writestr("Do you want to try using it anyhow (WARNING: This could"
|
||||
" crash the interpreter)");
|
||||
if (!(yesno("?"))) {
|
||||
writeln("Command cancelled!");
|
||||
agt_delay(3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* setup... */
|
||||
set_internal_buffer(gs);
|
||||
fi_saveroom[0].ptr = room_ptr;
|
||||
fi_savenoun[0].ptr = noun_ptr;
|
||||
fi_savecreat[0].ptr = creat_ptr;
|
||||
bp = 6;
|
||||
|
||||
read_globalrec(fi_savehead, nullptr, bp, 0);
|
||||
bp += compute_recsize(fi_savehead);
|
||||
read_recblock(flag, FT_BYTE, FLAG_NUM + 1, bp, 0);
|
||||
bp += ft_leng[FT_BYTE] * (FLAG_NUM + 1);
|
||||
read_recblock(agt_counter, FT_INT16, CNT_NUM + 1, bp, 0);
|
||||
bp += ft_leng[FT_INT16] * (CNT_NUM + 1);
|
||||
read_recblock(agt_var, FT_INT32, VAR_NUM + 1, bp, 0);
|
||||
bp += ft_leng[FT_INT32] * (VAR_NUM + 1);
|
||||
|
||||
numrec = rangefix(maxroom - first_room + 1);
|
||||
read_recarray(room, sizeof(room_rec), numrec, fi_saveroom, nullptr, bp, 0);
|
||||
bp += compute_recsize(fi_saveroom) * numrec;
|
||||
numrec = rangefix(maxnoun - first_noun + 1);
|
||||
read_recarray(noun, sizeof(noun_rec), numrec, fi_savenoun, nullptr, bp, 0);
|
||||
bp += compute_recsize(fi_savenoun) * numrec;
|
||||
numrec = rangefix(maxcreat - first_creat + 1);
|
||||
read_recarray(creature, sizeof(creat_rec), numrec, fi_savecreat, nullptr, bp, 0);
|
||||
bp += compute_recsize(fi_savecreat) * numrec;
|
||||
if (userstr != nullptr) {
|
||||
read_recarray(userstr, sizeof(tline), MAX_USTR, fi_saveustr, nullptr, bp, 0);
|
||||
bp += ft_leng[FT_TLINE] * MAX_USTR;
|
||||
}
|
||||
if (objflag != nullptr) {
|
||||
i = objextsize(0);
|
||||
read_recblock(objflag, FT_BYTE, i, bp, 0);
|
||||
bp += ft_leng[FT_BYTE] * i;
|
||||
}
|
||||
if (objprop != nullptr) {
|
||||
i = objextsize(1);
|
||||
read_recblock(objprop, FT_INT32, i, bp, 0);
|
||||
bp += ft_leng[FT_INT32] * i;
|
||||
}
|
||||
set_internal_buffer(nullptr);
|
||||
|
||||
if (skip_descr) /* Need to "fix" position information. This is a hack. */
|
||||
/* Basically, this sets the position of each object to its default */
|
||||
/* The problem here is that the usual position info is invalid-- we've
|
||||
changed games, and hence dictionaries */
|
||||
for (i = 0; i < maxnoun - first_noun; i++) {
|
||||
if (noun[i].position != nullptr && noun[i].position[0] != 0)
|
||||
noun[i].pos_prep = -1;
|
||||
else noun[i].pos_prep = 0;
|
||||
}
|
||||
else /* Rebuild position information */
|
||||
for (i = 0; i < maxnoun - first_noun; i++)
|
||||
if (noun[i].pos_prep == -1)
|
||||
noun[i].position = noun[i].initpos;
|
||||
else
|
||||
noun[i].position = nullptr;
|
||||
|
||||
init_vals();
|
||||
skip_descr = 0; /* If we set this to 1, restore it to its original state */
|
||||
/* Now do some simple consistancy checking on major variables */
|
||||
if (loc > maxroom || loc < 0 || turncnt < 0 ||
|
||||
curr_lives < 0 || curr_lives > max_lives) {
|
||||
error("Error: Save file inconsistent.");
|
||||
}
|
||||
}
|
||||
|
||||
void init_state_sys(void)
|
||||
/* Initializes the state saving mechanisms */
|
||||
/* Mainly it just computes the size of a state block */
|
||||
{
|
||||
state_size = compute_recsize(fi_savehead)
|
||||
+ compute_recsize(fi_saveroom) * rangefix(maxroom - first_room + 1)
|
||||
+ compute_recsize(fi_savenoun) * rangefix(maxnoun - first_noun + 1)
|
||||
+ compute_recsize(fi_savecreat) * rangefix(maxcreat - first_creat + 1)
|
||||
+ ft_leng[FT_BYTE] * (FLAG_NUM + 1)
|
||||
+ ft_leng[FT_INT16] * (CNT_NUM + 1)
|
||||
+ ft_leng[FT_INT32] * (VAR_NUM + 1)
|
||||
+ ft_leng[FT_BYTE] * objextsize(0)
|
||||
+ ft_leng[FT_INT32] * objextsize(1)
|
||||
+ 6; /* Six bytes in header */
|
||||
if (userstr != nullptr) state_size += ft_leng[FT_TLINE] * MAX_USTR;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
/* SAVE FILE ROUTINES */
|
||||
|
||||
extern Common::Error savegame(Common::WriteStream *savefile) {
|
||||
uchar *gs;
|
||||
long size;
|
||||
|
||||
#ifndef UNDO_SAVE
|
||||
gs = getstate(nullptr);
|
||||
#else
|
||||
gs = undo_state;
|
||||
#endif
|
||||
if (gs == nullptr) {
|
||||
writeln("Insufficiant memory to support SAVE.");
|
||||
return Common::kWritingFailed;
|
||||
}
|
||||
|
||||
if (!filevalid(savefile, fSAV)) {
|
||||
writeln("That is not a valid save file.");
|
||||
return Common::kWritingFailed;
|
||||
}
|
||||
size = gs[0] + (((long)gs[1]) << 8) + (((long)gs[2]) << 16) + (((long)gs[3]) << 24);
|
||||
bool result = binwrite(savefile, gs, size, 1, 0);
|
||||
#ifndef UNDO_SAVE
|
||||
rfree(gs);
|
||||
#endif
|
||||
if (!result) {
|
||||
warning("Error writing save file.");
|
||||
return Common::kWritingFailed;
|
||||
} else {
|
||||
return Common::kNoError;
|
||||
}
|
||||
}
|
||||
|
||||
/* 1=success, 0=failure */
|
||||
Common::Error loadgame(Common::SeekableReadStream *loadfile) {
|
||||
long size;
|
||||
uchar *gs;
|
||||
const char *errstr;
|
||||
|
||||
if (!filevalid(loadfile, fSAV)) {
|
||||
warning("Unable to open file.");
|
||||
return Common::kReadingFailed;
|
||||
}
|
||||
size = binsize(loadfile);
|
||||
if (size == -1) {
|
||||
warning("Could not access file.");
|
||||
return Common::kReadingFailed;
|
||||
}
|
||||
|
||||
gs = (uchar *)rmalloc(size);
|
||||
if (!binread(loadfile, gs, size, 1, &errstr)) {
|
||||
warning("Error reading file.");
|
||||
rfree(gs);
|
||||
return Common::kReadingFailed;
|
||||
}
|
||||
|
||||
if (size != gs[0] + (((long)gs[1]) << 8) + (((long)gs[2]) << 16) + (((long)gs[3]) << 24)) {
|
||||
if (size == gs[0] + (((long)gs[1]) << 8)) {
|
||||
/* Old save file format; patch to look like new format */
|
||||
gs = (uchar *)rrealloc(gs, size + 2);
|
||||
memmove(gs + 4, gs + 2, size - 2);
|
||||
gs[2] = gs[3] = 0;
|
||||
} else {
|
||||
warning("Save file corrupted or invalid.");
|
||||
rfree(gs);
|
||||
return Common::kReadingFailed;
|
||||
}
|
||||
}
|
||||
|
||||
putstate(gs);
|
||||
rfree(gs);
|
||||
set_statline();
|
||||
look_room();
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void restart_game(void) {
|
||||
putstate(restart_state);
|
||||
reset_random();
|
||||
agt_clrscr();
|
||||
set_statline();
|
||||
do_look = do_autoverb = 1;
|
||||
if (intro_ptr.size > 0) {
|
||||
print_descr(intro_ptr, 1);
|
||||
wait_return();
|
||||
agt_clrscr();
|
||||
}
|
||||
newroom();
|
||||
}
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
1177
engines/glk/agt/token.cpp
Normal file
1177
engines/glk/agt/token.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1475
engines/glk/agt/util.cpp
Normal file
1475
engines/glk/agt/util.cpp
Normal file
File diff suppressed because it is too large
Load Diff
208
engines/glk/agt/vars.cpp
Normal file
208
engines/glk/agt/vars.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/agt/agility.h"
|
||||
#include "glk/agt/interp.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace AGT {
|
||||
|
||||
uchar DIAG, interp_arg, debug_da1, RAW_CMD_OUT;
|
||||
int ERR_LEVEL;
|
||||
|
||||
rbool agx_file;
|
||||
rbool have_opt;
|
||||
rbool skip_descr;
|
||||
rbool no_auxsyn;
|
||||
rbool BATCH_MODE, make_test;
|
||||
rbool have_meta;
|
||||
rbool debug_mode, freeze_mode, milltime_mode, bold_mode;
|
||||
uchar score_mode, statusmode;
|
||||
rbool intro_first;
|
||||
rbool box_title;
|
||||
rbool mars_fix;
|
||||
rbool fix_ascii_flag;
|
||||
rbool dbg_nomsg;
|
||||
rbool irun_mode;
|
||||
rbool verboseflag;
|
||||
int font_status;
|
||||
|
||||
rbool MASTERS_OR;
|
||||
integer FLAG_NUM, CNT_NUM, VAR_NUM;
|
||||
integer MAX_USTR;
|
||||
integer MAX_SUB;
|
||||
integer DVERB;
|
||||
integer NUM_ERR;
|
||||
integer num_rflags, num_nflags, num_cflags;
|
||||
integer num_rprops, num_nprops, num_cprops;
|
||||
integer oprop_cnt, oflag_cnt;
|
||||
integer maxroom, maxnoun, maxcreat;
|
||||
long MaxQuestion;
|
||||
integer first_room, first_noun, first_creat, last_obj;
|
||||
long last_message, last_cmd;
|
||||
long numglobal;
|
||||
long maxpict, maxpix, maxfont, maxsong;
|
||||
long num_prep;
|
||||
int num_auxcomb;
|
||||
int num_comb;
|
||||
integer exitmsg_base;
|
||||
integer start_room, treas_room, resurrect_room, max_lives;
|
||||
long max_score;
|
||||
integer startup_time, delta_time;
|
||||
int ver, aver;
|
||||
long game_sig;
|
||||
int vm_size;
|
||||
int min_ver;
|
||||
room_rec *room;
|
||||
creat_rec *creature;
|
||||
noun_rec *noun;
|
||||
cmd_rec *command;
|
||||
unsigned char *objflag;
|
||||
long *objprop;
|
||||
attrdef_rec *attrtable;
|
||||
propdef_rec *proptable;
|
||||
vardef_rec *vartable;
|
||||
flagdef_rec *flagtable;
|
||||
const char **propstr;
|
||||
long propstr_size;
|
||||
tline *userstr;
|
||||
word *sub_name;
|
||||
verbentry_rec *verbinfo;
|
||||
short *verbptr, *verbend;
|
||||
slist *synlist;
|
||||
slist *comblist;
|
||||
word *old_agt_verb;
|
||||
slist *userprep;
|
||||
word flag_noun[MAX_FLAG_NOUN], *globalnoun;
|
||||
word pix_name[MAX_PIX];
|
||||
filename *pictlist, *pixlist, *fontlist, *songlist;
|
||||
uchar opt_data[14];
|
||||
slist *auxsyn;
|
||||
slist *preplist;
|
||||
uchar *verbflag;
|
||||
slist *auxcomb;
|
||||
|
||||
#ifdef PATH_SEP
|
||||
char **gamepath;
|
||||
#endif
|
||||
|
||||
rbool stable_random;
|
||||
rbool DEBUG_MEM;
|
||||
rbool debug_parse;
|
||||
rbool DEBUG_EXEC_VERB;
|
||||
rbool DEBUG_DISAMBIG;
|
||||
rbool DEBUG_SMSG;
|
||||
rbool debug_disambig, debug_any;
|
||||
rbool DEBUG_OUT;
|
||||
Common::DumpFile *debugfile;
|
||||
|
||||
rbool notify_flag, listexit_flag, menu_mode;
|
||||
rbool cmd_saveable;
|
||||
rbool can_undo;
|
||||
uchar *restart_state, *undo_state;
|
||||
char doing_restore;
|
||||
rbool do_look;
|
||||
rbool do_autoverb;
|
||||
rbool script_on;
|
||||
genfile scriptfile;
|
||||
signed char logflag;
|
||||
int logdelay;
|
||||
genfile log_in, log_out;
|
||||
rbool fast_replay;
|
||||
rbool sound_on;
|
||||
integer *pictable;
|
||||
fc_type hold_fc;
|
||||
unsigned short compass_rose;
|
||||
|
||||
rbool quitflag, deadflag, winflag, endflag;
|
||||
rbool first_visit_flag, newlife_flag, room_firstdesc;
|
||||
rbool start_of_turn;
|
||||
rbool end_of_turn;
|
||||
rbool actor_in_scope;
|
||||
integer loc;
|
||||
integer player_contents, player_worn;
|
||||
long totwt, totsize;
|
||||
integer curr_lives;
|
||||
long tscore, old_score;
|
||||
long objscore;
|
||||
integer turncnt;
|
||||
integer curr_time;
|
||||
rbool *flag;
|
||||
short *agt_counter;
|
||||
|
||||
#ifdef AGT_16BIT
|
||||
short *agt_var;
|
||||
#else
|
||||
long *agt_var;
|
||||
#endif
|
||||
|
||||
long agt_number;
|
||||
rbool agt_answer;
|
||||
tline l_stat, r_stat;
|
||||
rbool nomatch_aware;
|
||||
rbool smart_look;
|
||||
int vm_width;
|
||||
menuentry *verbmenu;
|
||||
|
||||
int vb;
|
||||
integer actor, dobj, iobj;
|
||||
parse_rec *actor_rec, *dobj_rec, *iobj_rec;
|
||||
word prep;
|
||||
parse_rec *curr_creat_rec;
|
||||
int disambig_score;
|
||||
word input[MAXINPUT];
|
||||
words in_text[MAXINPUT];
|
||||
short ip, ep;
|
||||
short ap, vp, np, pp, op;
|
||||
word ext_code[wabout + 1];
|
||||
short last_he, last_she, last_it, last_they;
|
||||
|
||||
volatile int screen_width, status_width;
|
||||
int screen_height;
|
||||
volatile int curr_x;
|
||||
rbool par_fill_on, center_on;
|
||||
rbool textbold;
|
||||
|
||||
uchar trans_ascii[256];
|
||||
rbool rm_acct;
|
||||
long rfree_cnt, ralloc_cnt;
|
||||
long rm_size, rm_freesize;
|
||||
words *verblist;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
|
||||
uchar do_disambig;
|
||||
rbool beforecmd;
|
||||
rbool suppress_debug;
|
||||
rbool was_metaverb;
|
||||
integer oldloc;
|
||||
integer subcall_arg;
|
||||
integer *creat_fix;
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
|
||||
rbool *dbgflagptr;
|
||||
long *dbgvarptr;
|
||||
short *dbgcntptr;
|
||||
rbool PURE_DOT;
|
||||
|
||||
} // End of namespace AGT
|
||||
} // End of namespace Glk
|
||||
Reference in New Issue
Block a user