- added compile time validation for SetAction, SetAI and SetMove.

the expression classes were deleted again, this can be done without them.
This commit is contained in:
Christoph Oelckers 2023-01-02 00:27:49 +01:00
parent bf577916ec
commit 47f9642294
6 changed files with 118 additions and 218 deletions

View file

@ -46,6 +46,7 @@
#include "v_font.h"
#include "gamecontrol.h"
#include "gi.h"
#include "games/duke/src/duke3d.h"
PFunction* FindBuiltinFunction(FName funcname);
@ -177,14 +178,81 @@ static FxExpression *ResolveGlobalCustomFunction(FxFunctionCall *func, FCompileC
return newfunc->Resolve(ctx);
}
}
// the following 3 are just for compile time argument validation, they do not affect code generation.
else if (func->MethodName == NAME_SetAction && isDukeEngine())
{
auto cls = ctx.Function->Variants[0].SelfClass;
if (cls == nullptr || !cls->isClass()) return func;
auto clas = static_cast<PClassType*>(cls)->Descriptor;
if (!clas->IsDescendantOf(RUNTIME_CLASS(Duke3d::DDukeActor))) return func;
if (CheckArgSize(NAME_SetAction, func->ArgList, 1, 1, ScriptPosition))
{
FxExpression* x;
x = func->ArgList[0] = func->ArgList[0]->Resolve(ctx);
if (x && x->isConstant() && (x->ValueType == TypeName || x->ValueType == TypeString))
{
auto c = static_cast<FxConstant*>(x);
auto nm = c->GetValue().GetName();
if (nm == NAME_None) return func;
int pos = Duke3d::LookupAction(clas, nm);
if (pos == 0)
{
ScriptPosition.Message(MSG_ERROR, "Invalid action '%s'", nm.GetChars());
delete func;
return nullptr;
}
}
}
}
else if (func->MethodName == NAME_SetAI && isDukeEngine())
{
auto cls = ctx.Function->Variants[0].SelfClass;
if (cls == nullptr || !cls->isClass()) return func;
auto clas = static_cast<PClassType*>(cls)->Descriptor;
if (!clas->IsDescendantOf(RUNTIME_CLASS(Duke3d::DDukeActor))) return func;
if (CheckArgSize(NAME_SetAI, func->ArgList, 1, 1, ScriptPosition))
{
FxExpression* x;
x = func->ArgList[0] = func->ArgList[0]->Resolve(ctx);
if (x && x->isConstant() && (x->ValueType == TypeName || x->ValueType == TypeString))
{
auto c = static_cast<FxConstant*>(x);
auto nm = c->GetValue().GetName();
if (nm == NAME_None) return func;
int pos = Duke3d::LookupAI(clas, nm);
if (pos == 0)
{
ScriptPosition.Message(MSG_ERROR, "Invalid AI '%s'", nm.GetChars());
delete func;
return nullptr;
}
}
}
}
else if (func->MethodName == NAME_SetMove && isDukeEngine())
{
auto cls = ctx.Function->Variants[0].SelfClass;
if (cls == nullptr || !cls->isClass()) return func;
auto clas = static_cast<PClassType*>(cls)->Descriptor;
if (!clas->IsDescendantOf(RUNTIME_CLASS(Duke3d::DDukeActor))) return func;
if (CheckArgSize(NAME_SetMove, func->ArgList, 1, 2, ScriptPosition))
{
FxExpression* x;
x = func->ArgList[0] = func->ArgList[0]->Resolve(ctx);
if (x && x->isConstant() && (x->ValueType == TypeName || x->ValueType == TypeString))
{
auto c = static_cast<FxConstant*>(x);
auto nm = c->GetValue().GetName();
if (nm == NAME_None) return func;
int pos = Duke3d::LookupMove(clas, nm);
if (pos == 0)
{
ScriptPosition.Message(MSG_ERROR, "Invalid move '%s'", nm.GetChars());
delete func;
return nullptr;
}
}
}
}
// most of these can be resolved right here. Only isWorldTour, isPlutoPak and isShareware can not if Duke is being played.
else if (func->MethodName == NAME_isDuke)
@ -258,152 +326,6 @@ static FxExpression *ResolveGlobalCustomFunction(FxFunctionCall *func, FCompileC
return func;
}
//==========================================================================
//
// FxSetActionCall
//
//==========================================================================
FxSetActionCall::FxSetActionCall(FxExpression *self, FxExpression* arg, const FScriptPosition &pos)
: FxExpression(EFX_ActionSpecialCall, pos)
{
Self = self;
Arg = arg;
}
//==========================================================================
//
//
//
//==========================================================================
FxSetActionCall::~FxSetActionCall()
{
SAFE_DELETE(Self);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxSetActionCall::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpEmit FxSetActionCall::Emit(VMFunctionBuilder *build)
{
return ExpEmit();
}
//==========================================================================
//
// FxSetAICall
//
//==========================================================================
FxSetAICall::FxSetAICall(FxExpression *self, FxExpression* arg, const FScriptPosition &pos)
: FxExpression(EFX_ActionSpecialCall, pos)
{
Self = self;
Arg = arg;
}
//==========================================================================
//
//
//
//==========================================================================
FxSetAICall::~FxSetAICall()
{
SAFE_DELETE(Self);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxSetAICall::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpEmit FxSetAICall::Emit(VMFunctionBuilder *build)
{
return ExpEmit();
}
//==========================================================================
//
// FxSetMoveCall
//
//==========================================================================
FxSetMoveCall::FxSetMoveCall(FxExpression *self, FxExpression* arg, const FScriptPosition &pos)
: FxExpression(EFX_ActionSpecialCall, pos)
{
Self = self;
Arg = arg;
}
//==========================================================================
//
//
//
//==========================================================================
FxSetMoveCall::~FxSetMoveCall()
{
SAFE_DELETE(Self);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxSetMoveCall::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpEmit FxSetMoveCall::Emit(VMFunctionBuilder *build)
{
return ExpEmit();
}
//==========================================================================
//
// code generation is only performed for some Duke checks that depend on CON

View file

@ -2,62 +2,6 @@
#include "codegen.h"
#include "coreactor.h"
//==========================================================================
//
//
//
//==========================================================================
class FxSetActionCall : public FxExpression
{
FxExpression *Self;
FxExpression *Arg;
public:
FxSetActionCall(FxExpression *self, FxExpression* arg, const FScriptPosition &pos);
~FxSetActionCall();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
//
//
//==========================================================================
class FxSetAICall : public FxExpression
{
FxExpression *Self;
FxExpression *Arg;
public:
FxSetAICall(FxExpression *self, FxExpression* arg, const FScriptPosition &pos);
~FxSetAICall();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
//
//
//==========================================================================
class FxSetMoveCall : public FxExpression
{
FxExpression *Self;
FxExpression *Arg;
public:
FxSetMoveCall(FxExpression *self, FxExpression* arg, const FScriptPosition &pos);
~FxSetMoveCall();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//

View file

@ -1,5 +1,6 @@
// Raze specific names
xx(0)
xx(no)
xx(IngameMenu)
xx(ListMenuItemBloodDripDrawer)
xx(UsermapMenu)
@ -53,3 +54,6 @@ xx(isDukeEngine)
xx(isBlood)
xx(isSW)
xx(isExhumed)
xx(ChangeAction)
xx(ChangeAI)
xx(ChangeMove)

View file

@ -247,9 +247,9 @@ bool checkhitswitch(int snum, walltype* wwal, DDukeActor* act);
void drawshadows(tspriteArray& tsprites, tspritetype* t, DDukeActor* h);
void applyanimations(tspritetype* t, DDukeActor* h, const DVector2& viewVec, DAngle viewang);
int LookupAction(DDukeActor* self, FName name);
int LookupMove(DDukeActor* self, FName name);
int LookupAI(DDukeActor* self, FName name);
int LookupAction(PClass* self, FName name);
int LookupMove(PClass* self, FName name);
int LookupAI(PClass* self, FName name);
inline int32_t krand(void)

View file

@ -506,22 +506,46 @@ void GameInterface::FinalizeSetup()
}
int LookupAction(DDukeActor* self, FName name)
int LookupAction(PClass* cls, FName name)
{
// todo
return 0;
while (true)
{
auto ainf = static_cast<PClassActor*>(cls)->ActorInfo();
for (int i = 0; i < ainf->NumActions; i++)
{
if (actions[ainf->FirstAction + i].name == name) return ainf->FirstAction + i;
}
if (cls == RUNTIME_CLASS(DDukeActor)) return 0;
cls = cls->ParentClass;
}
}
int LookupMove(DDukeActor* self, FName name)
int LookupMove(PClass* cls, FName name)
{
// todo
return 0;
while (true)
{
auto ainf = static_cast<PClassActor*>(cls)->ActorInfo();
for (int i = 0; i < ainf->NumMoves; i++)
{
if (actions[ainf->FirstMove + i].name == name) return ainf->FirstMove + i;
}
if (cls == RUNTIME_CLASS(DDukeActor)) return 0;
cls = cls->ParentClass;
}
}
int LookupAI(DDukeActor* self, FName name)
int LookupAI(PClass* cls, FName name)
{
// todo
return 0;
while (true)
{
auto ainf = static_cast<PClassActor*>(cls)->ActorInfo();
for (int i = 0; i < ainf->NumAIs; i++)
{
if (actions[ainf->FirstAI + i].name == name) return ainf->FirstAI + i;
}
if (cls == RUNTIME_CLASS(DDukeActor)) return 0;
cls = cls->ParentClass;
}
}

View file

@ -714,8 +714,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, aim, aim_)
void Duke_SetAction(DDukeActor* self, int intname)
{
int ndx = LookupAction(self, FName(ENamedName(intname)));
int ndx = LookupAction(self->GetClass(), FName(ENamedName(intname)));
self->curAction = &actions[ndx];
self->actioncounter = self->curframe = 0;
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, SetAction, Duke_SetAction)
@ -728,7 +730,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, SetAction, Duke_SetAction)
void Duke_SetMove(DDukeActor* self, int intname, int flags)
{
int ndx = LookupMove(self, FName(ENamedName(intname)));
int ndx = LookupMove(self->GetClass(), FName(ENamedName(intname)));
self->curMove = &moves[ndx];
self->spr.hitag = flags;
}
@ -744,11 +746,15 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, SetMove, Duke_SetMove)
void Duke_SetAI(DDukeActor* self, int intname)
{
int ndx = LookupAI(self, FName(ENamedName(intname)));
int ndx = LookupAI(self->GetClass(), FName(ENamedName(intname)));
self->curMove = &moves[ais[ndx].move];
self->curAction = &actions[ais[ndx].action];
self->spr.hitag = ais[ndx].moveflags;
self->curAI = ais[ndx].name;
self->actioncounter = self->curframe = 0;
self->counter = 0;
if (self->spr.hitag & random_angle)
self->spr.Angles.Yaw = randomAngle();
}
DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, SetAI, Duke_SetAI)