aboutsummaryrefslogtreecommitdiff
path: root/engines/glk
diff options
context:
space:
mode:
authorPaul Gilbert2019-05-11 10:18:13 +1000
committerPaul Gilbert2019-05-11 10:18:13 +1000
commit0b2346c1f14d94efa1264aadef5bf13c1f15ddef (patch)
treebc55b876fae2f99d3b5eb45414fcba6a3f00213d /engines/glk
parent88300636350e18eced9d27691980705f47d2a43c (diff)
downloadscummvm-rg350-0b2346c1f14d94efa1264aadef5bf13c1f15ddef.tar.gz
scummvm-rg350-0b2346c1f14d94efa1264aadef5bf13c1f15ddef.tar.bz2
scummvm-rg350-0b2346c1f14d94efa1264aadef5bf13c1f15ddef.zip
GLK: HUGO: Added heobject
Diffstat (limited to 'engines/glk')
-rw-r--r--engines/glk/hugo/heobject.cpp671
-rw-r--r--engines/glk/hugo/hugo.cpp35
-rw-r--r--engines/glk/hugo/hugo.h130
-rw-r--r--engines/glk/hugo/hugo_defines.h13
-rw-r--r--engines/glk/hugo/hugo_types.h25
-rw-r--r--engines/glk/module.mk1
6 files changed, 863 insertions, 12 deletions
diff --git a/engines/glk/hugo/heobject.cpp b/engines/glk/hugo/heobject.cpp
new file mode 100644
index 0000000000..cc1416d98d
--- /dev/null
+++ b/engines/glk/hugo/heobject.cpp
@@ -0,0 +1,671 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glk/hugo/hugo.h"
+
+namespace Glk {
+namespace Hugo {
+
+#if defined (DEBUGGER)
+
+int Hugo::CheckObjectRange(int obj) {
+ if (runtime_warnings) {
+ return CheckinRange((unsigned)obj, (unsigned)objects, "object");
+ } else
+ return true;
+}
+
+#endif
+
+int Hugo::Child(int obj) {
+ int c;
+
+#if defined (DEBUGGER)
+ if (!CheckObjectRange(obj)) return 0;
+#endif
+ if (obj<0 || obj>=objects) return 0;
+
+ defseg = objtable;
+
+ c = PeekWord(2 + obj*object_size + object_size - 4);
+
+ defseg = gameseg;
+
+ return c;
+}
+
+int Hugo::Children(int obj) {
+ int count = 0;
+ int nextobj;
+
+ if (obj<0 || obj>=objects) return 0;
+
+ nextobj = Child(obj);
+ while (nextobj)
+ {count++;
+ nextobj = Sibling(nextobj);}
+ return count;
+}
+
+int Hugo::Elder(int obj) {
+ int lastobj;
+ int p, cp;
+
+ if (obj<0 || obj>=objects) return 0;
+
+ p = Parent(obj);
+ cp = Child(p);
+
+ if (p==0 || cp==obj)
+ return 0;
+
+ lastobj = cp;
+ while (Sibling(lastobj) != obj)
+ lastobj = Sibling(lastobj);
+
+ return lastobj;
+}
+
+unsigned long Hugo::GetAttributes(int obj, int attribute_set) {
+ unsigned long a;
+
+ defseg = objtable;
+
+#if defined (DEBUGGER)
+ if (!CheckObjectRange(obj)) return 0;
+#endif
+ if (obj<0 || obj>=objects) return 0;
+
+ a = (unsigned long)PeekWord(2 + obj*object_size + attribute_set*4)
+ + (unsigned long)PeekWord(2 + obj*object_size + attribute_set*4 + 2)*65536L;
+
+ defseg = gameseg;
+
+ return a;
+}
+
+int Hugo::GetProp(int obj, int p, int n, char s) {
+ char objonly, /* no verbroutine given in before, etc. */
+ isadditive = 0, /* before, after, etc. */
+ gotone = 0, /* when a match has been made */
+ getpropaddress = 0; /* when getting &object.property */
+ int i;
+ int tempself,
+ objtype, /* i.e., what we're matching to */
+ flag = 0;
+ int g = 0;
+ int templocals[MAXLOCALS];
+ int temp_stack_depth;
+ char tempinexpr = inexpr;
+ unsigned int pa, /* property address */
+ offset = 0;
+ long inprop, /* code position in complex property */
+ returnaddr;
+#if defined (DEBUGGER)
+ long orig_inprop;
+ int tempdbnest;
+
+ /* Don't check a possible non-existent display object (-1) */
+ if (obj!=-1 || display_object!=-1) CheckObjectRange(obj);
+#endif
+ /* This way either -1 (the non-existent display object) or a too-high
+ object will fail
+ */
+ if (obj<0 || obj>=objects) return 0;
+
+ /* The display object, which is automatically created by the compiler,
+ did not exist pre-v2.4
+ */
+ if ((obj==display_object) && game_version>=24)
+ {
+ /* There are no actual default "properties" per se on the
+ display object--but reading them returns certain data about
+ the current state of display affairs
+ */
+
+ /* no display.<prop> #2, etc. */
+ if (n==1 && p<=pointer_y)
+ {
+ if (p==screenwidth)
+#if defined (GLK) && defined (ACTUAL_LINELENGTH)
+ g = ACTUAL_LINELENGTH();
+#else
+ g = SCREENWIDTH/FIXEDCHARWIDTH;
+#endif
+ else if (p==screenheight)
+/* ACTUAL_SCREENHEIGHT can be set to a non-portable function if
+ SCREENHEIGHT and SCREENHEIGHT have been set to large values in
+ order to force the non-portable layer to handle wrapping and
+ scrolling (as in the Glk port).
+*/
+#if defined (ACTUAL_SCREENHEIGHT)
+ g = ACTUAL_SCREENHEIGHT();
+#else
+ g = SCREENHEIGHT/FIXEDLINEHEIGHT;
+#endif
+ else if (p==linelength)
+/* ACTUAL_LINELENGTH functions similarly to ACTUAL_SCREENWIDTH,
+ above.
+*/
+#if defined (ACTUAL_LINELENGTH)
+ g = ACTUAL_LINELENGTH();
+#else
+ g = physical_windowwidth/FIXEDCHARWIDTH;
+#endif
+ else if (p==windowlines)
+ g = physical_windowheight/FIXEDLINEHEIGHT;
+ else if (p==cursor_column)
+ g = (currentpos+1+hugo_textwidth(pbuffer))/FIXEDCHARWIDTH;
+ else if (p==cursor_row)
+ g = currentline;
+ else if (p==hasgraphics)
+ g = hugo_hasgraphics();
+ else if (p==title_caption)
+ g = FindWord(game_title);
+ else if (p==hasvideo)
+#if !defined (COMPILE_V25)
+ g = hugo_hasvideo();
+#else
+ g = 0;
+#endif
+ else if (p==needs_repaint)
+ g = display_needs_repaint;
+ else if (p==pointer_x)
+ g = display_pointer_x;
+ else if (p==pointer_y)
+ g = display_pointer_y;
+ else
+ g = 0;
+
+ return g;
+ }
+ }
+
+ /* To avoid prematurely getting an address in &obj.prop.prop */
+ if (getaddress && MEM(codeptr)!=DECIMAL_T)
+ getpropaddress = true;
+
+ tempself = var[self];
+ if (!s) var[self] = obj;
+
+ temp_stack_depth = stack_depth;
+
+
+GetNextProp:
+
+ pa = PropAddr(obj, p, offset);
+
+ defseg = proptable;
+
+ /* If the object doesn't have property p, see if there's a
+ default value.
+ */
+ if (!pa)
+ {
+ if (offset) goto NoMorePropMatches;
+
+ if (getpropaddress) /* if an &value */
+ g = 0;
+ else
+ g = PeekWord(p * 2 + 2);
+ }
+
+ else
+ {
+ /* Property is a value... */
+ if (Peek(pa+1) < PROP_ROUTINE)
+ {
+ if (getaddress || (int)Peek(pa+1) < n || n<=0)
+ {
+#if defined (DEBUGGER)
+ if (n!=1)
+ CheckinRange(n, (int)Peek(pa+1), "property element");
+#endif
+ g = 0;
+ }
+ else
+ g = PeekWord(pa + n * 2);
+ }
+
+ /* ...or a property routine */
+ else
+ {
+ /* Check if this is an additive property */
+ defseg = proptable;
+ if (Peek(2 + Peek(0)*2 + p)&ADDITIVE_FLAG)
+ isadditive = true;
+
+ /* If an &value, return the address of the
+ property routine.
+ */
+ if (getpropaddress)
+ {
+ g = PeekWord(pa+2);
+ goto NoMorePropMatches;
+ }
+ else
+ {
+#if defined (DEBUGGER)
+ if (debug_eval)
+ {
+ debug_eval_error = true;
+ DebugMessageBox("Expression Error",
+ "Property routine illegal in watch/assignment");
+ defseg = gameseg;
+ return 0;
+ }
+#endif
+ /* If not a complex property such as
+ before or after:
+ */
+ if ((game_version>=22 && (Peek(2 + Peek(0)*2 + p)&COMPLEX_FLAG)==0) || (game_version<22 && p!=before && p!=after))
+ {
+ ret = 1;
+ returnaddr = codeptr;
+
+ /* Check to see if this is a valid tail-recursive return... */
+ if (tail_recursion==TAIL_RECURSION_PROPERTY && MEM(codeptr)==EOL_T)
+ {
+ PassLocals(0);
+ tail_recursion_addr = (long)PeekWord(pa+2)*address_scale;
+ return 0;
+ }
+ /* ...but if we're not immediately followed by and end-of-line marker,
+ or another property value, cancel the pending tail-recursion
+ */
+ else if (MEM(codeptr)!=DECIMAL_T)
+ {
+ tail_recursion = 0;
+ }
+
+ for (i=0; i<MAXLOCALS; i++)
+ templocals[i] = var[MAXGLOBALS+i];
+
+ PassLocals(0);
+
+ SetStackFrame(stack_depth+1, RUNROUTINE_BLOCK, 0, 0);
+#if defined (DEBUGGER)
+ tempdbnest = dbnest;
+ DebugRunRoutine((long)PeekWord(pa+2)*address_scale);
+ dbnest = tempdbnest;
+#else
+ RunRoutine((long)PeekWord(pa+2)*address_scale);
+#endif
+
+ retflag = 0;
+ codeptr = returnaddr;
+ g = ret;
+ ret = 0;
+ }
+
+ /* Complex property: */
+ else
+ {
+ for (i=0; i<MAXLOCALS; i++)
+ templocals[i] = var[MAXGLOBALS+i];
+
+ inprop = (long)PeekWord(pa + 2)*address_scale;
+#ifdef DEBUGGER
+ orig_inprop = inprop;
+#endif
+ defseg = gameseg;
+ while (Peek(inprop)!=CLOSE_BRACE_T)
+ {
+ returnaddr = codeptr;
+
+ codeptr = inprop;
+ objonly = false;
+ objtype = GetValue();
+ inprop = codeptr;
+ codeptr = returnaddr;
+
+ flag = 0;
+
+ /* If only an object (or other variable) is
+ given, and no verbroutine
+ */
+ if (Peek(inprop)==JUMP_T)
+ {
+ objonly = true;
+ if (!gotone && obj==objtype) flag = 1;
+ }
+
+ /* Otherwise, one or more verbroutines are
+ specified
+ */
+ else
+ {
+ while (Peek(inprop)!=JUMP_T)
+ {
+ if (PeekWord(inprop+1)==(unsigned int)var[verbroutine] ||
+
+ /* This is necessary because of the awkward way the pre-v2.2
+ differentiated non-verbroutine blocks, i.e., with Parse
+ */
+ ((game_version<22) && PeekWord(inprop+1)==(unsigned int)parseaddr && !gotone))
+ {
+ if (obj==objtype) flag = 1;
+ }
+ inprop += 3;
+ }
+ }
+
+ if (flag==1)
+ {
+ gotone = true;
+ ret = 1;
+ returnaddr = codeptr;
+
+ SetStackFrame(stack_depth, RUNROUTINE_BLOCK, 0, 0);
+
+ PassLocals(0);
+#if defined (DEBUGGER)
+ /* Prevent premature stopping */
+ if (debugger_step_over && !debugger_finish)
+ debugger_run = true;
+
+ if (IsBreakpoint(orig_inprop))
+ complex_prop_breakpoint = true;
+
+ sprintf(debug_line, "Calling: %s.%s", objectname[obj], propertyname[p]);
+ trace_complex_prop_routine = true;
+
+ tempdbnest = dbnest;
+ DebugRunRoutine(inprop+3);
+ dbnest = tempdbnest;
+#else
+ RunRoutine(inprop+3);
+#endif
+ retflag = 0;
+ codeptr = returnaddr;
+ g = ret;
+ ret = 0;
+ }
+
+ /* The following used to read "if (!flag || objonly..."
+ meaning that any non-verbroutine related routines
+ would fall through regardless of whether they returned
+ true or false. I don't recall the rationale for this,
+ and have therefore removed it.
+ */
+ if (!flag || (objonly && !g) || ((game_version<22) && PeekWord(inprop-2)==(unsigned int)parseaddr))
+ inprop = (long)PeekWord(inprop+1)*address_scale;
+ else break;
+ }
+ }
+
+ for (i=0; i<MAXLOCALS; i++)
+ var[MAXGLOBALS+i] = templocals[i];
+
+ if (isadditive && !g)
+ {
+ offset = pa + 4;
+ gotone = false;
+ goto GetNextProp;
+ }
+ }
+ }
+ }
+
+NoMorePropMatches:
+
+ defseg = gameseg;
+
+ var[self] = tempself;
+ inexpr = tempinexpr;
+ stack_depth = temp_stack_depth;
+
+ return g;
+}
+
+int Hugo::GrandParent(int obj) {
+ int nextobj;
+
+#if defined (DEBUGGER)
+ if (!CheckObjectRange(obj)) return 0;
+#endif
+ if (obj<0 || obj>=objects) return 0;
+
+ defseg = objtable;
+ while ((nextobj = PeekWord(2 + obj*object_size + object_size-8)) != 0)
+ obj = nextobj;
+ defseg = gameseg;
+
+ return obj;
+}
+
+void Hugo::MoveObj(int obj, int p) {
+ int oldparent, prevobj, s;
+ unsigned int objaddr, parentaddr, lastobjaddr;
+
+ if (obj==p) return;
+ if (obj<0 || obj>=objects) return;
+
+ oldparent = Parent(obj);
+ /* if (oldparent==p) return; */
+
+ objaddr = 2 + obj*object_size;
+
+ /* First, detach the object from its old parent and siblings... */
+
+ prevobj = Elder(obj);
+ s = Sibling(obj);
+ defseg = objtable;
+ if (prevobj) /* sibling */
+ PokeWord(2 + prevobj*object_size + object_size-6, s);
+ else /* child */
+ PokeWord(2 + oldparent*object_size + object_size-4, s);
+
+
+ /* Then move it to the new parent... */
+
+ defseg = objtable;
+ PokeWord(objaddr + object_size-8, p); /* new parent */
+ PokeWord(objaddr + object_size-6, 0); /* erase old sibling */
+
+ /* Only operate on the new parent if it isn't object 0 */
+ if (p!=0)
+ {
+
+ /* Object is sole child, or... */
+ if (Child(p)==0)
+ {
+ parentaddr = 2 + p*object_size;
+ defseg = objtable;
+ PokeWord(parentaddr + object_size-4, obj);
+ }
+
+ /* ...object is next sibling. */
+ else
+ {
+ lastobjaddr = 2 + Youngest(p)*object_size;
+ defseg = objtable;
+ PokeWord(lastobjaddr + object_size-6, obj);
+ }
+ }
+}
+
+char *Hugo::Name(int obj) {
+ int p;
+
+ p = GetProp(obj, 0, 1, 0);
+
+ if (p)
+ return GetWord((unsigned int)p);
+ else
+ return 0;
+}
+
+int Hugo::Parent(int obj) {
+ int p;
+
+#if defined (DEBUGGER)
+ if (!CheckObjectRange(obj)) return 0;
+#endif
+ if (obj<0 || obj>=objects) return 0;
+
+ defseg = objtable;
+
+ p = PeekWord(2 + obj*object_size + object_size-8);
+
+ defseg = gameseg;
+
+ return p;
+}
+
+unsigned int Hugo::PropAddr(int obj, int p, unsigned int offset) {
+ unsigned char c;
+ int proplen;
+ unsigned int ptr;
+
+#if defined (DEBUGGER)
+ /* Don't check any non-existent display object (-1) */
+ if (p!=-1) CheckinRange(p, properties, "property");
+ CheckObjectRange(obj);
+#endif
+ /* This way either -1 (the non-existent display object) or a too-high
+ object will fail
+ */
+ if (obj<0 || obj>=objects) return 0;
+
+ defseg = objtable;
+
+ /* Position in the property table...
+
+ i.e., ptr = PeekWord(2 + obj*object_size + (object_size-2));
+ */
+ ptr = PeekWord(object_size*(obj+1));
+
+ /* ...unless a position has already been given */
+ if (offset) ptr = offset;
+
+ defseg = proptable;
+
+ c = Peek(ptr);
+ while (c != PROP_END && c != (unsigned char)p)
+ {
+ proplen = Peek(ptr + 1);
+
+ /* Property routine address is 1 word */
+ if (proplen==PROP_ROUTINE) proplen = 1;
+
+ ptr += proplen * 2 + 2;
+ c = Peek(ptr);
+ }
+
+ defseg = gameseg;
+
+ if (c==PROP_END)
+ return 0;
+ else
+ return ptr;
+}
+
+void Hugo::PutAttributes(int obj, unsigned long a, int attribute_set) {
+ unsigned int lword, hword;
+
+ hword = (unsigned int)(a/65536L);
+ lword = (unsigned int)(a%65536L);
+
+ defseg = objtable;
+
+ PokeWord(2 + obj*object_size + attribute_set*4, lword);
+ PokeWord(2 + obj*object_size + attribute_set*4 + 2, hword);
+
+ defseg = gameseg;
+}
+
+void Hugo::SetAttribute(int obj, int attr, int c) {
+ unsigned long a, mask;
+
+#if defined (DEBUGGER)
+ if (!CheckObjectRange(obj)) return;
+#endif
+ if (obj<0 || obj>=objects) return;
+
+ a = GetAttributes(obj, attr/32);
+
+ mask = 1L<<(long)(attr%32);
+
+ if (c==1)
+ a = a | mask;
+ else
+ {
+ if (a & mask)
+ a = a ^ mask;
+ }
+
+ PutAttributes(obj, a, attr/32);
+}
+
+int Hugo::Sibling(int obj) {
+ int s;
+
+#if defined (DEBUGGER)
+ if (!CheckObjectRange(obj)) return 0;
+#endif
+ if (obj<0 || obj>=objects) return 0;
+
+ defseg = objtable;
+
+ s = PeekWord(2+ obj*object_size + object_size-6);
+
+ defseg = gameseg;
+
+ return s;
+}
+
+int Hugo::TestAttribute(int obj, int attr, int nattr) {
+ unsigned long a, mask, ta;
+
+#if defined (DEBUGGER)
+ if (!CheckObjectRange(obj)) return 0;
+#endif
+ if (obj<0 || obj>=objects) return 0;
+
+ a = GetAttributes(obj, attr/32);
+
+ mask = 1L<<(attr%32);
+
+ ta = a & mask;
+ if (ta) ta = 1;
+
+ if (nattr) ta = ta ^ 1;
+
+ return (int)ta;
+}
+
+int Hugo::Youngest(int obj) {
+ int nextobj;
+
+ if (Child(obj)==0) return 0;
+
+ nextobj = Child(obj);
+
+ while (Sibling(nextobj))
+ nextobj = Sibling(nextobj);
+
+ return nextobj;
+}
+
+} // End of namespace Hugo
+} // End of namespace Glk
diff --git a/engines/glk/hugo/hugo.cpp b/engines/glk/hugo/hugo.cpp
index 8e8113421a..a5fbdb935f 100644
--- a/engines/glk/hugo/hugo.cpp
+++ b/engines/glk/hugo/hugo.cpp
@@ -26,8 +26,12 @@ namespace Glk {
namespace Hugo {
Hugo::Hugo(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
- mainwin(nullptr), currentwin(nullptr), secondwin(nullptr), auxwin(nullptr), address_scale(16),
+ 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),
+ // hemisc
game_version(0), object_size(0), game(nullptr), script(nullptr), save(nullptr),
playback(nullptr), record(nullptr), io(nullptr), ioblock('\0'), ioerror('\0'),
codestart(0), objtable(0), eventtable(0), proptable(0), arraytable(0), dicttable(0),
@@ -52,18 +56,30 @@ Hugo::Hugo(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gam
objgrammar(0), objstart(0), objfinish(0), addflag(0), speaking(0), oopscount(0),
parse_called_twice(0), reparse_everything(0), full_buffer(false), recursive_call(false),
parse_location(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) {
+ 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), currentroutine(false),
+ complex_prop_breakpoint(false), trace_complex_prop_routine(false), properties(0),
+ current_locals(0)
+#endif
+ {
+ // heexpr
+ Common::fill(&eval[0], &eval[MAX_EVAL_ELEMENTS], 0);
+ Common::fill(&var[0], &var[MAXLOCALS + MAXGLOBALS], 0);
+
+ // hemisc
Common::fill(&context_command[0][0], &context_command[MAX_CONTEXT_COMMANDS][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][5], 0);
- Common::fill(&var[0], &var[MAXLOCALS + MAXGLOBALS], 0);
// heparse
Common::fill(&buffer[0], &buffer[MAXBUFFER + MAXWORDS], '\0');
@@ -80,6 +96,17 @@ Hugo::Hugo(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gam
// herun
Common::fill(&passlocal[0], &passlocal[MAXLOCALS], 0);
+
+ // heset
+ game_title[0] = '\0';
+
+#ifdef DEBUGGER
+ debug_line[0] = '\0';
+ Common::fill(&objectname[0], &objectname[MAX_OBJECT], nullptr);
+ Common::fill(&propertyname[0], &propertyname[MAX_PROPERTY], nullptr);
+ Common::fill(&codeline[0][0], &codeline[9][100], 0);
+ Common::fill(&localname[0][0], &localname[9][100], 0);
+#endif
}
void Hugo::runGame() {
diff --git a/engines/glk/hugo/hugo.h b/engines/glk/hugo/hugo.h
index a33c5998c8..de64744df6 100644
--- a/engines/glk/hugo/hugo.h
+++ b/engines/glk/hugo/hugo.h
@@ -40,6 +40,8 @@ class Hugo : public GlkAPI, public HTokens, public StringFunctions {
private:
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
@@ -48,6 +50,18 @@ private:
*/
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;
+
+
// hemisc
char gamefile[255];
int game_version;
@@ -119,9 +133,6 @@ private:
bool just_cleared_screen;
int secondwin_bottom;
- // heexpr
- int var[MAXLOCALS + MAXGLOBALS];
-
// heobject
int display_object; ///< i.e., non-existent (yet)
char display_needs_repaint; ///< for display object
@@ -196,6 +207,32 @@ private:
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;
+ int currentroutine;
+ bool complex_prop_breakpoint;
+ bool trace_complex_prop_routine;
+ char *objectname[MAX_OBJECT];
+ char *propertyname[MAX_PROPERTY];
+// CODE code[999];
+ CALL call[999];
+ int properties;
+ WINDOW window[99];
+ int codeline[9][100];
+ char localname[9][100];
+ int current_locals;
+#endif
private:
/**
* \defgroup heglk
@@ -491,6 +528,88 @@ private:
int Undo();
+ /**@}*/
+
+ /**
+ * \defgroup heobject - Object/property/attribute management functions
+ * @{
+ */
+
+#if defined (DEBUGGER)
+ int CheckinRange(uint v1, uint v2, const char *v3) {
+ // TODO: Where the heck is this actualy implemented in Gargoyle
+ 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) {}
+
+ 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) {}
+#endif
+
+ 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);
+
+ 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);
/**@}*/
private:
@@ -535,10 +654,7 @@ public:
void PromptMore() {}
void hugo_stopsample() {}
void hugo_stopmusic() {}
- void SetAttribute(int obj, int attr, int c) {}
- unsigned int PropAddr(int obj, int p, unsigned int offset) { return 0; }
- int GetProp(int obj, int p, int n, char s) { return 0; }
- void MoveObj(int obj, int p) {}
+ int hugo_hasgraphics() { return 0; }
};
} // End of namespace Hugo
diff --git a/engines/glk/hugo/hugo_defines.h b/engines/glk/hugo/hugo_defines.h
index 260586eab3..ce2d0061fd 100644
--- a/engines/glk/hugo/hugo_defines.h
+++ b/engines/glk/hugo/hugo_defines.h
@@ -31,9 +31,16 @@ namespace Hugo {
#define HEVERSION 3
#define HEREVISION 3
#define HEINTERIM ".0"
+#define GLK
+#define DEBUGGER
#define MAXOBJLIST 32
#define MAX_CONTEXT_COMMANDS 32
+#define MAX_EVAL_ELEMENTS 256
+#define MAX_GAME_TITLE 64
+#define MAX_DEBUG_LINE 256
+#define MAX_OBJECT 999
+#define MAX_PROPERTY 999
#define MAXBUFFER 255
#define MAXUNDO 1024
#define CHARWIDTH 1
@@ -140,6 +147,12 @@ browsing.
#define TAIL_RECURSION_ROUTINE (-1)
#define TAIL_RECURSION_PROPERTY (-2)
+#if defined (DEBUGGER)
+#define VIEW_CALLS 0
+#define VIEW_LOCALS 1
+#define CODE_WINDOW 2
+#endif
+
} // End of namespace Hugo
} // End of namespace Glk
diff --git a/engines/glk/hugo/hugo_types.h b/engines/glk/hugo/hugo_types.h
index 9298510504..3d7af86894 100644
--- a/engines/glk/hugo/hugo_types.h
+++ b/engines/glk/hugo/hugo_types.h
@@ -107,10 +107,33 @@ struct CODE_BLOCK {
int type; ///< see #defines, below
long brk; ///< break address, or 0 to indicate NOP
long returnaddr; ///< used only for do-while loops
+#if defined (DEBUGGER)
+ int dbnest; ///< for recovering from 'break'
+#endif
+
+ CODE_BLOCK() : type(0), brk(0), returnaddr(0)
+#if defined (DEBUGGER)
+ , dbnest(0)
+#endif
+ {
+ }
+};
+
+#if defined (DEBUGGER)
+struct CALL {
+ long addr;
+ bool param;
- CODE_BLOCK() : type(0), brk(0), returnaddr(0) {}
+ CALL() : addr(0), param(false) {}
};
+struct WINDOW {
+ int count;
+
+ WINDOW() : count(99) {}
+};
+#endif
+
} // End of namespace Hugo
} // End of namespace Glk
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 74ab60f9a8..41c53c38e7 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -74,6 +74,7 @@ MODULE_OBJS := \
hugo/detection.o \
hugo/heglk.o \
hugo/hemisc.o \
+ hugo/heobject.o \
hugo/htokens.o \
hugo/hugo.o \
hugo/stringfn.o \