diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5a3351880..a5164e84b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index de53dc3af..4c8be07f1 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.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" diff --git a/src/g_doom/a_possessed.cpp b/src/g_doom/a_possessed.cpp deleted file mode 100644 index 0b9a9ecfd..000000000 --- a/src/g_doom/a_possessed.cpp +++ /dev/null @@ -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; -} diff --git a/src/info.cpp b/src/info.cpp index 5e267b39c..268d4f91c 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -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 diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 0c2cb8e28..fbdc1a212 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -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, diff --git a/src/p_map.cpp b/src/p_map.cpp index 849f8dd24..ef46f6566 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -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 diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 5d40d1ed3..7398fa29f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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 diff --git a/src/p_sight.cpp b/src/p_sight.cpp index c10365eea..fefe9eb27 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -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; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index de7048d88..8fec40113 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -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(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); } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 3fb1b1576..d099daa22 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -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(); }; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index a4815cb33..601fb5e9a 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -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))); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 12ce01273..747d53c3b 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -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 diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 1b7c4ce70..c72c2b567 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -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; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 872a3ef98..027aaf7dc 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -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 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 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 fire = "ArchvileFire"); @@ -108,8 +111,6 @@ class Actor : Thinker native native void A_FatAttack2(class spawntype = "FatShot"); native void A_FatAttack3(class 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(); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 41c4bfec9..f49264062 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -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 +} diff --git a/wadsrc/static/zscript/doom/possessed.txt b/wadsrc/static/zscript/doom/possessed.txt index de1e50ff2..8b6612076 100644 --- a/wadsrc/static/zscript/doom/possessed.txt +++ b/wadsrc/static/zscript/doom/possessed.txt @@ -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); + } + } + } +}