diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 60a2318b4..3e5a4dc10 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5930,4 +5930,55 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) { ACTION_JUMP(block); } +} + +//=========================================================================== +// +// A_FaceVelocity(angle offset, bool pitch, ptr) +// +// Sets the actor('s pointer) to face the direction of travel. +//=========================================================================== +enum FVFlags +{ + FVF_NOPITCH = 1 << 0, + FVF_INTERPOLATE = 1 << 1, + FVF_NOANGLE = 1 << 2, + FVF_RESETPITCH = 1 << 3, +}; +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceVelocity) +{ + ACTION_PARAM_START(3); + ACTION_PARAM_FIXED(offset, 0) + ACTION_PARAM_INT(flags, 1); + ACTION_PARAM_INT(ptr, 2); + + AActor *mobj = COPY_AAPTR(self, ptr); + + //Need an actor. + if (!mobj || ((flags & FVF_NOPITCH) && (flags & FVF_NOANGLE))) + { + ACTION_SET_RESULT(false); + return; + } + + //Don't bother calculating this if we don't have any horizontal movement. + if (!(flags & FVF_NOANGLE) && (mobj->velx != 0 || mobj->vely != 0)) + { + fixed_t vx = mobj->x + mobj->velx, vy = mobj->y + mobj->vely; + angle_t angle = R_PointToAngle2(mobj->x, mobj->y, vx, vy) + offset; + mobj->SetAngle(angle, !!(flags & FVF_INTERPOLATE)); + } + + if (!(flags & FVF_NOPITCH)) + { + //Reset pitch to 0 if specified. + if (mobj->velz == 0 && (flags & FVF_RESETPITCH)) + mobj->pitch = 0; + else + { + FVector2 velocity(mobj->velx, mobj->vely); + fixed_t pitch = R_PointToAngle2(0, 0, (fixed_t)velocity.Length(), mobj->velz); + mobj->SetPitch(-pitch, !!(flags & FVF_INTERPOLATE)); + } + } } \ No newline at end of file diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 7dc89f201..22312fed8 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -340,6 +340,7 @@ ACTOR Actor native //: Thinker action native A_CheckBlock(state block, int flags = 0, int ptr = AAPTR_DEFAULT); action native A_CheckSightOrRange(float distance, state label, bool two_dimension = false); action native A_CheckRange(float distance, state label, bool two_dimension = false); + action native A_FaceVelocity(float offset = 0, int flags = 0, int ptr = AAPTR_DEFAULT); action native A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); action native A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 7f8fbc09e..9667db563 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -495,6 +495,15 @@ enum CBF_SETONPTR = 1 << 4, //Sets the pointer change on the actor doing the checking instead of self. }; +//Flags for A_FaceVelocity +enum +{ + FVF_NOPITCH = 1 << 0, + FVF_INTERPOLATE = 1 << 1, + FVF_NOANGLE = 1 << 2, + FVF_RESETPITCH = 1 << 3, +}; + // This is only here to provide one global variable for testing. native int testglobalvar;