diff --git a/src/namedef.h b/src/namedef.h index 17626092a..661c8be19 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -610,6 +610,7 @@ xx(DecoCallLineSpecial) xx(DecoNameToClass) xx(DecoFindMultiNameState) xx(DecoFindSingleNameState) +xx(Damage) // basic type names xx(Default) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 7f8bad6ea..fab33a95b 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -719,6 +719,20 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxDamage +// +//========================================================================== + +class FxDamage : public FxExpression +{ +public: + FxDamage(const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxArrayElement diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index eb8256778..148df60e7 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2424,6 +2424,11 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars()); } } + // the damage property needs special handling + else if (Identifier == NAME_Damage) + { + newex = new FxDamage(ScriptPosition); + } // now check the global identifiers. else if ((sym = ctx.FindGlobal(Identifier)) != NULL) { @@ -2516,6 +2521,66 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build) return me; } + +//========================================================================== +// +// +// +//========================================================================== + +FxDamage::FxDamage(const FScriptPosition &pos) +: FxExpression(pos) +{ +} + +//========================================================================== +// +// FxDamage :: Resolve +// +//========================================================================== + +FxExpression *FxDamage::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + ValueType = VAL_Int; + return this; +} + +//========================================================================== +// +// FxDamage :: Emit +// +// Call this actor's damage function, if it has one +// +//========================================================================== + +ExpEmit FxDamage::Emit(VMFunctionBuilder *build) +{ + ExpEmit dmgval(build, REGT_INT); + + // Get damage function + ExpEmit dmgfunc(build, REGT_POINTER); + build->Emit(OP_LO, dmgfunc.RegNum, 0/*self*/, build->GetConstantInt(myoffsetof(AActor, Damage))); + + // If it's non-null... + build->Emit(OP_EQA_K, 1, dmgfunc.RegNum, build->GetConstantAddress(0, ATAG_GENERIC)); + size_t nulljump = build->Emit(OP_JMP, 0); + + // ...call it + build->Emit(OP_PARAM, 0, REGT_POINTER, 0/*self*/); + build->Emit(OP_CALL, dmgfunc.RegNum, 1, 1); + build->Emit(OP_RESULT, 0, REGT_INT, dmgval.RegNum); + size_t notnulljump = build->Emit(OP_JMP, 0); + + // Otherwise, use 0 + build->BackpatchToHere(nulljump); + build->EmitLoadInt(dmgval.RegNum, 0); + build->BackpatchToHere(notnulljump); + + return dmgval; +} + + //========================================================================== // //