- 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.
This commit is contained in:
Christoph Oelckers 2016-11-05 17:14:16 +01:00
parent 24925c88a8
commit 98fa3d2d93
8 changed files with 157 additions and 24 deletions

View File

@ -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;
}
//==========================================================================

View File

@ -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;
}

View File

@ -683,6 +683,7 @@ xx(BuiltinNameToClass)
xx(BuiltinFindMultiNameState)
xx(BuiltinFindSingleNameState)
xx(BuiltinHandleRuntimeState)
xx(BuiltinGetDefault)
xx(Damage)
// basic type names

View File

@ -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<PPointer*>(obj->ValueType)->PointedType, true);
return this;
}
//==========================================================================
//
//
//
//==========================================================================
int BuiltinGetDefault(VMFrameStack *stack, VMValue *param, TArray<VMValue> &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<PPointer *>(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<PPointer>(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;
}
//==========================================================================

View File

@ -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);
};
//==========================================================================

View File

@ -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.

View File

@ -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<Actor> 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);

View File

@ -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