- Added a RETI instruction for returning 15-bit signed immediate values.

- Changed Actor's Damage property into an actual function. All access to the damage property
  must now be done through GetMissileDamage. actor->GetMissileDamage(0, 1) is equivalent
  to the former actor->Damage, for the case where actor->Damage was not an expression. (I
  suppose I will probably need to make a thunk for DECORATE expressions that want to read it.)
- Cleaned up some decorate expression evaluation functions that are no longer used.

SVN r3919 (scripting)
This commit is contained in:
Randy Heit 2012-10-28 04:36:52 +00:00
parent 5e184260ac
commit 6e88529324
23 changed files with 271 additions and 196 deletions

View file

@ -797,7 +797,7 @@ public:
fixed_t velx, vely, velz; // velocity
SDWORD tics; // state tic counter
FState *state;
SDWORD Damage; // For missiles and monster railgun
VMFunction *Damage; // For missiles and monster railgun
int projectileKickback;
DWORD flags;
DWORD flags2; // Heretic flags

View file

@ -852,7 +852,7 @@ static int PatchThing (int thingy)
}
else if (linelen == 14 && stricmp (Line1, "Missile damage") == 0)
{
info->Damage = val;
info->Damage = CreateDamageFunction(val);
}
else if (linelen == 5)
{

View file

@ -47,7 +47,7 @@ static void BrainishExplosion (fixed_t x, fixed_t y, fixed_t z)
boom->SetState (state);
}
boom->effects = 0;
boom->Damage = 0; // disables collision detection which is not wanted here
boom->Damage = NULL; // disables collision detection which is not wanted here
boom->tics -= pr_brainscream() & 7;
if (boom->tics < 1)
boom->tics = 1;

View file

@ -144,7 +144,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom)
if (n == 0)
{
n = self->Damage; // GetMissileDamage (0, 1);
n = self->GetMissileDamage(0, 1);
}
if (spawntype == NULL)
{

View file

@ -65,7 +65,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BetaSkullAttack)
return 0;
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
A_FaceTarget(self);
damage = (pr_oldsoul()%8+1)*self->Damage;
damage = (pr_oldsoul()%8+1)*self->GetMissileDamage(0,1);
P_DamageMobj(self->target, self, self, damage, NAME_None);
return 0;
}

View file

@ -116,7 +116,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack)
fire->velx = baseFire->velx;
fire->vely = baseFire->vely;
fire->velz = baseFire->velz;
fire->Damage = 0;
fire->Damage = NULL;
fire->health = (i+1) * 2;
P_CheckMissileSpawn (fire);
}

View file

@ -356,7 +356,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LastZap)
{
mo->SetState (mo->FindState (NAME_Death));
mo->velz = 40*FRACUNIT;
mo->Damage = 0;
mo->Damage = NULL;
}
return 0;
}

View file

@ -302,6 +302,9 @@ size_t PClassActor::PropagateMark()
GC::Mark(OwnedStates[i].ActionFunc);
}
}
// Mark damage function
GC::Mark(((AActor *)Defaults)->Damage);
// marked += ActorInfo->NumOwnedStates * sizeof(FState);
return Super::PropagateMark();
}

View file

@ -2832,7 +2832,7 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
break;
case APROP_Damage:
actor->Damage = value;
actor->Damage = CreateDamageFunction(value);
break;
case APROP_Alpha:
@ -2994,7 +2994,7 @@ int DLevelScript::GetActorProperty (int tid, int property)
{
case APROP_Health: return actor->health;
case APROP_Speed: return actor->Speed;
case APROP_Damage: return actor->Damage; // Should this call GetMissileDamage() instead?
case APROP_Damage: return actor->GetMissileDamage(0,1);
case APROP_DamageFactor:return actor->DamageFactor;
case APROP_Alpha: return actor->alpha;
case APROP_RenderStyle: for (int style = STYLE_None; style < STYLE_Count; ++style)

View file

@ -136,6 +136,7 @@ IMPLEMENT_POINTY_CLASS (AActor)
DECLARE_POINTER (LastHeard)
DECLARE_POINTER (master)
DECLARE_POINTER (Poisoner)
DECLARE_POINTER (Damage)
END_POINTERS
AActor::~AActor ()
@ -2778,21 +2779,34 @@ CCMD(utid)
int AActor::GetMissileDamage (int mask, int add)
{
if ((Damage & 0xC0000000) == 0x40000000)
{
return EvalExpressionI (Damage & 0x3FFFFFFF, this);
}
if (Damage == 0)
if (Damage == NULL)
{
return 0;
}
VMFrameStack stack;
VMValue param = this;
VMReturn results[2];
int amount, calculated = false;
results[0].IntAt(&amount);
results[1].IntAt(&calculated);
if (stack.Call(Damage, &param, 1, results, 2) < 1)
{ // No results
return 0;
}
if (calculated)
{
return amount;
}
else if (mask == 0)
{
return add * Damage;
return add * amount;
}
else
{
return ((pr_missiledamage() & mask) + add) * Damage;
return ((pr_missiledamage() & mask) + add) * amount;
}
}

View file

@ -495,7 +495,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
else if (def == DEF_Projectile && sc.Compare ("Damage"))
{
sc.MustGetNumber ();
defaults->Damage = sc.Number;
defaults->Damage = CreateDamageFunction(sc.Number);
}
else if (def == DEF_Projectile && sc.Compare ("DamageType"))
{

View file

@ -261,6 +261,17 @@ void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag)
//
//==========================================================================
static void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, int labellen)
{
const char *marks = "=======================================================";
fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks);
fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n",
sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam);
VMDumpConstants(dump, sfunc);
fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code);
VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc);
}
static void FinishThingdef()
{
int errorcount = StateParams.ResolveAll();
@ -305,17 +316,10 @@ static void FinishThingdef()
sfunc->NumArgs = NAP;
func = sfunc;
#if 1
const char *marks = "=======================================================";
char label[64];
int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)",
tcall->ActorClass->TypeName.GetChars(),
tcall->FirstState, tcall->NumStates);
fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks);
fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n",
sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam);
VMDumpConstants(dump, sfunc);
fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code);
VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc);
tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates);
DumpFunction(dump, sfunc, label, labellen);
codesize += sfunc->CodeSize;
#endif
}
@ -324,10 +328,6 @@ static void FinishThingdef()
tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func);
}
}
#if 1
fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4);
#endif
fclose(dump);
for (i = 0; i < PClassActor::AllActorClasses.Size(); i++)
{
@ -348,7 +348,42 @@ static void FinishThingdef()
errorcount++;
continue;
}
if (def->Damage != NULL)
{
VMScriptFunction *sfunc;
FxDamageValue *dmg = (FxDamageValue *)def->Damage;
sfunc = dmg->GetFunction();
if (sfunc == NULL)
{
FCompileContext ctx(ti, true);
dmg->Resolve(ctx);
VMFunctionBuilder buildit;
buildit.Registers[REGT_POINTER].Get(1); // The self pointer
dmg->Emit(&buildit);
sfunc = buildit.MakeFunction();
sfunc->NumArgs = 1;
// Save this function in case this damage value was reused
// (which happens quite easily with inheritance).
dmg->SetFunction(sfunc);
}
def->Damage = sfunc;
#if 1
if (sfunc != NULL)
{
char label[64];
int labellen = mysnprintf(label, countof(label), "Function %s.Damage",
ti->TypeName.GetChars());
DumpFunction(dump, sfunc, label, labellen);
codesize += sfunc->CodeSize;
}
#endif
}
}
#if 1
fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4);
#endif
fclose(dump);
if (errorcount > 0)
{
I_Error("%d errors during actor postprocessing", errorcount);
@ -399,3 +434,23 @@ void LoadActors ()
// Base time: ~52 ms
}
//==========================================================================
//
// CreateDamageFunction
//
// Creates a damage function suitable for a constant, non-expressioned
// value.
//
//==========================================================================
VMScriptFunction *CreateDamageFunction(int dmg)
{
VMFunctionBuilder build;
build.Registers[REGT_POINTER].Get(1); // The self pointer
build.EmitRetInt(0, false, dmg);
build.EmitRetInt(1, true, 0);
VMScriptFunction *sfunc = build.MakeFunction();
sfunc->NumArgs = 1;
return sfunc;
}

View file

@ -141,8 +141,8 @@ public:
void Clear();
int Add(FxExpression *x, PClassActor *o, bool c);
int Reserve(int num, PClassActor *cls);
void Set(int num, FxExpression *x, bool cloned = false);
void Copy(int dest, int src, int cnt);
// void Set(int num, FxExpression *x, bool cloned = false);
// void Copy(int dest, int src, int cnt);
int ResolveAll();
FxExpression *Get(int no);
unsigned int Size() { return expressions.Size(); }
@ -184,6 +184,14 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass)
bag->statedef.MakeStateDefines(stateclass);
}
//==========================================================================
//
// Damage function creation
//
//==========================================================================
VMScriptFunction *CreateDamageFunction(int dmg);
//==========================================================================
//
// Action function lookup
@ -270,6 +278,7 @@ union FPropParam
int i;
float f;
const char *s;
FxExpression *exp;
};
typedef void (*PropHandler)(AActor *defaults, PClassActor *info, Baggage &bag, FPropParam *params);
@ -328,6 +337,9 @@ int MatchString (const char *in, const char **strings);
#define PROP_STRING_PARM(var, no) \
const char *var = params[(no)+1].s;
#define PROP_EXP_PARM(var, no) \
FxExpression *var = params[(no)+1].exp;
#define PROP_INT_PARM(var, no) \
int var = params[(no)+1].i;
@ -375,44 +387,6 @@ int MatchString (const char *in, const char **strings);
}
int EvalExpressionI (DWORD x, AActor *self);
int EvalExpressionCol (DWORD x, AActor *self);
FSoundID EvalExpressionSnd (DWORD x, AActor *self);
double EvalExpressionF (DWORD x, AActor *self);
fixed_t EvalExpressionFix (DWORD x, AActor *self);
FState *EvalExpressionState (DWORD x, AActor *self);
const PClass *EvalExpressionClass (DWORD x, AActor *self);
FName EvalExpressionName (DWORD x, AActor *self);
#if 0
#define ACTION_PARAM_START(count)
#define ACTION_PARAM_INT(var, i) \
int var = EvalExpressionI(ParameterIndex+i, self);
#define ACTION_PARAM_BOOL(var,i) \
bool var = !!EvalExpressionI(ParameterIndex+i, self);
#define ACTION_PARAM_FIXED(var,i) \
fixed_t var = EvalExpressionFix(ParameterIndex+i, self);
#define ACTION_PARAM_FLOAT(var,i) \
float var = float(EvalExpressionF(ParameterIndex+i, self));
#define ACTION_PARAM_DOUBLE(var,i) \
double var = EvalExpressionF(ParameterIndex+i, self);
#define ACTION_PARAM_CLASS(var,i) \
const PClass *var = EvalExpressionClass(ParameterIndex+i, self);
#define ACTION_PARAM_STATE(var,i) \
FState *var = EvalExpressionState(ParameterIndex+i, stateowner);
#define ACTION_PARAM_COLOR(var,i) \
PalEntry var = EvalExpressionCol(ParameterIndex+i, self);
#define ACTION_PARAM_SOUND(var,i) \
FSoundID var = EvalExpressionSnd(ParameterIndex+i, self);
#define ACTION_PARAM_STRING(var,i) \
const char *var = EvalExpressionName(ParameterIndex+i, self);
#define ACTION_PARAM_NAME(var,i) \
FName var = EvalExpressionName(ParameterIndex+i, self);
#define ACTION_PARAM_ANGLE(var,i) \
angle_t var = angle_t(EvalExpressionF(ParameterIndex+i, self)*ANGLE_90/90.f);
#endif
#define ACTION_SET_RESULT(v) do { if (numret > 0) { assert(ret != NULL); ret->SetInt(v); numret = 1; } } while(0)
// Checks to see what called the current action function

View file

@ -904,6 +904,28 @@ public:
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
//
//
//==========================================================================
class FxDamageValue : public FxExpression
{
FxExpression *val;
bool Calculated;
VMScriptFunction *MyFunction;
public:
FxDamageValue(FxExpression *v, bool calc);
~FxDamageValue();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
VMScriptFunction *GetFunction() const { return MyFunction; }
void SetFunction(VMScriptFunction *func) { MyFunction = func; }
};
FxExpression *ParseExpression (FScanner &sc, PClassActor *cls);

View file

@ -79,7 +79,7 @@ DEFINE_MEMBER_VARIABLE_ALIAS(momy, vely, AActor)
DEFINE_MEMBER_VARIABLE_ALIAS(momz, velz, AActor)
DEFINE_MEMBER_VARIABLE(scaleX, AActor)
DEFINE_MEMBER_VARIABLE(scaleY, AActor)
DEFINE_MEMBER_VARIABLE(Damage, AActor)
//DEFINE_MEMBER_VARIABLE(Damage, AActor)
DEFINE_MEMBER_VARIABLE(Score, AActor)
DEFINE_MEMBER_VARIABLE(accuracy, AActor)
DEFINE_MEMBER_VARIABLE(stamina, AActor)
@ -120,89 +120,6 @@ static PSymbol *FindDecorateBuiltinFunction(FName funcname, VMNativeFunction::Na
return sym;
}
//==========================================================================
//
// EvalExpression
// [GRB] Evaluates previously stored expression
//
//==========================================================================
int EvalExpressionI (DWORD xi, AActor *self)
{
FxExpression *x = StateParams.Get(xi);
if (x == NULL) return 0;
return x->EvalExpression (self).GetInt();
}
int EvalExpressionCol (DWORD xi, AActor *self)
{
FxExpression *x = StateParams.Get(xi);
if (x == NULL) return 0;
return x->EvalExpression (self).GetColor();
}
FSoundID EvalExpressionSnd (DWORD xi, AActor *self)
{
FxExpression *x = StateParams.Get(xi);
if (x == NULL) return 0;
return x->EvalExpression (self).GetSoundID();
}
double EvalExpressionF (DWORD xi, AActor *self)
{
FxExpression *x = StateParams.Get(xi);
if (x == NULL) return 0;
return x->EvalExpression (self).GetFloat();
}
fixed_t EvalExpressionFix (DWORD xi, AActor *self)
{
FxExpression *x = StateParams.Get(xi);
if (x == NULL) return 0;
ExpVal val = x->EvalExpression (self);
switch (val.Type)
{
default:
return 0;
case VAL_Int:
return val.Int << FRACBITS;
case VAL_Float:
return fixed_t(val.Float*FRACUNIT);
}
}
FName EvalExpressionName (DWORD xi, AActor *self)
{
FxExpression *x = StateParams.Get(xi);
if (x == NULL) return 0;
return x->EvalExpression (self).GetName();
}
const PClass * EvalExpressionClass (DWORD xi, AActor *self)
{
FxExpression *x = StateParams.Get(xi);
if (x == NULL) return 0;
return x->EvalExpression (self).GetClass();
}
FState *EvalExpressionState (DWORD xi, AActor *self)
{
FxExpression *x = StateParams.Get(xi);
if (x == NULL) return 0;
return x->EvalExpression (self).GetState();
}
//==========================================================================
//
//
@ -4025,6 +3942,64 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build)
return dest;
}
//==========================================================================
//
//
//
//==========================================================================
FxDamageValue::FxDamageValue(FxExpression *v, bool calc)
: FxExpression(v->ScriptPosition)
{
val = v;
ValueType = VAL_Unknown;
Calculated = calc;
MyFunction = NULL;
if (!calc)
{
assert(v->isConstant() && "Non-calculated damage must be constant");
}
}
FxDamageValue::~FxDamageValue()
{
SAFE_DELETE(val);
}
FxExpression *FxDamageValue::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(val, ctx)
if (!val->ValueType.isNumeric())
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
return NULL;
}
return this;
}
// This is a highly-specialized "expression" type that emits a complete function.
ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build)
{
if (val->isConstant())
{
build->EmitRetInt(0, false, val->EvalExpression(NULL).Int);
}
else
{
ExpEmit emitval = val->Emit(build);
assert(emitval.RegType == REGT_INT);
build->Emit(OP_RET, 0, REGT_INT | (emitval.Konst ? REGT_KONST : 0), emitval.RegNum);
}
build->Emit(OP_RETI, 1, 0x8000 | (int)Calculated);
return ExpEmit();
}
//==========================================================================
//
@ -4096,38 +4071,6 @@ int FStateExpressions::Reserve(int num, PClassActor *cls)
//
//==========================================================================
void FStateExpressions::Set(int num, FxExpression *x, bool cloned)
{
if (num >= 0 && num < int(Size()))
{
assert(expressions[num].expr == NULL || expressions[num].cloned);
expressions[num].expr = x;
expressions[num].cloned = cloned;
}
}
//==========================================================================
//
//
//
//==========================================================================
void FStateExpressions::Copy(int dest, int src, int cnt)
{
for(int i=0; i<cnt; i++)
{
// For now set only a reference because these expressions may change when being resolved
expressions[dest+i].expr = (FxExpression*)intptr_t(src+i);
expressions[dest+i].cloned = true;
}
}
//==========================================================================
//
//
//
//==========================================================================
int FStateExpressions::ResolveAll()
{
int errorcount = 0;

View file

@ -669,16 +669,26 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau
switch ((*p) & 223)
{
case 'X': // Expression in parentheses or number.
if (sc.CheckString ("("))
{
FxExpression *x = ParseExpression(sc, bag.Info);
conv.i = 0x40000000 | StateParams.Add(x, bag.Info, false);
FxExpression *x = NULL;
if (sc.CheckString ("("))
{
x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info)), true);
sc.MustGetStringName(")");
}
else
{
sc.MustGetNumber();
if (sc.Number != 0)
{
x = new FxDamageValue(new FxConstant(sc.Number, bag.ScriptPosition), false);
}
}
conv.exp = x;
params.Push(conv);
sc.MustGetStringName(")");
break;
}
// fall through
break;
case 'I':
sc.MustGetNumber();

View file

@ -449,7 +449,7 @@ DEFINE_PROPERTY(painthreshold, I, Actor)
//==========================================================================
DEFINE_PROPERTY(damage, X, Actor)
{
PROP_INT_PARM(id, 0);
PROP_EXP_PARM(id, 0);
// Damage can either be a single number, in which case it is subject
// to the original damage calculation rules. Or, it can be an expression
@ -457,7 +457,9 @@ DEFINE_PROPERTY(damage, X, Actor)
// compatibility reasons, expressions must be enclosed within
// parentheses.
defaults->Damage = id;
// Store this expression here for now. It will be converted to a function
// later once all actors have been processed.
defaults->Damage = (VMFunction *)id;
}
//==========================================================================

View file

@ -490,6 +490,27 @@ size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value)
}
}
//==========================================================================
//
// VMFunctionBuilder :: EmitRetInt
//
// Returns an integer, using either an immediate value or a constant
// register, as appropriate.
//
//==========================================================================
size_t VMFunctionBuilder::EmitRetInt(int retnum, bool final, int value)
{
if (value >= -16384 && value <= 16383)
{
return Emit(OP_RETI, retnum, value | (final << 15));
}
else
{
return Emit(OP_RETI, retnum, REGT_INT | REGT_KONST | (final ? REGT_FINAL : 0), GetConstantInt(value));
}
}
//==========================================================================
//
// VMFunctionBuilder :: Backpatch

View file

@ -37,6 +37,7 @@ public:
size_t Emit(int opcode, int opa, VM_SHALF opbc);
size_t Emit(int opcode, int opabc);
size_t EmitLoadInt(int regnum, int value);
size_t EmitRetInt(int retnum, bool final, int value);
void Backpatch(size_t addr, size_t target);
void BackpatchToHere(size_t addr);

View file

@ -43,6 +43,7 @@
#define RII16 MODE_AI | MODE_BCJOINT | MODE_BCIMMS
#define I24 MODE_ABCJOINT
#define I8 MODE_AIMMZ | MODE_BUNUSED | MODE_CUNUSED
#define I8I16 MODE_AIMMZ | MODE_BCIMMZ
#define __BCP MODE_AUNUSED | MODE_BCJOINT | MODE_BCPARAM
#define RPI8 MODE_AP | MODE_BIMMZ | MODE_CUNUSED
#define KPI8 MODE_AKP | MODE_BIMMZ | MODE_CUNUSED
@ -246,6 +247,22 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
}
break;
case OP_RETI:
if (a == 0 && code[i].i16 & 0x8000)
{
col = printf_wrapper(out, "%d", (code[i].i16 << 17) >> 17);
}
else
{
col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func);
col += print_reg(out, col, (code[i].i16 << 17) >> 17, MODE_IMMS, 16, func);
if (code[i].i16 & 0x8000)
{
col += printf_wrapper(out, " [final]");
}
}
break;
default:
if ((mode & MODE_BCTYPE) == MODE_BCCAST)
{

View file

@ -593,6 +593,18 @@ begin:
return a < numret ? a + 1 : numret;
}
NEXTOP;
OP(RETI):
assert(ret != NULL || numret == 0);
if (a < numret)
{
// Shifting by 17 to wipe out the final bit
ret[a].SetInt(((pc[-1].i16) << 17) >> 17);
}
if (pc[-1].i16 & 0x8000)
{
return a < numret ? a + 1 : numret;
}
NEXTOP;
OP(RESULT):
// This instruction is just a placeholder to indicate where a return
// value should be stored. It does nothing on its own and should not

View file

@ -81,6 +81,7 @@ xx(TAIL, tail, RPI8), // Call+Ret in a single instruction
xx(TAIL_K, tail, KPI8),
xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL)
xx(RET, ret, I8BCP), // Copy value from register encoded in BC to return value A, possibly returning
xx(RETI, reti, I8I16), // Copy immediate from BC to return value A, possibly returning
xx(TRY, try, I24), // When an exception is thrown, start searching for a handler at pc + ABC
xx(UNTRY, untry, I8), // Pop A entries off the exception stack
xx(THROW, throw, THROW), // A == 0: Throw exception object pB

View file

@ -41,7 +41,7 @@ ACTOR Actor native //: Thinker
native int tid;
native int TIDtoHate;
native int waterlevel;
native int damage;
//native int damage;
native fixed_t x;
native fixed_t y;
native fixed_t z;