diff options
author | Paul Gilbert | 2019-05-11 16:46:30 +1000 |
---|---|---|
committer | Paul Gilbert | 2019-05-12 10:19:47 +1000 |
commit | 4113183f5b3cc707c54b5723413c7e69b0f8f37c (patch) | |
tree | 39917e09d0f6362af786199b1bc8441f0e8493d8 /engines/glk | |
parent | 7f9eaf0f12632bd58b35862f6e57fb7dc67f3f44 (diff) | |
download | scummvm-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.cpp | 583 | ||||
-rw-r--r-- | engines/glk/hugo/hugo.h | 19 | ||||
-rw-r--r-- | engines/glk/module.mk | 1 |
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 \ |