From 98fa3d2d939d663acc1e2cf95c92dc0940f8c130 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 5 Nov 2016 17:14:16 +0100 Subject: [PATCH] - added an accessor to the actor defaults. This might have been possible with less work using a function but that would have necessitated some type casts when using it on subclasses. - scriptified A_BarrelDestroy to test the above. --- src/dobjtype.cpp | 4 +- src/g_doom/a_doommisc.cpp | 18 ---- src/namedef.h | 1 + src/scripting/codegeneration/codegen.cpp | 126 ++++++++++++++++++++++- src/scripting/codegeneration/codegen.h | 6 +- src/scripting/zscript/zcc-parse.lemon | 8 ++ wadsrc/static/zscript/actor.txt | 1 - wadsrc/static/zscript/doom/doommisc.txt | 17 +++ 8 files changed, 157 insertions(+), 24 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 1b5d3bc7e..e3c638062 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1508,10 +1508,10 @@ void PPointer::SetOps() bool PPointer::IsMatch(intptr_t id1, intptr_t id2) const { - assert(id2 == 0); + assert(id2 == 0 || id2 == 1); PType *pointat = (PType *)id1; - return pointat == PointedType; + return pointat == PointedType && (!!id2) == IsConst; } //========================================================================== diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index 534ed400e..9f3178295 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -29,21 +29,3 @@ #include "a_revenant.cpp" #include "a_scriptedmarine.cpp" -// The barrel of green goop ------------------------------------------------ - -DEFINE_ACTION_FUNCTION(AActor, A_BarrelDestroy) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (dmflags2 & DF2_BARRELS_RESPAWN) - { - self->Height = self->GetDefault()->Height; - self->renderflags |= RF_INVISIBLE; - self->flags &= ~MF_SOLID; - } - else - { - self->Destroy (); - } - return 0; -} diff --git a/src/namedef.h b/src/namedef.h index 809c28a9c..8f1a54337 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -683,6 +683,7 @@ xx(BuiltinNameToClass) xx(BuiltinFindMultiNameState) xx(BuiltinFindSingleNameState) xx(BuiltinHandleRuntimeState) +xx(BuiltinGetDefault) xx(Damage) // basic type names diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 39034c752..4ece6ad4f 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5015,6 +5015,27 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) delete this; return x->Resolve(ctx); } + + if (Identifier == NAME_Default) + { + if (ctx.Function->Variants[0].SelfClass == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from static function"); + delete this; + return nullptr; + } + if (!ctx.Function->Variants[0].SelfClass->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); + delete this; + return nullptr; + } + + FxExpression * x = new FxClassDefaults(new FxSelf(ScriptPosition), ScriptPosition); + delete this; + return x->Resolve(ctx); + } + // Ugh, the horror. Constants need to be taken from the owning class, but members from the self class to catch invalid accesses here... // see if the current class (if valid) defines something with this name. PSymbolTable *symtbl; @@ -5348,6 +5369,95 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build) } +//========================================================================== +// +// +// +//========================================================================== + +FxClassDefaults::FxClassDefaults(FxExpression *X, const FScriptPosition &pos) + : FxExpression(EFX_ClassDefaults, pos) +{ + obj = X; + EmitTail = false; +} + +FxClassDefaults::~FxClassDefaults() +{ + SAFE_DELETE(obj); +} + + +//========================================================================== +// +// +// +//========================================================================== + +PPrototype *FxClassDefaults::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxClassDefaults::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(obj, ctx); + assert(obj->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))); + ValueType = NewPointer(static_cast(obj->ValueType)->PointedType, true); + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +int BuiltinGetDefault(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +{ + assert(numparam == 1); + PARAM_POINTER_AT(0, obj, DObject); + ACTION_RETURN_OBJECT(obj->GetClass()->Defaults); +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) +{ + EmitParameter(build, obj, ScriptPosition); + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinGetDefault, BuiltinGetDefault); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + auto callfunc = ((PSymbolVMFunction *)sym)->Function; + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); + + if (EmitTail) + { + ExpEmit call; + call.Final = true; + return call; + } + + ExpEmit out(build, REGT_POINTER); + build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum); + return out; + +} + //========================================================================== // // @@ -5465,6 +5575,21 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) CHECKRESOLVED(); SAFE_RESOLVE(classx, ctx); + if (membervar->SymbolName == NAME_Default) + { + if (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) + || !static_cast(classx->ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(AActor))) + { + ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); + delete this; + return nullptr; + } + FxExpression * x = new FxClassDefaults(classx, ScriptPosition); + classx = nullptr; + delete this; + return x->Resolve(ctx); + } + if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { PPointer *ptrtype = dyn_cast(classx->ValueType); @@ -5581,7 +5706,6 @@ FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition : FxStructMember(x, mem, pos) { ExprType = EFX_ClassMember; - //if (classx->IsDefaultObject()) Readonly=true; } //========================================================================== diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index b118b8d5d..a244e519e 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -355,12 +355,14 @@ public: class FxClassDefaults : public FxExpression { FxExpression *obj; + bool EmitTail; public: - FxClassDefaults(FxExpression*, const FScriptPosition &); + FxClassDefaults(FxExpression *, const FScriptPosition &); ~FxClassDefaults(); + PPrototype *ReturnProto(); FxExpression *Resolve(FCompileContext&); - bool IsDefaultObject() const; + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 666eff5a2..fc707428e 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -224,6 +224,14 @@ dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). A->AppendSibling(id2); X = A; /*X-overwrites-A*/ } +dottable_id(X) ::= dottable_id(A) DOT DEFAULT. +{ + NEW_AST_NODE(Identifier,id2,A); + id2->Id = NAME_Default; + A->AppendSibling(id2); + X = A; /*X-overwrites-A*/ +} + // a bit of a hack to allow the 'color' token to be used inside default properties. // as a variable name it is practically meaningless because it cannot defined // as such anywhere so it will always produce an error during processing. diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index fdadab53c..efdeb3ef1 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -357,7 +357,6 @@ class Actor : Thinker native native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff", name damagetype = "none"); native void A_Stop(); native void A_Respawn(int flags = 1); - native void A_BarrelDestroy(); native void A_QueueCorpse(); native void A_DeQueueCorpse(); native void A_LookEx(int flags = 0, float minseedist = 0, float maxseedist = 0, float maxheardist = 0, float fov = 0, state label = null); diff --git a/wadsrc/static/zscript/doom/doommisc.txt b/wadsrc/static/zscript/doom/doommisc.txt index 80e330a68..a11c411f8 100644 --- a/wadsrc/static/zscript/doom/doommisc.txt +++ b/wadsrc/static/zscript/doom/doommisc.txt @@ -34,6 +34,23 @@ class ExplosiveBarrel : Actor } } +extend class Actor +{ + void A_BarrelDestroy() + { + if (GetCVar("sv_barrelrespawn")) + { + Height = Default.Height; + bInvisible = true; + bSolid = false; + } + else + { + Destroy(); + } + } +} + // Bullet puff ------------------------------------------------------------- class BulletPuff : Actor