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_keen.cpp
|
||||||
g_doom/a_lostsoul.cpp
|
g_doom/a_lostsoul.cpp
|
||||||
g_doom/a_painelemental.cpp
|
g_doom/a_painelemental.cpp
|
||||||
g_doom/a_possessed.cpp
|
|
||||||
g_doom/a_revenant.cpp
|
g_doom/a_revenant.cpp
|
||||||
g_doom/a_scriptedmarine.cpp
|
g_doom/a_scriptedmarine.cpp
|
||||||
g_doom/a_spidermaster.cpp
|
g_doom/a_spidermaster.cpp
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include "a_keen.cpp"
|
#include "a_keen.cpp"
|
||||||
#include "a_lostsoul.cpp"
|
#include "a_lostsoul.cpp"
|
||||||
#include "a_painelemental.cpp"
|
#include "a_painelemental.cpp"
|
||||||
#include "a_possessed.cpp"
|
|
||||||
#include "a_revenant.cpp"
|
#include "a_revenant.cpp"
|
||||||
#include "a_spidermaster.cpp"
|
#include "a_spidermaster.cpp"
|
||||||
#include "a_scriptedmarine.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();
|
ActionCycles.Clock();
|
||||||
|
|
||||||
static VMFrameStack stack;
|
VMFrameStack stack;
|
||||||
VMValue params[3] = { self, stateowner, VMValue(info, ATAG_STATEINFO) };
|
VMValue params[3] = { self, stateowner, VMValue(info, ATAG_STATEINFO) };
|
||||||
// If the function returns a state, store it at *stateret.
|
// If the function returns a state, store it at *stateret.
|
||||||
// If it doesn't return a state but stateret is non-NULL, we need
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(AActor, HitFriend)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
ACTION_RETURN_BOOL(P_HitFriend(self));
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// P_Move
|
// P_Move
|
||||||
// Move in the current direction,
|
// 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;
|
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
|
// P_LinePickActor
|
||||||
|
|
|
@ -510,6 +510,14 @@ bool AActor::SetState (FState *newstate, bool nofunction)
|
||||||
return true;
|
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
|
// AActor :: AddInventory
|
||||||
|
|
|
@ -905,6 +905,14 @@ done:
|
||||||
return res;
|
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)
|
ADD_STAT (sight)
|
||||||
{
|
{
|
||||||
FString out;
|
FString out;
|
||||||
|
|
|
@ -1519,9 +1519,8 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
|
||||||
assert(ValueType == TypeBool);
|
assert(ValueType == TypeBool);
|
||||||
ExpEmit from = Operand->Emit(build);
|
ExpEmit from = Operand->Emit(build);
|
||||||
assert(!from.Konst);
|
assert(!from.Konst);
|
||||||
// ~x & 1
|
// boolean not is the same as XOR-ing the lowest bit
|
||||||
build->Emit(OP_NOT, from.RegNum, from.RegNum, 0);
|
build->Emit(OP_XOR_RK, from.RegNum, from.RegNum, build->GetConstantInt(1));
|
||||||
build->Emit(OP_AND_RK, from.RegNum, from.RegNum, build->GetConstantInt(1));
|
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1734,32 +1733,54 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build)
|
||||||
int zero = build->GetConstantInt(0);
|
int zero = build->GetConstantInt(0);
|
||||||
int regtype = ValueType->GetRegType();
|
int regtype = ValueType->GetRegType();
|
||||||
ExpEmit pointer = Base->Emit(build);
|
ExpEmit pointer = Base->Emit(build);
|
||||||
ExpEmit out = pointer;
|
|
||||||
|
|
||||||
if (!pointer.Target)
|
if (!pointer.Target)
|
||||||
{
|
{
|
||||||
out = ExpEmit(build, regtype);
|
ExpEmit out(build, regtype);
|
||||||
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero);
|
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;
|
||||||
}
|
}
|
||||||
|
else if (NeedResult)
|
||||||
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));
|
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
|
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;
|
auto x = Condition;
|
||||||
Condition = nullptr;
|
Condition = nullptr;
|
||||||
delete this;
|
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)
|
if (line->ExprType != EFX_JumpStatement || static_cast<FxJumpStatement *>(line)->Token != TK_Break)
|
||||||
{
|
{
|
||||||
SAFE_RESOLVE(line, ctx);
|
SAFE_RESOLVE(line, ctx);
|
||||||
|
line->NeedResult = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5999,6 +6022,8 @@ FxIfStatement::FxIfStatement(FxExpression *cond, FxExpression *true_part,
|
||||||
Condition = cond;
|
Condition = cond;
|
||||||
WhenTrue = true_part;
|
WhenTrue = true_part;
|
||||||
WhenFalse = false_part;
|
WhenFalse = false_part;
|
||||||
|
if (WhenTrue != nullptr) WhenTrue->NeedResult = false;
|
||||||
|
if (WhenFalse != nullptr) WhenFalse->NeedResult = false;
|
||||||
assert(cond != NULL);
|
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)
|
: FxLoopStatement(EFX_ForLoop, pos), Init(init), Condition(condition), Iteration(iteration), Code(code)
|
||||||
{
|
{
|
||||||
ValueType = TypeVoid;
|
ValueType = TypeVoid;
|
||||||
|
if (Iteration != nullptr) Iteration->NeedResult = false;
|
||||||
|
if (Code != nullptr) Code->NeedResult = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FxForLoop::~FxForLoop()
|
FxForLoop::~FxForLoop()
|
||||||
|
@ -7139,19 +7166,19 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case REGT_INT:
|
case REGT_INT:
|
||||||
build->Emit(OP_LK, build->GetConstantInt(constval->GetValue().GetInt()), RegNum);
|
build->Emit(OP_LK, RegNum, build->GetConstantInt(constval->GetValue().GetInt()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REGT_FLOAT:
|
case REGT_FLOAT:
|
||||||
build->Emit(OP_LKF, build->GetConstantFloat(constval->GetValue().GetFloat()), RegNum);
|
build->Emit(OP_LKF, RegNum, build->GetConstantFloat(constval->GetValue().GetFloat()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REGT_POINTER:
|
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;
|
break;
|
||||||
|
|
||||||
case REGT_STRING:
|
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);
|
emitval.Free(build);
|
||||||
}
|
}
|
||||||
|
|
|
@ -300,6 +300,7 @@ public:
|
||||||
PType *ValueType = nullptr;
|
PType *ValueType = nullptr;
|
||||||
|
|
||||||
bool isresolved = false;
|
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;
|
EFxType ExprType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1246,7 +1247,7 @@ public:
|
||||||
FxSequence(const FScriptPosition &pos) : FxExpression(EFX_Sequence, pos) {}
|
FxSequence(const FScriptPosition &pos) : FxExpression(EFX_Sequence, pos) {}
|
||||||
FxExpression *Resolve(FCompileContext&);
|
FxExpression *Resolve(FCompileContext&);
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
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();
|
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_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_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(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_VisibleStartAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleStartAngle)));
|
||||||
symt.AddSymbol(new PField(NAME_VisibleStartPitch, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleStartPitch)));
|
symt.AddSymbol(new PField(NAME_VisibleStartPitch, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleStartPitch)));
|
||||||
symt.AddSymbol(new PField(NAME_VisibleEndAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndAngle)));
|
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("Pos", TypeVector3, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos)));
|
||||||
symt.AddSymbol(new PField("Vel", TypeVector3, VARF_Native, myoffsetof(AActor, Vel)));
|
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("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_Target, TypeActor, VARF_Native, myoffsetof(AActor, target)));
|
||||||
symt.AddSymbol(new PField(NAME_Master, TypeActor, VARF_Native, myoffsetof(AActor, master)));
|
symt.AddSymbol(new PField(NAME_Master, TypeActor, VARF_Native, myoffsetof(AActor, master)));
|
||||||
symt.AddSymbol(new PField(NAME_Tracer, TypeActor, VARF_Native, myoffsetof(AActor, tracer)));
|
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_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_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_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_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_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)));
|
#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_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_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_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_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].a == NULL)); x = (FStateParamInfo *)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_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_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
|
#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.Code = code;
|
||||||
it.PrintableName = name;
|
it.PrintableName = name;
|
||||||
it.Function = new VMScriptFunction;
|
it.Function = new VMScriptFunction;
|
||||||
|
it.Function->Name = functype->SymbolName;
|
||||||
it.Function->ImplicitArgs = functype->GetImplicitArgs();
|
it.Function->ImplicitArgs = functype->GetImplicitArgs();
|
||||||
it.Proto = nullptr;
|
it.Proto = nullptr;
|
||||||
it.FromDecorate = fromdecorate;
|
it.FromDecorate = fromdecorate;
|
||||||
|
|
|
@ -51,6 +51,12 @@ class Actor : Thinker native
|
||||||
native void TraceBleed(int damage, Actor missile);
|
native void TraceBleed(int damage, Actor missile);
|
||||||
native bool CheckMeleeRange();
|
native bool CheckMeleeRange();
|
||||||
native int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0);
|
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
|
// DECORATE compatible functions
|
||||||
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
|
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_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_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_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_Scream();
|
||||||
native void A_SPosAttack();
|
|
||||||
native void A_SPosAttackUseAtkSound();
|
|
||||||
native void A_VileChase();
|
native void A_VileChase();
|
||||||
native void A_VileStart();
|
native void A_VileStart();
|
||||||
native void A_VileTarget(class<Actor> fire = "ArchvileFire");
|
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_FatAttack2(class<Actor> spawntype = "FatShot");
|
||||||
native void A_FatAttack3(class<Actor> spawntype = "FatShot");
|
native void A_FatAttack3(class<Actor> spawntype = "FatShot");
|
||||||
native void A_BossDeath();
|
native void A_BossDeath();
|
||||||
native void A_CPosAttack();
|
|
||||||
native void A_CPosRefire();
|
|
||||||
native void A_SkullAttack(float speed = 20);
|
native void A_SkullAttack(float speed = 20);
|
||||||
native void A_BetaSkullAttack();
|
native void A_BetaSkullAttack();
|
||||||
native void A_Metal();
|
native void A_Metal();
|
||||||
|
|
|
@ -824,4 +824,41 @@ struct FStateParamInfo
|
||||||
int mPSPIndex;
|
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 ;
|
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