mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 13:01:47 +00:00
- scriptified the functions in a_possessed.cpp and added the needed exports and constants.
- fixed: Script functions did not receive the function name when being created. - relaxed the asserts for PARAM_STATE, because the VM knows nothing about ATAG_STATE. Any state variable's content (e.g. Actor.SeeState) will receive ATAG_GENERIC, rather than ATAG_STATE. - added a 'NeedResult' flag so that certain operations can create shorter code if the result of the expression is not needed. So far only used for postdecrement/increment statements on local variables (which is the most frequent case where this matters.) - fixed postincrement and decrement for local variables. Due to the result preservation semantics it created faulty code.
This commit is contained in:
parent
33d00070b5
commit
823c52aeb2
16 changed files with 246 additions and 170 deletions
|
@ -842,7 +842,6 @@ set( NOT_COMPILED_SOURCE_FILES
|
|||
g_doom/a_keen.cpp
|
||||
g_doom/a_lostsoul.cpp
|
||||
g_doom/a_painelemental.cpp
|
||||
g_doom/a_possessed.cpp
|
||||
g_doom/a_revenant.cpp
|
||||
g_doom/a_scriptedmarine.cpp
|
||||
g_doom/a_spidermaster.cpp
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "a_keen.cpp"
|
||||
#include "a_lostsoul.cpp"
|
||||
#include "a_painelemental.cpp"
|
||||
#include "a_possessed.cpp"
|
||||
#include "a_revenant.cpp"
|
||||
#include "a_spidermaster.cpp"
|
||||
#include "a_scriptedmarine.cpp"
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "m_random.h"
|
||||
#include "s_sound.h"
|
||||
#include "p_local.h"
|
||||
#include "p_enemy.h"
|
||||
#include "gstrings.h"
|
||||
#include "a_action.h"
|
||||
#include "vm.h"
|
||||
*/
|
||||
|
||||
static FRandom pr_posattack ("PosAttack");
|
||||
static FRandom pr_sposattack ("SPosAttack");
|
||||
static FRandom pr_cposattack ("CPosAttack");
|
||||
static FRandom pr_cposrefire ("CPosRefire");
|
||||
|
||||
//
|
||||
// A_PosAttack
|
||||
//
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_PosAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
int damage;
|
||||
DAngle angle;
|
||||
DAngle slope;
|
||||
|
||||
if (!self->target)
|
||||
return 0;
|
||||
|
||||
A_FaceTarget (self);
|
||||
angle = self->Angles.Yaw;
|
||||
slope = P_AimLineAttack (self, angle, MISSILERANGE);
|
||||
|
||||
S_Sound (self, CHAN_WEAPON, "grunt/attack", 1, ATTN_NORM);
|
||||
angle += pr_posattack.Random2() * (22.5 / 256);
|
||||
damage = ((pr_posattack()%5)+1)*3;
|
||||
P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void A_SPosAttack2 (AActor *self)
|
||||
{
|
||||
int i;
|
||||
DAngle bangle;
|
||||
DAngle slope;
|
||||
|
||||
A_FaceTarget (self);
|
||||
bangle = self->Angles.Yaw;
|
||||
slope = P_AimLineAttack (self, bangle, MISSILERANGE);
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
DAngle angle = bangle + pr_sposattack.Random2() * (22.5 / 256);
|
||||
int damage = ((pr_sposattack()%5)+1)*3;
|
||||
P_LineAttack(self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SPosAttackUseAtkSound)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (!self->target)
|
||||
return 0;
|
||||
|
||||
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
|
||||
A_SPosAttack2 (self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This version of the function, which uses a hard-coded sound, is
|
||||
// meant for Dehacked only.
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SPosAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (!self->target)
|
||||
return 0;
|
||||
|
||||
S_Sound (self, CHAN_WEAPON, "shotguy/attack", 1, ATTN_NORM);
|
||||
A_SPosAttack2 (self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_CPosAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
DAngle angle;
|
||||
DAngle bangle;
|
||||
int damage;
|
||||
DAngle slope;
|
||||
|
||||
if (!self->target)
|
||||
return 0;
|
||||
|
||||
// [RH] Andy Baker's stealth monsters
|
||||
if (self->flags & MF_STEALTH)
|
||||
{
|
||||
self->visdir = 1;
|
||||
}
|
||||
|
||||
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
|
||||
A_FaceTarget (self);
|
||||
bangle = self->Angles.Yaw;
|
||||
slope = P_AimLineAttack (self, bangle, MISSILERANGE);
|
||||
|
||||
angle = bangle + pr_cposattack.Random2() * (22.5 / 256);
|
||||
damage = ((pr_cposattack()%5)+1)*3;
|
||||
P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_CPosRefire)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
// keep firing unless target got out of sight
|
||||
A_FaceTarget (self);
|
||||
|
||||
if (pr_cposrefire() < 40)
|
||||
return 0;
|
||||
|
||||
if (!self->target
|
||||
|| P_HitFriend (self)
|
||||
|| self->target->health <= 0
|
||||
|| !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES))
|
||||
{
|
||||
self->SetState (self->SeeState);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -77,7 +77,7 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info,
|
|||
{
|
||||
ActionCycles.Clock();
|
||||
|
||||
static VMFrameStack stack;
|
||||
VMFrameStack stack;
|
||||
VMValue params[3] = { self, stateowner, VMValue(info, ATAG_STATEINFO) };
|
||||
// If the function returns a state, store it at *stateret.
|
||||
// If it doesn't return a state but stateret is non-NULL, we need
|
||||
|
|
|
@ -461,6 +461,12 @@ bool P_HitFriend(AActor * self)
|
|||
return false;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, HitFriend)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
ACTION_RETURN_BOOL(P_HitFriend(self));
|
||||
}
|
||||
|
||||
//
|
||||
// P_Move
|
||||
// Move in the current direction,
|
||||
|
|
|
@ -4043,6 +4043,18 @@ DAngle P_AimLineAttack(AActor *t1, DAngle angle, double distance, FTranslatedLin
|
|||
return result->linetarget ? result->pitch : t1->Angles.Pitch;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, AimLineAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_ANGLE(angle);
|
||||
PARAM_FLOAT(distance);
|
||||
PARAM_POINTER_OPT(pLineTarget, FTranslatedLineTarget) { pLineTarget = nullptr; }
|
||||
PARAM_ANGLE_OPT(vrange) { vrange = 0.; }
|
||||
PARAM_INT_OPT(flags) { flags = 0; }
|
||||
PARAM_OBJECT_OPT(target, AActor) { target = nullptr; }
|
||||
PARAM_OBJECT_OPT(friender, AActor) { friender = nullptr; }
|
||||
ACTION_RETURN_FLOAT(P_AimLineAttack(self, angle, distance, pLineTarget, vrange, flags, target, friender).Degrees);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -4410,6 +4422,25 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, LineAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_ANGLE(angle);
|
||||
PARAM_FLOAT(distance);
|
||||
PARAM_ANGLE(pitch);
|
||||
PARAM_INT(damage);
|
||||
PARAM_NAME(damageType);
|
||||
PARAM_CLASS(puffType, AActor);
|
||||
PARAM_INT_OPT(flags) { flags = 0; }
|
||||
PARAM_POINTER_OPT(victim, FTranslatedLineTarget) { victim = nullptr; }
|
||||
|
||||
int acdmg;
|
||||
auto puff = P_LineAttack(self, angle, distance, pitch, damage, damageType, puffType, flags, victim, &acdmg);
|
||||
if (numret > 0) ret[0].SetPointer(puff, ATAG_OBJECT);
|
||||
if (numret > 1) ret[1].SetInt(acdmg), numret = 2;
|
||||
return numret;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// P_LinePickActor
|
||||
|
|
|
@ -510,6 +510,14 @@ bool AActor::SetState (FState *newstate, bool nofunction)
|
|||
return true;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, SetState)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_STATE(state);
|
||||
PARAM_BOOL_OPT(nofunction) { nofunction = false; }
|
||||
ACTION_RETURN_BOOL(self->SetState(state, nofunction));
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// AActor :: AddInventory
|
||||
|
|
|
@ -905,6 +905,14 @@ done:
|
|||
return res;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, CheckSight)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_OBJECT(target, AActor);
|
||||
PARAM_INT_OPT(flags) { flags = 0; }
|
||||
ACTION_RETURN_BOOL(P_CheckSight(self, target, flags));
|
||||
}
|
||||
|
||||
ADD_STAT (sight)
|
||||
{
|
||||
FString out;
|
||||
|
|
|
@ -1519,9 +1519,8 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
|
|||
assert(ValueType == TypeBool);
|
||||
ExpEmit from = Operand->Emit(build);
|
||||
assert(!from.Konst);
|
||||
// ~x & 1
|
||||
build->Emit(OP_NOT, from.RegNum, from.RegNum, 0);
|
||||
build->Emit(OP_AND_RK, from.RegNum, from.RegNum, build->GetConstantInt(1));
|
||||
// boolean not is the same as XOR-ing the lowest bit
|
||||
build->Emit(OP_XOR_RK, from.RegNum, from.RegNum, build->GetConstantInt(1));
|
||||
return from;
|
||||
}
|
||||
|
||||
|
@ -1734,32 +1733,54 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build)
|
|||
int zero = build->GetConstantInt(0);
|
||||
int regtype = ValueType->GetRegType();
|
||||
ExpEmit pointer = Base->Emit(build);
|
||||
ExpEmit out = pointer;
|
||||
|
||||
if (!pointer.Target)
|
||||
{
|
||||
out = ExpEmit(build, regtype);
|
||||
ExpEmit out(build, regtype);
|
||||
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero);
|
||||
ExpEmit assign(build, regtype);
|
||||
if (regtype == REGT_INT)
|
||||
{
|
||||
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.));
|
||||
}
|
||||
build->Emit(ValueType->GetStoreOp(), pointer.RegNum, out.RegNum, zero);
|
||||
pointer.Free(build);
|
||||
assign.Free(build);
|
||||
return out;
|
||||
}
|
||||
|
||||
ExpEmit assign(build, regtype);
|
||||
if (regtype == REGT_INT)
|
||||
else if (NeedResult)
|
||||
{
|
||||
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1));
|
||||
ExpEmit out(build, regtype);
|
||||
if (regtype == REGT_INT)
|
||||
{
|
||||
build->Emit(OP_MOVE, out.RegNum, pointer.RegNum);
|
||||
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, pointer.RegNum, pointer.RegNum, build->GetConstantInt(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(OP_MOVEF, out.RegNum, pointer.RegNum);
|
||||
build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, pointer.RegNum, pointer.RegNum, build->GetConstantFloat(1.));
|
||||
}
|
||||
pointer.Free(build);
|
||||
return out;
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.));
|
||||
if (regtype == REGT_INT)
|
||||
{
|
||||
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, pointer.RegNum, pointer.RegNum, build->GetConstantInt(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, pointer.RegNum, pointer.RegNum, build->GetConstantFloat(1.));
|
||||
}
|
||||
pointer.Free(build);
|
||||
return ExpEmit();
|
||||
}
|
||||
|
||||
if (!pointer.Target)
|
||||
{
|
||||
build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero);
|
||||
}
|
||||
|
||||
pointer.Free(build);
|
||||
assign.Free(build);
|
||||
return out;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -5795,7 +5816,8 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
|
|||
auto x = Condition;
|
||||
Condition = nullptr;
|
||||
delete this;
|
||||
return Condition;
|
||||
x->NeedResult = false;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5805,6 +5827,7 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
|
|||
if (line->ExprType != EFX_JumpStatement || static_cast<FxJumpStatement *>(line)->Token != TK_Break)
|
||||
{
|
||||
SAFE_RESOLVE(line, ctx);
|
||||
line->NeedResult = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5999,6 +6022,8 @@ FxIfStatement::FxIfStatement(FxExpression *cond, FxExpression *true_part,
|
|||
Condition = cond;
|
||||
WhenTrue = true_part;
|
||||
WhenFalse = false_part;
|
||||
if (WhenTrue != nullptr) WhenTrue->NeedResult = false;
|
||||
if (WhenFalse != nullptr) WhenFalse->NeedResult = false;
|
||||
assert(cond != NULL);
|
||||
}
|
||||
|
||||
|
@ -6338,6 +6363,8 @@ FxForLoop::FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *
|
|||
: FxLoopStatement(EFX_ForLoop, pos), Init(init), Condition(condition), Iteration(iteration), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
if (Iteration != nullptr) Iteration->NeedResult = false;
|
||||
if (Code != nullptr) Code->NeedResult = false;
|
||||
}
|
||||
|
||||
FxForLoop::~FxForLoop()
|
||||
|
@ -7139,19 +7166,19 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
default:
|
||||
case REGT_INT:
|
||||
build->Emit(OP_LK, build->GetConstantInt(constval->GetValue().GetInt()), RegNum);
|
||||
build->Emit(OP_LK, RegNum, build->GetConstantInt(constval->GetValue().GetInt()));
|
||||
break;
|
||||
|
||||
case REGT_FLOAT:
|
||||
build->Emit(OP_LKF, build->GetConstantFloat(constval->GetValue().GetFloat()), RegNum);
|
||||
build->Emit(OP_LKF, RegNum, build->GetConstantFloat(constval->GetValue().GetFloat()));
|
||||
break;
|
||||
|
||||
case REGT_POINTER:
|
||||
build->Emit(OP_LKP, build->GetConstantAddress(constval->GetValue().GetPointer(), ATAG_GENERIC), RegNum);
|
||||
build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ATAG_GENERIC));
|
||||
break;
|
||||
|
||||
case REGT_STRING:
|
||||
build->Emit(OP_LKS, build->GetConstantString(constval->GetValue().GetString()), RegNum);
|
||||
build->Emit(OP_LKS, RegNum, build->GetConstantString(constval->GetValue().GetString()));
|
||||
}
|
||||
emitval.Free(build);
|
||||
}
|
||||
|
|
|
@ -300,6 +300,7 @@ public:
|
|||
PType *ValueType = nullptr;
|
||||
|
||||
bool isresolved = false;
|
||||
bool NeedResult = true; // should be set to false if not needed and properly handled by all nodes for their subnodes to eliminate redundant code
|
||||
EFxType ExprType;
|
||||
};
|
||||
|
||||
|
@ -1246,7 +1247,7 @@ public:
|
|||
FxSequence(const FScriptPosition &pos) : FxExpression(EFX_Sequence, pos) {}
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); }
|
||||
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); expr->NeedResult = false; }
|
||||
VMFunction *GetDirectFunction();
|
||||
};
|
||||
|
||||
|
|
|
@ -680,6 +680,7 @@ void InitThingdef()
|
|||
symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold)));
|
||||
symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold)));
|
||||
symt.AddSymbol(new PField(NAME_Damage, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DamageVal)));
|
||||
symt.AddSymbol(new PField("visdir", TypeSInt32, VARF_Native, myoffsetof(AActor, visdir)));
|
||||
symt.AddSymbol(new PField(NAME_VisibleStartAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleStartAngle)));
|
||||
symt.AddSymbol(new PField(NAME_VisibleStartPitch, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleStartPitch)));
|
||||
symt.AddSymbol(new PField(NAME_VisibleEndAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndAngle)));
|
||||
|
@ -688,6 +689,7 @@ void InitThingdef()
|
|||
symt.AddSymbol(new PField("Pos", TypeVector3, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos)));
|
||||
symt.AddSymbol(new PField("Vel", TypeVector3, VARF_Native, myoffsetof(AActor, Vel)));
|
||||
symt.AddSymbol(new PField("Scale", TypeVector2, VARF_Native, myoffsetof(AActor, Scale)));
|
||||
symt.AddSymbol(new PField("SeeState", TypeState, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, SeeState)));
|
||||
symt.AddSymbol(new PField(NAME_Target, TypeActor, VARF_Native, myoffsetof(AActor, target)));
|
||||
symt.AddSymbol(new PField(NAME_Master, TypeActor, VARF_Native, myoffsetof(AActor, master)));
|
||||
symt.AddSymbol(new PField(NAME_Tracer, TypeActor, VARF_Native, myoffsetof(AActor, tracer)));
|
||||
|
|
|
@ -915,7 +915,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
|||
#define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); double x = param[p].f;
|
||||
#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); DAngle x = param[p].f;
|
||||
#define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s();
|
||||
#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a;
|
||||
#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].atag == ATAG_GENERIC || param[p].a == NULL)); FState *x = (FState *)param[p].a;
|
||||
#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a;
|
||||
#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
|
||||
#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
|
||||
|
@ -932,8 +932,8 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
|||
#define PARAM_FLOAT_OPT_AT(p,x) double x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else
|
||||
#define PARAM_ANGLE_OPT_AT(p,x) DAngle x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else
|
||||
#define PARAM_STRING_OPT_AT(p,x) FString x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_STRING); x = param[p].s(); } else
|
||||
#define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else
|
||||
#define PARAM_STATEINFO_OPT_AT(p,x) FStateParamInfo *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATEINFO || param[p].a == NULL)); x = (FStateParamInfo *)param[p].a; } else
|
||||
#define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].atag == ATAG_GENERIC || param[p].a == NULL)); x = (FState *)param[p].a; } else
|
||||
#define PARAM_STATEINFO_OPT_AT(p,x) FStateParamInfo *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATEINFO || param[p].atag == ATAG_GENERIC || param[p].a == NULL)); x = (FStateParamInfo *)param[p].a; } else
|
||||
#define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else
|
||||
#define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else
|
||||
#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); } else
|
||||
|
|
|
@ -665,6 +665,7 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c
|
|||
it.Code = code;
|
||||
it.PrintableName = name;
|
||||
it.Function = new VMScriptFunction;
|
||||
it.Function->Name = functype->SymbolName;
|
||||
it.Function->ImplicitArgs = functype->GetImplicitArgs();
|
||||
it.Proto = nullptr;
|
||||
it.FromDecorate = fromdecorate;
|
||||
|
|
|
@ -51,6 +51,12 @@ class Actor : Thinker native
|
|||
native void TraceBleed(int damage, Actor missile);
|
||||
native bool CheckMeleeRange();
|
||||
native int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0);
|
||||
native double AimLineAttack(double angle, double distance, out FTranslatedLineTarget pLineTarget = null, double vrange = 0., int flags = 0, Actor target = null, Actor friender = null);
|
||||
native Actor, int LineAttack(double angle, double distance, double pitch, int damage, Name damageType, class<Actor> pufftype, int flags = 0, out FTranslatedLineTarget victim = null);
|
||||
native bool CheckSight(Actor target, int flags = 0);
|
||||
native bool HitFriend();
|
||||
native bool SetState(state st, bool nofunction = false);
|
||||
|
||||
|
||||
// DECORATE compatible functions
|
||||
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
|
||||
|
@ -88,10 +94,7 @@ class Actor : Thinker native
|
|||
native void A_FaceTarget(float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0);
|
||||
native void A_FaceTracer(float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0);
|
||||
native void A_FaceMaster(float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0);
|
||||
native void A_PosAttack();
|
||||
native void A_Scream();
|
||||
native void A_SPosAttack();
|
||||
native void A_SPosAttackUseAtkSound();
|
||||
native void A_VileChase();
|
||||
native void A_VileStart();
|
||||
native void A_VileTarget(class<Actor> fire = "ArchvileFire");
|
||||
|
@ -108,8 +111,6 @@ class Actor : Thinker native
|
|||
native void A_FatAttack2(class<Actor> spawntype = "FatShot");
|
||||
native void A_FatAttack3(class<Actor> spawntype = "FatShot");
|
||||
native void A_BossDeath();
|
||||
native void A_CPosAttack();
|
||||
native void A_CPosRefire();
|
||||
native void A_SkullAttack(float speed = 20);
|
||||
native void A_BetaSkullAttack();
|
||||
native void A_Metal();
|
||||
|
|
|
@ -824,4 +824,41 @@ struct FStateParamInfo
|
|||
int mPSPIndex;
|
||||
}
|
||||
|
||||
// returned by AimLineAttack.
|
||||
struct FTranslatedLineTarget
|
||||
{
|
||||
Actor linetarget;
|
||||
double angleFromSource;
|
||||
bool unlinked; // found by a trace that went through an unlinked portal.
|
||||
}
|
||||
|
||||
enum EAimFlags
|
||||
{
|
||||
ALF_FORCENOSMART = 1,
|
||||
ALF_CHECK3D = 2,
|
||||
ALF_CHECKNONSHOOTABLE = 4,
|
||||
ALF_CHECKCONVERSATION = 8,
|
||||
ALF_NOFRIENDS = 16,
|
||||
ALF_PORTALRESTRICT = 32, // only work through portals with a global offset (to be used for stuff that cannot remember the calculated FTranslatedLineTarget info)
|
||||
}
|
||||
|
||||
enum ELineAttackFlags
|
||||
{
|
||||
LAF_ISMELEEATTACK = 1,
|
||||
LAF_NORANDOMPUFFZ = 2,
|
||||
LAF_NOIMPACTDECAL = 4,
|
||||
LAF_NOINTERACT = 8,
|
||||
}
|
||||
|
||||
const MELEERANGE = 64;
|
||||
const SAWRANGE = (64.+(1./65536.)); // use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states)
|
||||
const MISSILERANGE = (32*64);
|
||||
const PLAYERMISSILERANGE = 8192; // [RH] New MISSILERANGE for players
|
||||
|
||||
enum ESightFlags
|
||||
{
|
||||
SF_IGNOREVISIBILITY=1,
|
||||
SF_SEEPASTSHOOTABLELINES=2,
|
||||
SF_SEEPASTBLOCKEVERYTHING=4,
|
||||
SF_IGNOREWATERBOUNDARY=8
|
||||
}
|
||||
|
|
|
@ -251,3 +251,93 @@ class WolfensteinSS : Actor
|
|||
Goto See ;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Code (must be attached to Actor)
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
extend class Actor
|
||||
{
|
||||
void A_PosAttack()
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
A_FaceTarget();
|
||||
double ang = angle;
|
||||
double slope = AimLineAttack(ang, MISSILERANGE);
|
||||
A_PlaySound("grunt/attack", CHAN_WEAPON);
|
||||
ang += Random2[PosAttack]() * (22.5/256);
|
||||
int damage = Random[PosAttack](1, 5) * 3;
|
||||
LineAttack(ang, MISSILERANGE, slope, damage, "Hitscan", "Bulletpuff");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void A_SPosAttackInternal()
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
A_FaceTarget();
|
||||
double bangle = angle;
|
||||
double slope = AimLineAttack(bangle, MISSILERANGE);
|
||||
|
||||
for (int i=0 ; i<3 ; i++)
|
||||
{
|
||||
double ang = bangle + Random2[SPosAttack]() * (22.5/256);
|
||||
int damage = Random[SPosAttack](1, 5) * 3;
|
||||
LineAttack(ang, MISSILERANGE, slope, damage, "Hitscan", "Bulletpuff");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void A_SPosAttackUseAtkSound()
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
A_PlaySound(AttackSound, CHAN_WEAPON);
|
||||
A_SPosAttackInternal();
|
||||
}
|
||||
}
|
||||
|
||||
// This version of the function, which uses a hard-coded sound, is meant for Dehacked only.
|
||||
void A_SPosAttack()
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
A_PlaySound("shotguy/attack", CHAN_WEAPON);
|
||||
A_SPosAttackInternal();
|
||||
}
|
||||
}
|
||||
|
||||
void A_CPosAttack()
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
if (bStealth) visdir = 1;
|
||||
A_PlaySound(AttackSound, CHAN_WEAPON);
|
||||
A_FaceTarget();
|
||||
double slope = AimLineAttack(angle, MISSILERANGE);
|
||||
double ang = angle + Random2[SPosAttack]() * (22.5/256);
|
||||
int damage = Random[CPosAttack](1, 5) * 3;
|
||||
LineAttack(ang, MISSILERANGE, slope, damage, "Hitscan", "Bulletpuff");
|
||||
}
|
||||
}
|
||||
|
||||
void A_CPosRefire()
|
||||
{
|
||||
// keep firing unless target got out of sight
|
||||
A_FaceTarget();
|
||||
if (Random[CPosRefire](0, 255) >= 40)
|
||||
{
|
||||
if (!target
|
||||
|| HitFriend()
|
||||
|| target.health <= 0
|
||||
|| !CheckSight(target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES))
|
||||
{
|
||||
SetState(SeeState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue