Files
scummvm-cursorfix/engines/glk/hugo/hugo.h
2026-02-02 04:50:13 +01:00

1218 lines
31 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/>.
*
*/
/* Based on the Hugo interpreter version 3.3.0 */
#ifndef GLK_HUGO_HUGO
#define GLK_HUGO_HUGO
#include "common/scummsys.h"
#include "common/str.h"
#include "glk/glk_api.h"
#include "glk/hugo/htokens.h"
#include "glk/hugo/hugo_defines.h"
#include "glk/hugo/hugo_types.h"
#include "glk/hugo/stringfn.h"
namespace Glk {
namespace Hugo {
class ResourceArchive;
/**
* Hugo game interpreter
*/
class Hugo : public GlkAPI, public HTokens, public StringFunctions {
friend class ResourceArchive;
private:
int _savegameSlot;
winid_t mainwin, currentwin;
winid_t secondwin, auxwin;
bool runtime_warnings;
int dbnest;
/**
* address_scale refers to the factor by which addresses are multiplied to
* get the "real" address. In this way, a 16-bit integer can reference
* 64K * 16 = 1024K of memory.
*/
int address_scale;
// heexpr
int eval[MAX_EVAL_ELEMENTS]; ///< expression components
int evalcount; ///< # of expr. components
int var[MAXLOCALS + MAXGLOBALS]; ///< variables
int incdec; ///< value is being incremented/dec.
char getaddress; ///< true when finding &routine
char inexpr; ///< true when in expression
char inobj; ///< true when in object compound
int last_precedence;
// hemedia
schanid_t mchannel;
schanid_t schannel;
long resids[2][MAXRES];
int numres[2];
// hemisc
char gamefile[255];
int game_version;
int object_size;
Common::SeekableReadStream *game;
HUGO_FILE script;
HUGO_FILE playback;
HUGO_FILE record;
HUGO_FILE io; char ioblock; char ioerror;
char id[3];
char serial[9];
unsigned int codestart;
unsigned int objtable;
unsigned int eventtable;
unsigned int proptable;
unsigned int arraytable;
unsigned int dicttable;
unsigned int syntable;
unsigned int initaddr;
unsigned int mainaddr;
unsigned int parseaddr;
unsigned int parseerroraddr;
unsigned int findobjectaddr;
unsigned int endgameaddr;
unsigned int speaktoaddr;
unsigned int performaddr;
int objects;
int events;
int dictcount;
int syncount;
char context_command[MAX_CONTEXT_COMMANDS][64];
int context_commands;
unsigned char *mem;
bool loaded_in_memory;
unsigned int defseg;
unsigned int gameseg;
long codeptr;
long codeend;
char pbuffer[MAXBUFFER * 2 + 1];
int currentpos;
int currentline;
int full;
signed char def_fcolor, def_bgcolor, def_slfcolor, def_slbgcolor;
signed char fcolor, bgcolor, icolor, default_bgcolor;
int currentfont;
char capital;
unsigned int textto;
int SCREENWIDTH, SCREENHEIGHT;
int physical_windowwidth, physical_windowheight,
physical_windowtop, physical_windowleft,
physical_windowbottom, physical_windowright;
int inwindow;
int charwidth, lineheight, FIXEDCHARWIDTH, FIXEDLINEHEIGHT;
int current_text_x, current_text_y;
bool skipping_more;
int undostack[MAXUNDO][5];
int undoptr;
int undoturn;
char undoinvalid;
char undorecord;
bool in_valid_window;
int glk_fcolor, glk_bgcolor;
int mainwin_bgcolor;
int glk_current_font;
bool just_cleared_screen;
int secondwin_bottom;
// heobject
int display_object; ///< i.e., non-existent (yet)
char display_needs_repaint; ///< for display object
int display_pointer_x, display_pointer_y;
// heparse
char buffer[MAXBUFFER + MAXWORDS];
char errbuf[MAXBUFFER + 1]; ///< last invalid input
char line[1025]; ///< line buffer
int words; ///< parsed word count
char *word[MAXWORDS + 1]; ///< breakdown into words
unsigned int wd[MAXWORDS + 1]; ///< " " dict. entries
unsigned int parsed_number; ///< needed for numbers in input
signed char remaining; ///< multiple commands in input
char parseerr[MAXBUFFER + 1]; ///< for passing to RunPrint, etc.
char parsestr[MAXBUFFER + 1]; ///< for passing quoted string
char xverb; ///< flag; 0 = regular verb
char starts_with_verb; ///< input line; 0 = no verb word
unsigned int grammaraddr; ///< address in grammar
char *obj_parselist; ///< objects with noun/adjective
int domain, odomain; ///< of object(s)
int objlist[MAXOBJLIST]; ///< for objects of verb
char objcount; ///< of objlist
char parse_allflag; ///< for "all" in MatchObject
pobject_structure pobjlist[MAXPOBJECTS]; ///< for possible objects
int pobjcount; ///< of pobjlist
int pobj; ///< last remaining suspect
int obj_match_state; ///< see MatchCommand() for details
char objword_cache[MAXWORDS]; ///< for MatchWord() xobject, etc.
char object_is_number; ///< number used in player command
unsigned int objgrammar; ///< for 2nd pass
int objstart; ///< " " "
int objfinish; ///< " " "
bool addflag; ///< true if adding to objlist[]
int speaking; ///< if command is addressed to obj.
char oops[MAXBUFFER + 1]; ///< illegal word
int oopscount; ///< # of corrections in a row
char parse_called_twice;
char reparse_everything;
char punc_string[64]; ///< punctuation string
byte full_buffer;
/**
* to MatchObject()
* Necessary for proper disambiguation when addressing a character;
* i.e., when 'held' doesn't refer to held by the player, etc.
*/
char recursive_call;
int parse_location; ///< usually var[location]
// heres
HUGO_FILE resource_file;
int extra_param;
char loaded_filename[MAX_RES_PATH];
char loaded_resname[MAX_RES_PATH];
char resource_type;
// herun
int passlocal[MAXLOCALS]; ///< locals passed to routine
int arguments_passed; ///< when calling routine
int ret; ///< return value and returning flag
char retflag;
bool during_player_input;
char override_full;
bool game_reset; ///< for restore, undo, etc.
CODE_BLOCK code_block[MAXSTACKDEPTH];
int stack_depth;
int tail_recursion;
long tail_recursion_addr;
// Used by RunWindow for setting current window dimensions:
int last_window_top, last_window_bottom, last_window_left, last_window_right;
int lowest_windowbottom, ///< in text lines
physical_lowest_windowbottom; ///< in pixels or text lines
bool just_left_window;
// heset
char game_title[MAX_GAME_TITLE];
char arrexpr; ///< true when assigning array
char multiprop; ///< true in multiple prop. assign.
int set_value;
#if defined (DEBUGGER)
char debug_line[MAX_DEBUG_LINE];
bool debug_eval;
bool debug_eval_error;
bool debugger_step_over;
bool debugger_finish;
bool debugger_run;
bool debugger_interrupt;
bool debugger_skip;
bool runtime_error;
uint currentroutine;
bool complex_prop_breakpoint;
bool trace_complex_prop_routine;
char *objectname[MAX_OBJECT];
char *propertyname[MAX_PROPERTY];
CALL call[MAXCALLS];
int routines;
int properties;
WINDOW window[9];
int codeline[9][100];
char localname[9][100];
int current_locals;
long this_codeptr;
int debug_workspace;
int attributes;
int original_dictcount;
int buffered_code_lines;
bool debugger_has_stepped_back;
bool debugger_step_back;
int debugger_collapsing;
int runaway_counter;
int history_count;
int active_screen;
int step_nest;
BREAKPOINT breakpoint[MAXBREAKPOINTS];
BREAKPOINT watch[MAXBREAKPOINTS];
int code_history[MAX_CODE_HISTORY];
int dbnest_history[MAX_CODE_HISTORY];
int history_last;
#endif
private:
/**
* \defgroup heexpr
* @{
*/
/**
* The new-and-improved expression evaluator. Evaluates the current expression
* (or sub-expression therein) beginning at eval[p].
*/
int EvalExpr(int p);
/**
* Called by GetValue(); does the actual dirty work of returning a value from a
* simple data type.
*/
int GetVal();
/**
* Does any reckoning for more sophisticated constructions.
*/
int GetValue();
/**
* Actually performs the increment given below by IsIncrement.
*/
int Increment(int a, char inctype);
/**
* If an increment/decrement is next up (i.e. ++, --, or +=, *=, etc.),
* then sets incdec equal to the increment/decrement and repositions codeptr.
* Returns the token number of the operation, if any.
*/
char IsIncrement(long addr);
/**
* Returns the precedence ranking of the operator represented by token[t].
* The lower the return value, the higher the rank in terms of processing order.
*/
int Precedence(int t);
/**
* Reads the current expression from the current code position into eval[],
* using the following key:
*
* if eval[n] is 0, eval[n+1] is a value
* if eval[n] is 1, eval[n+1] is a token
*
* <inexpr> is used in various routines to keep track of whether or not we're currently
* reading an expression. If <inexpr> is 1, we're in an expression; if 2, we may have
* to step back one code position if encountering a closing parentheses.
*/
void SetupExpr();
/**
* Cuts off straggling components of eval[] after an expression or sub-expression
* has been successfully evaluated.
*/
void TrimExpr(int ptr);
/**@}*/
/**
* \defgroup heglk
* @{
*/
/**
* Does whatever has to be done to initially set up the display
*/
void hugo_init_screen();
/**
* Does whatever has to be done to clean up the display pre-termination
*/
void hugo_cleanup_screen() {
// No implementation
}
void hugo_closefiles() {
// Glk closes all files on exit
}
int hugo_getkey() const {
// Not needed here--single-character events are handled solely by hugo_waitforkey(), below
return 0;
}
/**
* Gets a line of input from the keyboard, storing it in <buffer>.
*/
void hugo_getline(const char *prmpt);
/**
* Provided to be replaced by multitasking systems where cycling while waiting
* for a keystroke may not be such a hot idea.
*/
int hugo_waitforkey();
/**
* Returns true if a keypress is waiting to be retrieved.
*/
int hugo_iskeywaiting();
/**
* Waits for 1/n seconds. Returns false if waiting is unsupported.
*/
int hugo_timewait(int n);
/**
* Clears everything on the screen, moving the cursor to the top-left corner of the screen
*/
void hugo_clearfullscreen();
/**
* Clears the currently defined window, moving the cursor to the top-left corner of the window
*/
void hugo_clearwindow();
/**
* This function does whatever is necessary to set the system up for a standard text display
*/
void hugo_settextmode();
void hugo_settextwindow(int left, int top, int right, int bottom);
/**
* Specially accommodated in GetProp() While the engine thinks that the linelength is 0x7fff,
this tells things like the display object the actual length. (Defined as ACTUAL_LINELENGTH)
*/
int heglk_get_linelength();
/**
* Similar to heglk_get_linelength(). (Defined as ACTUAL_SCREENHEIGHT)
*/
int heglk_get_screenheight();
void hugo_settextpos(int x, int y);
/**
* Essentially the same as printf() without formatting, since printf() generally doesn't take
* into account color setting, font changes, windowing, etc.
*
* The newline character '\n' must be explicitly included at the end of a line in order to
* produce a linefeed. The new cursor position is set to the end of this printed text.
* Upon hitting the right edge of the screen, the printing position wraps to the start
* of the next line.
*/
void hugo_print(const char *a);
/**
* Scroll the text window
*/
void hugo_scrollwindowup() {
// No implementation. Glk takes care of it
}
/**
* Set the font
* @param f The <f> argument is a mask containing any or none of:
* BOLD_FONT, UNDERLINE_FONT, ITALIC_FONT, PROP_FONT.
*/
void hugo_font(int f);
/**
* Set the foreground (print) color
*/
void hugo_settextcolor(int c);
/**
* Set the background color
*/
void hugo_setbackcolor(int c);
/**
* Color-setting functions should always pass the color through hugo_color()
* in order to properly set default fore/background colors
*/
int hugo_color(int c);
/**
* Get the width of a character
* @remarks As given here, this function works only for non-proportional printing.
* For proportional printing, hugo_charwidth() should return the width of the supplied
* character in the current font and style.
*/
int hugo_charwidth(char a) const;
/**
* Return the width of a string
*/
int hugo_textwidth(const char *a) const;
/**
* Return the length of a string
*/
int hugo_strlen(const char *a) const;
void hugo_setgametitle(const char *t);
int hugo_hasvideo() const;
int hugo_playvideo(HUGO_FILE infile, long reslength, char loop_flag, char background, int volume);
void hugo_stopvideo();
/**@}*/
/**
* \defgroup hemisc
* @{
*/
/**
* The all-purpose printing routine that takes care of word-wrapping.
*/
void AP(const char *a);
/**
* Used whenever a routine is called, assumes the routine address and begins
* with the arguments (if any).
*/
int CallRoutine(unsigned int addr);
/**
* Adds a command to the context command list. A zero value (i.e., an empty string)
* resets the list.
*/
void ContextCommand();
/**
* Dynamically creates a new dictionary entry.
*/
unsigned int Dict();
/**
* Generates a fatal error
*/
void FatalError(int n);
void FileIO();
void Flushpbuffer();
void GetCommand();
/**
* From any address <addr>; the segment must be defined prior to calling the function.
*/
char *GetString(long addr);
/**
* Get text block from position <textaddr> in the text bank. If the game was not fully loaded
* in memory, i.e., if loaded_in_memory is not true, the block is read from disk.
*/
char *GetText(long textaddr);
/**
* From the dictionary table.
*/
char *GetWord(unsigned int w);
void HandleTailRecursion(long addr);
void InitGame();
void LoadGame();
/**
* Must be called before running every new routine, i.e. before calling RunRoutine().
* Unfortunately, the current locals must be saved in a temp array prior to calling.
* The argument n gives the number of arguments passed.
*/
void PassLocals(int n);
inline unsigned char Peek(long a) {
return MEM(defseg * 16L + a);
}
inline unsigned int PeekWord(long a) {
return (unsigned char)MEM(defseg * 16L + a) + (unsigned char)MEM(defseg * 16L + a + 1) * 256;
}
inline void Poke(unsigned int a, unsigned char v) {
SETMEM(defseg * 16L + a, v);
}
inline void PokeWord(unsigned int a, unsigned int v) {
SETMEM(defseg * 16L + a, (char)(v % 256));
SETMEM(defseg * 16L + a + 1, (char)(v / 256));
}
/**
* Returns <a> as a hex-number string in XXXXXX format.
*/
static const char *PrintHex(long a);
/**
* Print to client display taking into account cursor relocation,
* font changes, color setting, and window scrolling.
*/
void Printout(char *a, int no_scrollback_linebreak);
void PromptMore();
int RecordCommands();
/**
* Formats:
*
* end of turn: (0, undoturn, 0, 0, 0)
* move obj.: (MOVE_T, obj., parent, 0, 0)
* property: (PROP_T, obj., prop., # or PROP_ROUTINE, val.)
* attribute: (ATTR_T, obj., attr., 0 or 1, 0)
* variable: (VAR_T, var., value, 0, 0)
* array: (ARRAYDATA_T, array addr., element, val., 0)
* dict: (DICT_T, entry length, 0, 0, 0)
* word setting: (WORD_T, word number, new word, 0, 0)
*/
void SaveUndo(int a, int b, int c, int d, int e);
/**
* Properly sets up the code_block structure for the current stack depth depending
* on if this is a called block (RUNROUTINE_BLOCK) or otherwise.
*/
void SetStackFrame(int depth, int type, long brk, long returnaddr);
void SetupDisplay();
/**
* The method is passed <a> as the string and <*i> as the position in the string.
* The character(s) at a[*i], a[*(i+1)], etc. are converted into a single Latin-1
* (i.e., greater than 127) character value.
*
* Assume that the AP() has already encountered a control character ('\'),
* and that a[*i]... is one of:
*
* `a accent grave on following character (e.g., 'a')
* 'a accent acute on following character (e.g., 'a')
* ~n tilde on following (e.g., 'n' or 'N')
* :a umlaut on following (e.g., 'a')
* ^a circumflex on following (e.g., 'a')
* ,c cedilla on following (e.g., 'c' or 'C')
* < Spanish left quotation marks
* > Spanish right quotation marks
* ! upside-down exclamation mark
* ? upside-down question mark
* ae ae ligature
* AE AE ligature
* c cents symbol
* L British pound
* Y Japanese Yen
* - em (long) dash
* #nnn character value given by nnn
*
* Note that the return value is a single character--which will be either unchanged
* or a Latin-1 character value.
*/
char SpecialChar(const char *a, int *i);
int Undo();
/**@}*/
/**
* \defgroup hemedia
* @{
*/
int loadres(HUGO_FILE infile, int reslen, int type);
int hugo_hasgraphics();
void initsound();
void initmusic();
int hugo_playmusic(HUGO_FILE infile, long reslen, char loop_flag);
void hugo_musicvolume(int vol);
void hugo_stopmusic();
int hugo_playsample(HUGO_FILE infile, long reslen, char loop_flag);
void hugo_samplevolume(int vol);
void hugo_stopsample();
/**@}*/
/**
* \defgroup heobject - Object/property/attribute management functions
* @{
*/
int Child(int obj);
int Children(int obj);
int Elder(int obj);
/**
* Returns one of four sets of 32 attributes.
*/
unsigned long GetAttributes(int obj, int attribute_set);
/**
* Returns the value of '<obj>.<p> #<n>' If <s> is true, the self global
* is not set to <obj> in order to facilitate <obj>..<p> calls.
*/
int GetProp(int obj, int p, int n, char s);
/**
* Returns the value of the last object above <obj> in the tree before object 0.
*/
int GrandParent(int obj);
void MoveObj(int obj, int p);
const char *Name(int obj);
int Parent(int obj);
/**
* Returns address of <obj>.<p> (with <offset> provided for additive properties--
* i.e. subsequent calls with the same <obj> and <p>.
*/
unsigned int PropAddr(int obj, int p, unsigned int offset);
/**
* Writes (puts) one of four sets of 32 attributes.
*/
void PutAttributes(int obj, unsigned long a, int attribute_set);
/**
* Set an attribute
* c = 1 for set, 0 for clear
*/
void SetAttribute(int obj, int attr, int c);
int Sibling(int obj);
int TestAttribute(int obj, int attr, int nattr);
int Youngest(int obj);
/**@}*/
/**
* \defgroup heparse
* @{
*/
void AddAllObjects(int loc);
/**
* Adds the object <obj> to objlist[], making all related adjustments.
*/
void AddObj(int obj);
/**
* Adds <obj> as a contender to the possible object list, noting that it was referred
* to as either a noun or an adjective.
*/
void AddPossibleObject(int obj, char type, unsigned int w);
/**
* Move the address in the grammar table past the current token.
*/
void AdvanceGrammar();
/**
* For when it's only necessary to know if word[wn] is an object word for any object,
* not a particular object. Returns 1 for an object word or -1 for a non-object word.
*/
int AnyObjWord(int wn);
/**
* The non_grammar argument is true when called from a non-grammar function such as RunEvents().
*/
int Available(int obj, char non_grammar);
void CallLibraryParse();
/**
* Takes into account the preset domain for checking an object's presence;
* <domain> is 0, -1, or an object number..
*/
int DomainObj(int obj);
/**
* Returns the dictionary address of <a>.
*/
unsigned int FindWord(const char *a);
/**
* Checks to see if <obj> is in objlist[].
*/
int InList(int obj);
/**
* Deletes word[a].
*/
void KillWord(int a);
/**
* Here, briefly, is how MatchCommand() works:
*
* 1. Match the verb.
*
* 2. If no match, check to see if the line begins with an object (character)
* and try to match it.
*
* 3. If found, try to match a syntax for that verb, including objects, dictionary words,
* numbers, attributes, and routines. If any objects are specified, skip over them for now,
* marking the start and finish. This is done mostly in MatchWord().
*
* 4. Match the xobject, if there is one--via MatchObject().
*
* 5. If all is well, return to match the objects that were previously skipped over,
* loading them into objlist[]. Once again, this is done by MatchObject().
*
* (The reason the objects are initially skipped is because it may be necessary to know
* where to look for them--this may require knowing what the xobject is, if the syntax
* is something like:
*
* "get" <object> "from" <xobject>)
*
* The variable <obj_match_state> is the indicator of what stage object-matching is at:
*
* obj_match_state = 0 - haven't matched anything yet
*
* obj_match_state = 1 - xobject has been matched
*
* obj_match_state = 2 - matching object(s), loading objlist[]
*
* obj_match_state = 5 - matching first word/name, i.e., "Bob, <do something>"
*/
int MatchCommand();
/**
* The argument is the word number we're starting matching on.
*
* NOTE: recusive_call is set to 0 if this is the first call. MatchObject() sets it to 1
* when calling itself when asking for clarification as to which object is meant.
*
* Return true on a recursive call to allow parsing to continue.
*/
bool MatchObject(int *wordnum);
int MatchWord(int *wordnum);
/**
* Returns true if the specified object has the specified word as an adjective or noun
* (as specified by type).
*/
int ObjWordType(int obj, unsigned int w, int type);
/**
* Returns <adjective> if the word at dictionary address <w> is an adjective of <obj>,
* or <noun> if it is a noun.
*/
int ObjWord(int obj, unsigned int w);
/**
* Turns word[] into dictionary addresses stored in wd[]. Takes care of fingering illegal
* (unknown) words and doing alterations such as compounds, removals, and synonyms.
*/
int Parse();
void ParseError(int e, int a);
/**
* Deletes wd[a].
*/
void RemoveWord(int a);
/**
* Call FindObject(0, 0) to reset library's disambiguation mechanism.
*/
void ResetFindObject();
/**
* Splits <buffer> into the word[] array. Also does nifty things such as turning time
* values such as hh:mm into a single number (representing minutes from midnight).
*/
void SeparateWords();
/**
* Removes object <obj> from objlist[], making all related adjustments.
*/
void SubtractObj(int obj);
/**
* Removes <obj> as a possible contender for object disambiguation.
*/
void SubtractPossibleObject(int obj);
/**
* Called by MatchObject() to see if <obj> is available, and add it to or subtract
* it from objlist[] accordingly.
*/
void TryObj(int obj);
/**
* Checks first of all to see if an object is available, then checks if it meets
* all the qualifications demanded by the grammar syntax.
*/
int ValidObj(int obj);
/**@}*/
/**
* \defgroup heres
* @{
*/
void DisplayPicture();
void PlayMusic();
void PlaySample();
void PlayVideo();
/**
* Assumes that filename/resname contain a resourcefile name and a resource name.
* If resname is "", filename contains the path of the resource on disk.
* Returns the length of the resource if the named resource is found.
*
* If FindResource() returns non-zero, the file is hot, i.e., it is open and positioned
* to the start of the resource.
*
* Note that resourcefiles are expected to be in (if not the current directory) "object" or "games",
* and on-disk resources in (if not the given directory) "source" or "resource" (where these are the
* environment variables "HUGO_...", not actual on-disk directories).
*/
long FindResource(const char *filename, const char *resname);
/**
* Processes resourcefile/filename (and resource, if applicable).
* Returns 0 if a valid 0 parameter is passed as in "music 0" or "sound 0".
*/
int GetResourceParameters(char *filename, char *resname, int restype);
/**@}*/
/**
* \defgroup herun
* @{
*/
void RunDo();
void RunEvents();
void playGame();
void RunIf(char override);
void RunInput();
/**
* (All the debugger range-checking is important because invalid memory writes due
* to invalid object location calculations are a good way to crash the system.)
*/
void RunMove();
void RunPrint();
int RunRestart();
int RestoreGameData();
int RunRestore();
/**
* This is the main loop for running each line of code in sequence;
* the main switch statement is based on the first token in each line.
*
* This routine is relatively complex, especially given the addition of debugger control.
* Basically it is structured like this:
*
* 1. If this is the debugger build, see what debugger information has to be set up upon
* calling this block of code
*
* 2. Get the next token, and as long as it isn't CLOSE_BRACE_T ('}')...
*
* 3. ...If this is the debugger build, see if there is a standing debugger_interrupt
* to pass control back to the debugger, and perform all operations for stepping
* tracing, breakpoints, etc.
*
* 4. ...See what token we're dealing with and execute accordingly
*
* 5. ...Loop back to (2)
*
* 6. If this is the debugger build, do whatever is necessary to tidy up after finishing
* this block of code
*
* There's a bit of a trick involved since the original language design uses "{...}"
* structures for both conditionals and blocks that necessitate another (i.e., nested) call
* to RunRoutine(). The call_block structure array and stack_depth variable are the
* navigation guides.
*/
void RunRoutine(long addr);
int RunSave();
int RunScriptSet();
/**
* As in 'x = string(<array>, "<string>"[, maxlen]'.
*/
int RunString();
int RunSystem();
void SaveWindowData(SAVED_WINDOW_DATA *spw);
void RestoreWindowData(SAVED_WINDOW_DATA *spw);
void RunWindow();
/**@}*/
/**
* \defgroup heglk
* @{
*/
/**
* If gotvalue is passed as -1, then no value has already been as the (potential) object, etc.
* comprising the first part of the object.property, for example, to be set.
*/
void RunSet(int gotvalue);
unsigned int GetAnonymousFunction(long addr);
int SetCompound(int t);
/**@}*/
/**
* \defgroup Miscellaneous
* @{
*/
int hugo_fseek(Common::SeekableReadStream *s, long int offset, int whence) {
return !s->seek(offset, whence);
}
int hugo_fseek(strid_t s, long int offset, int whence) {
Common::SeekableReadStream *rs = *s;
return hugo_fseek(rs, offset, whence);
}
int hugo_fgetc(Common::SeekableReadStream *s) {
return s->readByte();
}
int hugo_fgetc(strid_t s) {
Common::SeekableReadStream *ws = *s;
return hugo_fgetc(ws);
}
int hugo_fputc(int c, Common::WriteStream *s) {
s->writeByte(c);
return s->err() ? EOF : 0;
}
int hugo_fputc(int c, strid_t s) {
Common::WriteStream *ws = *s;
return hugo_fputc(c, ws);
}
char *hugo_fgets(char *buf, int max, Common::SeekableReadStream *s) {
char *ptr = buf;
char c;
while (s->pos() < s->size() && --max > 0) {
c = hugo_fgetc(s);
if (c == '\n' || c == '\0')
break;
*ptr++ = c;
}
*ptr++ = '\0';
return buf;
}
char *hugo_fgets(char *buf, int max, strid_t s) {
Common::SeekableReadStream *rs = *s;
return hugo_fgets(buf, max, rs);
}
size_t hugo_fread(void *ptr, size_t size, size_t count, Common::SeekableReadStream *s) {
return s->read(ptr, size * count);
}
size_t hugo_fread(void *ptr, size_t size, size_t count, strid_t s) {
Common::SeekableReadStream *rs = *s;
return hugo_fread(ptr, size, count, rs);
}
int hugo_fprintf(Common::WriteStream *s, const char *fmt, ...) {
va_list va;
va_start(va, fmt);
Common::String text = Common::String::vformat(fmt, va);
va_end(va);
s->write(text.c_str(), text.size());
return s->err() ? -1 : 0;
}
int hugo_fprintf(strid_t s, const char *fmt, ...) {
va_list va;
va_start(va, fmt);
Common::String text = Common::String::vformat(fmt, va);
va_end(va);
Common::WriteStream *str = *s;
str->write(text.c_str(), text.size());
return str->err() ? -1 : 0;
}
int hugo_fputs(const char *str, Common::WriteStream *s) {
return s->write(str, strlen(str)) == strlen(str) ? 0 : -1;
}
int hugo_fputs(const char *str, strid_t s) {
Common::WriteStream *ws = *s;
return hugo_fputs(str, ws);
}
bool hugo_ferror(Common::SeekableReadStream *s) const {
return s->err();
}
bool hugo_ferror(strid_t s) const {
Common::SeekableReadStream *rs = *s;
return hugo_ferror(rs);
}
long hugo_ftell(Common::SeekableReadStream *s) {
return s->pos();
}
long hugo_ftell(strid_t s) {
Common::SeekableReadStream *rs = *s;
return hugo_ftell(rs);
}
int hugo_fclose(strid_t f) {
delete f;
return 0;
}
void hugo_exit(const char *msg) {
error("%s", line);
}
uint hugo_rand() {
return _random.getRandomNumber(0xffffff);
}
char *hugo_itoa(int value, char *str, int base, size_t str_size) {
assert(base == 10);
Common::sprintf_s(str, str_size, "%d", value);
return str;
}
/**@}*/
private:
/**
* Allocate memory block
*/
void *hugo_blockalloc(size_t num) { return malloc(num); }
void hugo_blockfree(void *block) { free(block); }
#if defined (DEBUGGER)
int CheckinRange(uint v1, uint v2, const char *v3) { return 1; }
/**
* Shorthand since many of these object functions may call CheckinRange() if the debugger
* is running and runtime_warnings is set.
*/
int CheckObjectRange(int obj);
void DebugRunRoutine(long addr) { RunRoutine(addr); }
void RuntimeWarning(const char *msg) {}
void DebugMessageBox(const char *title, const char *msg) {}
bool IsBreakpoint(long loc) const { return false; }
const char *RoutineName(long loc) { return "Routine"; }
void AddStringtoCodeWindow(const char *str) {}
void SwitchtoDebugger() {}
void Debugger() {}
void UpdateDebugScreen() {}
void SwitchtoGame() {}
void DebuggerFatal(DEBUGGER_ERROR err) { error("Debugger error"); }
void AddLinetoCodeWindow(int lineNum) {}
void RecoverLastGood() {}
void SetupWatchEval(int num) {}
bool EvalWatch() { return false; }
#endif
public:
/**
* Constructor
*/
Hugo(OSystem *syst, const GlkGameDescription &gameDesc);
/**
* Destructor
*/
~Hugo();
/**
* Run the game
*/
void runGame() override;
/**
* Returns the running interpreter type
*/
InterpreterType getInterpreterType() const override { return INTERPRETER_HUGO; }
/**
* 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 Hugo *g_vm;
} // End of namespace Hugo
} // End of namespace Glk
#endif