Initial commit
This commit is contained in:
582
engines/glk/hugo/heset.cpp
Normal file
582
engines/glk/hugo/heset.cpp
Normal file
@@ -0,0 +1,582 @@
|
||||
/* 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"
|
||||
|
||||
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
|
||||
*/
|
||||
buffer[0] = '\0';
|
||||
t = 0;
|
||||
for (a=1; a<=(int)MAXWORDS; a++)
|
||||
{
|
||||
if ((unsigned short)wd[a]!=UNKNOWN_WORD)
|
||||
Common::strcpy_s(buffer+t, sizeof(buffer) - t, GetWord(wd[a]));
|
||||
else
|
||||
hugo_itoa(parsed_number, buffer+t, 10, sizeof(buffer) - t);
|
||||
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)
|
||||
{
|
||||
Common::strlcpy(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
|
||||
Reference in New Issue
Block a user