aboutsummaryrefslogtreecommitdiff
path: root/engines/glk
diff options
context:
space:
mode:
authorPaul Gilbert2019-05-11 16:46:30 +1000
committerPaul Gilbert2019-05-12 10:19:47 +1000
commit4113183f5b3cc707c54b5723413c7e69b0f8f37c (patch)
tree39917e09d0f6362af786199b1bc8441f0e8493d8 /engines/glk
parent7f9eaf0f12632bd58b35862f6e57fb7dc67f3f44 (diff)
downloadscummvm-rg350-4113183f5b3cc707c54b5723413c7e69b0f8f37c.tar.gz
scummvm-rg350-4113183f5b3cc707c54b5723413c7e69b0f8f37c.tar.bz2
scummvm-rg350-4113183f5b3cc707c54b5723413c7e69b0f8f37c.zip
GLK: HUGO: Added heset
Diffstat (limited to 'engines/glk')
-rw-r--r--engines/glk/hugo/heset.cpp583
-rw-r--r--engines/glk/hugo/hugo.h19
-rw-r--r--engines/glk/module.mk1
3 files changed, 601 insertions, 2 deletions
diff --git a/engines/glk/hugo/heset.cpp b/engines/glk/hugo/heset.cpp
new file mode 100644
index 0000000000..b7e40e07cd
--- /dev/null
+++ b/engines/glk/hugo/heset.cpp
@@ -0,0 +1,583 @@
+/* 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 {
+
+void Hugo::RunSet(int gotvalue) {
+ char inc = 0; /* increment/decrement */
+ char temparrexpr, propval = 0;
+ int a = 0, t = 0, obj = 0;
+ int newl = 0; /* new length */
+ int newp = 0; /* new property val */
+ unsigned int element = 0; /* of an array */
+
+ unsigned short n, m, v; /* must be 16 bits */
+
+ inobj = 0;
+
+ if (gotvalue!=-1)
+ {
+ obj = gotvalue;
+ t = SetCompound(t);
+ goto StoreVal;
+ }
+
+ t = MEM(codeptr);
+
+ switch (t)
+ {
+ case OBJECTNUM_T:
+ {
+ codeptr++;
+ obj = PeekWord(codeptr);
+ codeptr += 2;
+ t = SetCompound(t);
+ break;
+ }
+
+ case VAR_T:
+ {
+ a = MEM(codeptr + 1);
+
+ /* Check for ++, --, +=, etc. */
+ inc = IsIncrement(codeptr+2);
+
+ if (MEM(codeptr + 2)==EQUALS_T || inc)
+ {
+ if (a < MAXGLOBALS) SaveUndo(VAR_T, a, var[a], 0, 0);
+
+ /* anonymous function */
+ if (!inc && MEM(codeptr+3)==EOL_T)
+ {
+ var[a] = GetAnonymousFunction(codeptr+4);
+ return;
+ }
+
+ if (inc)
+ {
+ var[a] = (Increment(var[a], inc)) + incdec;
+
+ /* backward-compatibility tweak */
+ if ((game_version<23) && MEM(codeptr)!=CLOSE_BRACE_T) codeptr--;
+
+ codeptr++; /* eol */
+ }
+ else
+ {
+ codeptr += 3;
+ inexpr = 1;
+ SetupExpr();
+ inexpr = 0;
+ v = EvalExpr(0);
+ var[a] = v;
+ }
+
+ /* If a global variable */
+ if (a < MAXGLOBALS)
+ {
+ if (a==wordcount) words = var[wordcount];
+ }
+
+ return;
+ }
+
+ obj = var[a];
+ codeptr += 2;
+ t = SetCompound(t);
+
+ break;
+ }
+
+ case WORD_T: /* "word" */
+ {
+ codeptr += 2; /* skip "[" */
+ n = GetValue();
+#if defined (DEBUGGER)
+ if ((debug_eval) && debug_eval_error)
+ return;
+#endif
+ codeptr += 2; /* skip "] =" */
+ inexpr = 1;
+ SetupExpr();
+ inexpr = 0;
+
+GetNextWord:
+ if (n >= MAXWORDS) n = MAXWORDS-1;
+ SaveUndo(WORD_T, n, wd[n], 0, 0);
+ wd[n] = EvalExpr(0);
+
+ if (MEM(codeptr)==COMMA_T)
+ {
+ codeptr++;
+ n++;
+ goto GetNextWord;
+ }
+
+ /* Have to (rather unfortunately) rebuild the entire
+ input buffer and word array here
+ */
+ strcpy(buffer, "");
+ t = 0;
+ for (a=1; a<=(int)MAXWORDS; a++)
+ {
+ if ((unsigned short)wd[a]!=UNKNOWN_WORD)
+ strcpy(buffer+t, GetWord(wd[a]));
+ else
+ itoa(parsed_number, buffer+t, 10);
+ word[a] = buffer + t;
+ t+=strlen(word[a])+1;
+ }
+
+ if (n>(unsigned)var[wordcount])
+ var[wordcount] = n;
+
+ return;
+ }
+
+ case ARRAYDATA_T:
+ case ARRAY_T:
+ {
+ char af_flag = false;
+ /* array[n]... */
+ if (t==ARRAYDATA_T)
+ {
+ m = PeekWord(codeptr + 1);
+ codeptr += 4; /* "[" */
+ n = GetValue();
+#if defined (DEBUGGER)
+ if ((debug_eval) && debug_eval_error)
+ return;
+#endif
+ codeptr++; /* "]" */
+ }
+
+ /* ...or array val[n] */
+ else
+ {
+ codeptr++;
+ m = GetValue();
+#if defined (DEBUGGER)
+ if ((debug_eval) && debug_eval_error)
+ return;
+#endif
+ codeptr++; /* "[" */
+ n = GetValue();
+#if defined (DEBUGGER)
+ if ((debug_eval) && debug_eval_error)
+ return;
+#endif
+ codeptr++; /* "]" */
+ }
+
+ if (game_version>=22)
+ {
+ /* Convert to word value */
+ m*=2;
+
+ if (game_version>=23)
+ /* Space for array length */
+ a = 2;
+ }
+
+#if defined (DEBUGGER)
+ CheckinRange(m+a+n*2, debug_workspace, "array data");
+#endif
+ /* Check for ++, --, +=, etc. */
+ inc = IsIncrement(codeptr);
+ if (inc)
+ {
+ defseg = arraytable;
+ v = PeekWord(m+a+n*2);
+ defseg = gameseg;
+ v = (Increment(v, inc)) + incdec;
+
+ codeptr++; /* eol */
+
+ element = m+a+n*2;
+
+ goto WriteArrayValue;
+ }
+
+ if (MEM(codeptr)==EQUALS_T)
+ {
+ codeptr++;
+
+ do
+ {
+ element = m+a+n*2;
+
+ temparrexpr = arrexpr;
+ arrexpr = true;
+
+ /* anonymous function */
+ if (!inc && MEM(codeptr)==EOL_T)
+ {
+ v = GetAnonymousFunction(codeptr+1);
+ af_flag = true;
+ }
+ else
+ {
+ v = GetValue();
+ }
+#if defined (DEBUGGER)
+ if ((debug_eval) && debug_eval_error)
+ return;
+#endif
+ if (arrexpr==false && MEM(codeptr-1)==76)
+ codeptr--;
+ arrexpr = temparrexpr;
+
+ if (!af_flag && (MEM(codeptr)==COMMA_T || MEM(codeptr)==CLOSE_BRACKET_T))
+ codeptr++;
+WriteArrayValue:
+ defseg = arraytable;
+
+ /* Make sure the value to be written is within range */
+ if ((element>0) && (element < (unsigned)(dicttable-arraytable)*16))
+ {
+ SaveUndo(ARRAYDATA_T, m+a, n, PeekWord(element), 0);
+
+ PokeWord(element, (unsigned int)v);
+ }
+
+ defseg = gameseg;
+
+ if (inc || af_flag) return;
+
+ n++;
+ }
+ while (MEM(codeptr)!=EOL_T);
+
+ codeptr++;
+ return;
+ }
+
+ defseg = arraytable;
+ obj = PeekWord((unsigned int)(m+a + n*2));
+ defseg = gameseg;
+ t = SetCompound(t);
+
+ break;
+ }
+ }
+
+
+StoreVal:
+
+ /* Now store the evaluated expression in the appropriate place... */
+
+ /*
+ t = 1: property
+ t = 2: attribute
+ t = 3: not attribute
+ t = 4: property reference
+ */
+
+ n = 1;
+
+ if (t==4)
+ {
+ inobj = true;
+ n = GetValue();
+
+#if defined (DEBUGGER)
+ if ((debug_eval) && debug_eval_error)
+ return;
+#endif
+ inobj = false;
+
+LoopBack:
+ if (MEM(codeptr)==IS_T || MEM(codeptr)==DECIMAL_T)
+ {
+ obj = GetProp(obj, set_value, n, 0);
+ t = SetCompound(t);
+ goto LoopBack;
+ }
+ /* Don't set t = 1 if it changed above before going back
+ to LoopBack:
+ */
+ else if (t==4)
+ t = 1; /* Just a property */
+ }
+ else if (t==1)
+ {
+ while (MEM(codeptr)==IS_T || MEM(codeptr)==DECIMAL_T)
+ {
+ obj = GetProp(obj, set_value, n, 0);
+ t = SetCompound(t);
+ }
+ }
+
+ switch (t)
+ {
+ case 1:
+ {
+ incdec = 0;
+
+ if (MEM(codeptr) != EQUALS_T)
+ {
+ /* Check for ++, --, +=, etc. */
+ if (!(inc = IsIncrement(codeptr)))
+ {
+#if defined (DEBUGGER)
+ if (debug_eval)
+ {
+ debug_eval_error = true;
+ return;
+ }
+#endif
+ FatalError(ILLEGAL_OP_E);
+ }
+ else if (MEM(codeptr)==EOL_T)
+ {
+ goto GetNextPropVal;
+ }
+ }
+ else
+ codeptr++;
+
+ /* Property routine (anonymous function)... */
+ if (MEM(codeptr)==EOL_T)
+ {
+ /* m = skipptr to the end of the property
+ routine block (i.e., the next statement
+ following it)
+ */
+ m = PeekWord(codeptr + 1);
+
+ newl = PROP_ROUTINE;
+ newp =(unsigned int)(((codeptr + 4)+(codeptr + 4)%address_scale)/address_scale);
+ codeptr = (long)m*address_scale;
+ m = PropAddr(obj, set_value, 0);
+ }
+
+ /* ...or not */
+ else
+ {
+GetNextPropVal:
+ inexpr = false;
+ temparrexpr = multiprop;
+ multiprop = true;
+ propval = true;
+ if (!inc) newp = GetValue();
+#if defined (DEBUGGER)
+ if ((debug_eval) && debug_eval_error)
+ return;
+#endif
+
+ if (!multiprop)
+ codeptr--;
+ multiprop = temparrexpr;
+
+ m = PropAddr(obj, set_value, 0);
+ if (m)
+ {
+ defseg = proptable;
+ newl = Peek((unsigned int)m + 1);
+ if (newl==PROP_ROUTINE) newl = 1;
+ }
+
+ /* Deal with setting built-in display object
+ properties
+ */
+ else if ((obj==display_object) && n==1)
+ {
+ if (set_value==title_caption)
+ {
+ strncpy(game_title, GetWord(newp), MAX_GAME_TITLE);
+ hugo_setgametitle(game_title);
+ }
+ else if (set_value==needs_repaint)
+ {
+ display_needs_repaint = (char)newp;
+ }
+ }
+#if defined (DEBUGGER)
+/*
+ else if (runtime_warnings)
+ {
+ RuntimeWarning("Setting non-existent property");
+ }
+*/
+#endif
+ }
+
+ /* Write property obj.z = newl words of newp */
+
+ if (m && (int)n <= 0)
+ {
+#if defined (DEBUGGER)
+ RuntimeWarning("Property element <= 0");
+#endif
+ if (inc) codeptr++;
+ }
+ else if (m && (int)n <= newl)
+ {
+ defseg = proptable;
+
+#if defined (DEBUGGER)
+ CheckinRange((unsigned)n, (unsigned)Peek(m+1), "property element");
+#endif
+ /* Check to make sure this property value is within range */
+ if ((unsigned)(m+2+(n-1)*2)<(unsigned)(eventtable-proptable)*16)
+ {
+ SaveUndo(PROP_T, obj, (unsigned int)set_value, n, PeekWord((unsigned int)(m+2+(n-1)*2)));
+
+ /* Save the (possibly changed) length) */
+ Poke((unsigned int)m + 1, (unsigned char)newl);
+
+ /* An assignment such as obj.prop++ or
+ obj.prop += ...
+ */
+ if (inc)
+ {
+ PokeWord((unsigned int)(m+2+(n-1)*2), Increment(PeekWord((unsigned int)(m+2+(n-1)*2)), inc) + incdec);
+ codeptr++; /* eol */
+ }
+
+ /* A regular obj.prop = ... assignment */
+ else
+ PokeWord((unsigned int)(m+2+(n-1)*2), newp);
+ }
+ }
+ else if (inc) codeptr++; /* eol */
+
+ defseg = gameseg;
+
+ if (inc) return;
+
+ if (propval && MEM(codeptr)==COMMA_T)
+ {n++;
+ codeptr++;
+ goto GetNextPropVal;}
+
+ if (propval) codeptr++;
+ if (MEM(codeptr)==EOL_T) codeptr++;
+ return;
+ }
+
+ case 2:
+ case 3:
+ {
+ModifyAttribute:
+
+#if defined (DEBUGGER)
+ CheckinRange((unsigned int)set_value, (unsigned)attributes, "attribute");
+#endif
+ SaveUndo(ATTR_T, obj, (unsigned int)set_value, TestAttribute(obj, (unsigned int)set_value, 0), 0);
+
+ SetAttribute(obj, set_value, (t==2));
+ t = 2; /* reset after 'not' */
+
+ if (MEM(codeptr++)==EOL_T) return;
+
+ /* Allow multiple attributes, comma-separated */
+ if (MEM(codeptr)==COMMA_T)
+ codeptr++;
+
+ if (MEM(codeptr)==NOT_T)
+ {
+ t = 3;
+ codeptr++;
+ }
+
+ set_value = GetValue();
+ goto ModifyAttribute;
+ }
+
+ default:
+ {
+#if defined (DEBUGGER)
+ if (debug_eval)
+ {
+ debug_eval_error = true;
+ return;
+ }
+#endif
+ /* Not any sort of variable data type */
+ FatalError(ILLEGAL_OP_E);
+ }
+ }
+}
+
+unsigned int Hugo::GetAnonymousFunction(long addr) {
+ long skipaddr;
+ unsigned int af_addr;
+
+ skipaddr = PeekWord(addr);
+ /* The address of the anonymous function is the next address boundary,
+ calculated as:
+ (((addr+2)/address_scale+1)*address_scale)/address_scale */
+ af_addr =(unsigned int)((addr+2)/address_scale+1);
+ codeptr = (long)skipaddr*address_scale;
+ return af_addr;
+}
+
+int Hugo::SetCompound(int t) {
+ if (Peek(codeptr)==DECIMAL_T) /* obj.property */
+ {
+ codeptr++;
+ inobj = 1;
+ set_value = GetValue(); /* the prop. # */
+ inobj = 0;
+
+ if (Peek(codeptr)==POUND_T) /* if obj.prop #... */
+ {
+ codeptr++;
+ return 4;
+ }
+ return 1;
+ }
+
+ if (Peek(codeptr)==IS_T) /* obj is ... */
+ {
+ inobj = 1;
+ if (Peek(codeptr+1)==NOT_T)
+ {
+ codeptr += 2;
+ set_value = GetValue(); /* the attr. # */
+ inobj = 0;
+ return 3;
+ }
+
+ codeptr++;
+ set_value = GetValue(); /* the attr. # */
+ inobj = 0;
+ return 2;
+ }
+
+#if defined (DEBUGGER)
+ if (debug_eval)
+ debug_eval_error = true;
+ else
+#endif
+
+ FatalError(ILLEGAL_OP_E);
+
+ return 0;
+}
+
+} // End of namespace Hugo
+} // End of namespace Glk
diff --git a/engines/glk/hugo/hugo.h b/engines/glk/hugo/hugo.h
index 98fbf9058a..046b6654dc 100644
--- a/engines/glk/hugo/hugo.h
+++ b/engines/glk/hugo/hugo.h
@@ -916,6 +916,23 @@ private:
/**@}*/
/**
+ * \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
* @{
*/
@@ -1066,8 +1083,6 @@ private:
void SetupWatchEval(int num) {}
bool EvalWatch() { return false; }
-
- void RunSet(int v) {}
#endif
public:
/**
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 00641dd854..fcb47149c1 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -78,6 +78,7 @@ MODULE_OBJS := \
hugo/heobject.o \
hugo/heparse.o \
hugo/herun.o \
+ hugo/heset.o \
hugo/htokens.o \
hugo/hugo.o \
hugo/stringfn.o \