mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
331 lines
11 KiB
C++
331 lines
11 KiB
C++
/* 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/hugo/hugo.h"
|
|
#include "glk/hugo/resource_archive.h"
|
|
#include "common/config-manager.h"
|
|
#include "common/translation.h"
|
|
|
|
namespace Glk {
|
|
namespace Hugo {
|
|
|
|
Hugo *g_vm;
|
|
|
|
Hugo::Hugo(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
|
|
mainwin(nullptr), currentwin(nullptr), secondwin(nullptr), auxwin(nullptr),
|
|
runtime_warnings(false), dbnest(0), address_scale(16),
|
|
SCREENWIDTH(0), SCREENHEIGHT(0), FIXEDCHARWIDTH(0), FIXEDLINEHEIGHT(0),
|
|
// heexpr
|
|
evalcount(0), incdec(0), getaddress(0), inexpr(0), inobj(0), last_precedence(0),
|
|
// hemedia
|
|
mchannel(nullptr), schannel(nullptr),
|
|
// hemisc
|
|
game_version(0), object_size(24), game(nullptr), script(nullptr),
|
|
playback(nullptr), record(nullptr), io(nullptr), ioblock('\0'), ioerror('\0'),
|
|
codestart(0), objtable(0), eventtable(0), proptable(0), arraytable(0), dicttable(0),
|
|
syntable(0), initaddr(0), mainaddr(0), parseaddr(0), parseerroraddr(0),
|
|
findobjectaddr(0), endgameaddr(0), speaktoaddr(0), performaddr(0),
|
|
objects(0), events(0), dictcount(0), syncount(0), mem(nullptr), loaded_in_memory(true),
|
|
defseg(0), gameseg(0), codeptr(0), codeend(0), currentpos(0), currentline(0), full(0),
|
|
def_fcolor(0), def_bgcolor(0), def_slfcolor(0), def_slbgcolor(0), fcolor(0), bgcolor(0),
|
|
icolor(0), default_bgcolor(0), currentfont(0), capital(0), textto(0),
|
|
physical_windowwidth(0), physical_windowheight(0), physical_windowtop(0),
|
|
physical_windowleft(0), physical_windowbottom(0), physical_windowright(0),
|
|
inwindow(0), charwidth(0), lineheight(0), current_text_x(0), current_text_y(0),
|
|
skipping_more(false), undoptr(0), undoturn(0), undoinvalid(0), undorecord(0),
|
|
context_commands(0), in_valid_window(false), glk_fcolor(DEF_FCOLOR), glk_bgcolor(DEF_BGCOLOR),
|
|
mainwin_bgcolor(0), glk_current_font(0), just_cleared_screen(false), secondwin_bottom(0),
|
|
// heobject
|
|
display_object(-1), display_needs_repaint(0), display_pointer_x(0), display_pointer_y(0),
|
|
// heparse
|
|
words(0), parsed_number(0), remaining(0), xverb(0), starts_with_verb(0),
|
|
grammaraddr(0), obj_parselist(nullptr), domain(0), odomain(0), objcount(0),
|
|
parse_allflag(false), pobjcount(0), pobj(0), obj_match_state(0), object_is_number(0),
|
|
objgrammar(0), objstart(0), objfinish(0), addflag(false), speaking(0), oopscount(0),
|
|
parse_called_twice(0), reparse_everything(0), full_buffer(0), recursive_call(false),
|
|
parse_location(0),
|
|
// heres
|
|
resource_file(nullptr), extra_param(0), resource_type(0),
|
|
// herun
|
|
arguments_passed(0), ret(0), retflag(0), during_player_input(false), override_full(0),
|
|
game_reset(false), stack_depth(0), tail_recursion(0), tail_recursion_addr(0),
|
|
last_window_top(0), last_window_bottom(0), last_window_left(0), last_window_right(0),
|
|
lowest_windowbottom(0), physical_lowest_windowbottom(0), just_left_window(false),
|
|
// heset
|
|
arrexpr(0), multiprop(0), set_value(0)
|
|
#if defined (DEBUGGER)
|
|
, debug_eval(false), debug_eval_error(false), debugger_step_over(false),
|
|
debugger_finish(false), debugger_run(false), debugger_interrupt(false),
|
|
debugger_skip(false), runtime_error(false), currentroutine(false),
|
|
complex_prop_breakpoint(false), trace_complex_prop_routine(false), routines(0),
|
|
properties(0), current_locals(0), this_codeptr(0), debug_workspace(0), attributes(0),
|
|
original_dictcount(0), buffered_code_lines(0), debugger_has_stepped_back(false),
|
|
debugger_step_back(false), debugger_collapsing(0), runaway_counter(0), history_count(0),
|
|
active_screen(0), step_nest(0), history_last(0)
|
|
#endif
|
|
{
|
|
g_vm = this;
|
|
gamefile[0] = '\0';
|
|
|
|
// heexpr
|
|
Common::fill(&eval[0], &eval[MAX_EVAL_ELEMENTS], 0);
|
|
Common::fill(&var[0], &var[MAXLOCALS + MAXGLOBALS], 0);
|
|
|
|
// hemedia
|
|
Common::fill(&resids[0][0], &resids[1][MAXRES], 0);
|
|
numres[0] = numres[1] = 0;
|
|
|
|
// hemisc
|
|
Common::fill(&context_command[0][0], &context_command[MAX_CONTEXT_COMMANDS - 1][64], 0);
|
|
Common::fill(&id[0], &id[3], '\0');
|
|
Common::fill(&serial[0], &serial[9], '\0');
|
|
Common::fill(&pbuffer[0], &pbuffer[MAXBUFFER * 2 + 1], 0);
|
|
Common::fill(&undostack[0][0], &undostack[MAXUNDO - 1][5], 0);
|
|
|
|
// heparse
|
|
Common::fill(&buffer[0], &buffer[MAXBUFFER + MAXWORDS], '\0');
|
|
Common::fill(&errbuf[0], &errbuf[MAXBUFFER + 1], 0);
|
|
Common::fill(&line[0], &line[1025], 0);
|
|
Common::fill(&word[0], &word[MAXWORDS + 1], (char *)nullptr);
|
|
Common::fill(&wd[0], &wd[MAXWORDS + 1], 0);
|
|
Common::fill(&parseerr[0], &parseerr[MAXBUFFER + 1], '\0');
|
|
Common::fill(&parsestr[0], &parsestr[MAXBUFFER + 1], '\0');
|
|
Common::fill(&objlist[0], &objlist[MAXOBJLIST], 0);
|
|
Common::fill(&objword_cache[0], &objword_cache[MAXWORDS], 0);
|
|
Common::fill(&oops[0], &oops[MAXBUFFER + 1], '\0');
|
|
Common::fill(&punc_string[0], &punc_string[64], '\0');
|
|
|
|
// heres
|
|
Common::fill(&loaded_filename[0], &loaded_filename[MAX_RES_PATH], '\0');
|
|
Common::fill(&loaded_resname[0], &loaded_resname[MAX_RES_PATH], '\0');
|
|
|
|
// herun
|
|
Common::fill(&passlocal[0], &passlocal[MAXLOCALS], 0);
|
|
|
|
// heset
|
|
game_title[0] = '\0';
|
|
|
|
// Miscellaneous
|
|
_savegameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
|
|
|
|
#ifdef DEBUGGER
|
|
debug_line[0] = '\0';
|
|
Common::fill(&objectname[0], &objectname[MAX_OBJECT], (char *)nullptr);
|
|
Common::fill(&propertyname[0], &propertyname[MAX_PROPERTY], (char *)nullptr);
|
|
Common::fill(&codeline[0][0], &codeline[9][0], 0);
|
|
Common::fill(&localname[0][0], &localname[9][0], 0);
|
|
Common::fill(&code_history[0], &code_history[MAX_CODE_HISTORY], 0);
|
|
Common::fill(&dbnest_history[0], &dbnest_history[MAX_CODE_HISTORY], 0);
|
|
#endif
|
|
}
|
|
|
|
Hugo::~Hugo() {
|
|
g_vm = nullptr;
|
|
}
|
|
|
|
void Hugo::runGame() {
|
|
hugo_init_screen();
|
|
|
|
SetupDisplay();
|
|
|
|
Common::strcpy_s(gamefile, getFilename().c_str());
|
|
pbuffer[0] = '\0';
|
|
|
|
ResourceArchive *res = new ResourceArchive();
|
|
SearchMan.add("Resources", res);
|
|
|
|
gameseg = 0;
|
|
|
|
LoadGame();
|
|
|
|
playGame();
|
|
|
|
hugo_cleanup_screen();
|
|
|
|
hugo_blockfree(mem);
|
|
mem = nullptr;
|
|
hugo_closefiles();
|
|
}
|
|
|
|
Common::Error Hugo::readSaveData(Common::SeekableReadStream *rs) {
|
|
char testid[3], testserial[9];
|
|
int lbyte, hbyte;
|
|
int j;
|
|
unsigned int k, undosize;
|
|
long i;
|
|
|
|
/* Check ID */
|
|
testid[0] = (char)hugo_fgetc(rs);
|
|
testid[1] = (char)hugo_fgetc(rs);
|
|
testid[2] = '\0';
|
|
if (hugo_ferror(rs)) goto RestoreError;
|
|
|
|
if (strcmp(testid, id)) {
|
|
GUIErrorMessage(_("Incorrect rs file."));
|
|
goto RestoreError;
|
|
}
|
|
|
|
/* Check serial number */
|
|
if (!hugo_fgets(testserial, 9, rs)) goto RestoreError;
|
|
if (strcmp(testserial, serial)) {
|
|
GUIErrorMessage(_("Save file created by different version."));
|
|
goto RestoreError;
|
|
}
|
|
|
|
/* Restore variables */
|
|
for (k = 0; k<MAXGLOBALS + MAXLOCALS; k++) {
|
|
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF)
|
|
goto RestoreError;
|
|
var[k] = lbyte + hbyte * 256;
|
|
}
|
|
|
|
/* Restore objtable and above */
|
|
|
|
if (hugo_fseek(game, objtable*16L, SEEK_SET)) goto RestoreError;
|
|
i = 0;
|
|
|
|
while (i<codeend-(long)(objtable*16L)) {
|
|
if ((hbyte = hugo_fgetc(rs))==EOF && hugo_ferror(rs)) goto RestoreError;
|
|
|
|
if (hbyte == 0) {
|
|
if ((lbyte = hugo_fgetc(rs))==EOF && hugo_ferror(rs)) goto RestoreError;
|
|
SETMEM(objtable*16L+i, (unsigned char)lbyte);
|
|
i++;
|
|
|
|
/* Skip byte in game file */
|
|
if (hugo_fgetc(game)==EOF) goto RestoreError;
|
|
} else {
|
|
while (hbyte--) {
|
|
/* Get unchanged game file byte */
|
|
if ((lbyte = hugo_fgetc(game))==EOF) goto RestoreError;
|
|
SETMEM(objtable*16L+i, (unsigned char)lbyte);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Restore undo data */
|
|
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF)
|
|
goto RestoreError;
|
|
undosize = lbyte + hbyte*256;
|
|
|
|
/* We can only restore undo data if it was saved by a port with
|
|
the same MAXUNDO as us */
|
|
if (undosize == MAXUNDO) {
|
|
for (k = 0; k < MAXUNDO; k++) {
|
|
for (j=0; j<5; j++) {
|
|
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF)
|
|
goto RestoreError;
|
|
undostack[k][j] = lbyte + hbyte*256;
|
|
}
|
|
}
|
|
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF) goto RestoreError;
|
|
undoptr = lbyte + hbyte*256;
|
|
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF) goto RestoreError;
|
|
undoturn = lbyte + hbyte*256;
|
|
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF) goto RestoreError;
|
|
undoinvalid = (unsigned char)lbyte, undorecord = (unsigned char)hbyte;
|
|
}
|
|
else undoinvalid = true;
|
|
|
|
return Common::kNoError;
|
|
|
|
RestoreError:
|
|
return Common::kReadingFailed;
|
|
}
|
|
|
|
Common::Error Hugo::writeGameData(Common::WriteStream *ws) {
|
|
int c, j;
|
|
int lbyte, hbyte;
|
|
long i;
|
|
int samecount = 0;
|
|
|
|
/* Write ID */
|
|
if (hugo_fputc(id[0], ws) == EOF || hugo_fputc(id[1], ws) == EOF) goto SaveError;
|
|
|
|
/* Write serial number */
|
|
if (hugo_fputs(serial, ws) == EOF) goto SaveError;
|
|
|
|
/* Save variables */
|
|
for (c = 0; c<MAXGLOBALS + MAXLOCALS; c++) {
|
|
hbyte = (unsigned int)var[c] / 256;
|
|
lbyte = (unsigned int)var[c] - hbyte * 256;
|
|
if (hugo_fputc(lbyte, ws) == EOF || hugo_fputc(hbyte, ws) == EOF) goto SaveError;
|
|
}
|
|
|
|
/* Save objtable to end of code space */
|
|
|
|
if (hugo_fseek(game, objtable * 16L, SEEK_SET)) goto SaveError;
|
|
|
|
for (i = 0; i <= codeend - (long)(objtable * 16L); i++) {
|
|
if ((lbyte = hugo_fgetc(game)) == EOF) goto SaveError;
|
|
hbyte = MEM(objtable * 16L + i);
|
|
|
|
/* If memory same as original game file */
|
|
if (lbyte == hbyte && samecount < 255)
|
|
samecount++;
|
|
|
|
/* If memory differs (or samecount exceeds 1 byte) */
|
|
else {
|
|
if (samecount)
|
|
if (hugo_fputc(samecount, ws) == EOF) goto SaveError;
|
|
|
|
if (lbyte != hbyte) {
|
|
if (hugo_fputc(0, ws) == EOF) goto SaveError;
|
|
if (hugo_fputc(hbyte, ws) == EOF) goto SaveError;
|
|
samecount = 0;
|
|
}
|
|
else samecount = 1;
|
|
}
|
|
}
|
|
if (samecount)
|
|
if (hugo_fputc(samecount, ws) == EOF) goto SaveError;
|
|
|
|
/* Save undo data */
|
|
|
|
/* Save the number of turns in this port's undo stack */
|
|
hbyte = (unsigned int)MAXUNDO / 256;
|
|
lbyte = (unsigned int)MAXUNDO - hbyte * 256;
|
|
if (hugo_fputc(lbyte, ws) == EOF || hugo_fputc(hbyte, ws) == EOF)
|
|
goto SaveError;
|
|
for (c = 0; c < MAXUNDO; c++) {
|
|
for (j = 0; j < 5; j++) {
|
|
hbyte = (unsigned int)undostack[c][j] / 256;
|
|
lbyte = (unsigned int)undostack[c][j] - hbyte * 256;
|
|
if (hugo_fputc(lbyte, ws) == EOF || hugo_fputc(hbyte, ws) == EOF)
|
|
goto SaveError;
|
|
}
|
|
}
|
|
if (hugo_fputc(undoptr - (undoptr / 256) * 256, ws) == EOF || hugo_fputc(undoptr / 256, ws) == EOF)
|
|
goto SaveError;
|
|
if (hugo_fputc(undoturn - (undoturn / 256) * 256, ws) == EOF || hugo_fputc(undoturn / 256, ws) == EOF)
|
|
goto SaveError;
|
|
if (hugo_fputc(undoinvalid, ws) == EOF || hugo_fputc(undorecord, ws) == EOF)
|
|
goto SaveError;
|
|
|
|
return Common::kNoError;
|
|
|
|
SaveError:
|
|
return Common::kWritingFailed;
|
|
}
|
|
|
|
} // End of namespace Hugo
|
|
} // End of namespace Glk
|