From dfed6ac1fb93ac182cb62deb347fa65ae00fe034 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Thu, 28 Jul 2016 15:52:20 -0500 Subject: [PATCH] Added SpriteAngle and SpriteRotation properties. - Includes four functions, A_SetSprite(Angle/Rotation) and GetSprite(Angle/Rotation). - SpriteRotation offsets the angle of the sprite, allowing for actors to move backwards or sideways for example. - SpriteAngle requires +SPRITEANGLE and sets the actor's sprite to the absolute rotation found at that angle. Overrides SpriteRotation once the flag is on. --- src/actor.h | 3 + src/p_mobj.cpp | 5 ++ src/r_things.cpp | 20 ++++-- src/thingdef/thingdef_codeptr.cpp | 104 +++++++++++++++++++++++++++ src/thingdef/thingdef_data.cpp | 1 + src/thingdef/thingdef_properties.cpp | 18 +++++ src/version.h | 2 +- wadsrc/static/actors/actor.txt | 6 ++ 8 files changed, 154 insertions(+), 5 deletions(-) diff --git a/src/actor.h b/src/actor.h index a9ce18a57..154d14289 100644 --- a/src/actor.h +++ b/src/actor.h @@ -382,6 +382,7 @@ enum ActorFlag7 MF7_ALLOWTHRUFLAGS = 0x00400000, // [MC] Allow THRUACTORS and the likes on puffs to prevent mod breakage. MF7_USEKILLSCRIPTS = 0x00800000, // [JM] Use "KILL" Script on death if not forced by GameInfo. MF7_NOKILLSCRIPTS = 0x01000000, // [JM] No "KILL" Script on death whatsoever, even if forced by GameInfo. + MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified. }; // --- mobj.renderflags --- @@ -978,6 +979,8 @@ public: DVector3 __Pos; // double underscores so that it won't get used by accident. Access to this should be exclusively through the designated access functions. DVector3 OldRenderPos; + DAngle SpriteAngle; + DAngle SpriteRotation; DRotator Angles; DVector3 Vel; double Speed; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index be875b951..94df4c3bf 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -383,6 +383,11 @@ void AActor::Serialize(FArchive &arc) << RipLevelMin << RipLevelMax; arc << DefThreshold; + if (SaveVersion >= 4549) + { + arc << SpriteAngle; + arc << SpriteRotation; + } { FString tagstr; diff --git a/src/r_things.cpp b/src/r_things.cpp index 3d2133398..78d72fbc8 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -809,11 +809,17 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor angle_t rot; if (sprframe->Texture[0] == sprframe->Texture[1]) { - rot = (ang - thing->Angles.Yaw + 45.0/2*9).BAMs() >> 28; + if (thing->flags7 & MF7_SPRITEANGLE) + rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28; + else + rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28; } else { - rot = (ang - thing->Angles.Yaw + (45.0/2*9-180.0/16)).BAMs() >> 28; + if (thing->flags7 & MF7_SPRITEANGLE) + rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + else + rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; } picnum = sprframe->Texture[rot]; if (sprframe->Flip & (1 << rot)) @@ -848,11 +854,17 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor angle_t rot; if (sprframe->Texture[0] == sprframe->Texture[1]) { - rot = (ang - thing->Angles.Yaw + 45.0 / 2 * 9).BAMs() >> 28; + if (thing->flags7 & MF7_SPRITEANGLE) + rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28; + else + rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28; } else { - rot = (ang - thing->Angles.Yaw + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + if (thing->flags7 & MF7_SPRITEANGLE) + rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + else + rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; } picnum = sprframe->Texture[rot]; if (sprframe->Flip & (1 << rot)) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index bf2a5983b..17c5b5cf5 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -395,6 +395,64 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetGibHealth) return 0; } +//========================================================================== +// +// GetSpriteAngle +// +// NON-ACTION function returns the sprite angle of a pointer. +//========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteAngle) +{ + if (numret > 0) + { + assert(ret != NULL); + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *target = COPY_AAPTR(self, ptr); + if (target == nullptr) + { + ret->SetFloat(0.0); + } + else + { + const double ang = target->SpriteAngle.Degrees; + ret->SetFloat(ang); + } + return 1; + } + return 0; +} + +//========================================================================== +// +// GetSpriteRotation +// +// NON-ACTION function returns the sprite rotation of a pointer. +//========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteRotation) +{ + if (numret > 0) + { + assert(ret != NULL); + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *target = COPY_AAPTR(self, ptr); + if (target == nullptr) + { + ret->SetFloat(0.0); + } + else + { + const double ang = target->SpriteRotation.Degrees; + ret->SetFloat(ang); + } + return 1; + } + return 0; +} + //========================================================================== // // GetZAt @@ -7219,3 +7277,49 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopySpriteFrame) if (!(flags & CPSF_NOFRAME)) copyto->frame = copyfrom->frame; ACTION_RETURN_BOOL(true); } + +//========================================================================== +// +// A_SetSpriteAngle(angle, ptr) +// +// Specifies which angle the actor must always draw its sprite from. +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpriteAngle) +{ + PARAM_ACTION_PROLOGUE; + PARAM_FLOAT_OPT(angle) { angle = 0.; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *mobj = COPY_AAPTR(self, ptr); + + if (mobj == nullptr) + { + ACTION_RETURN_BOOL(false); + } + mobj->SpriteAngle = angle; + ACTION_RETURN_BOOL(true); +} + +//========================================================================== +// +// A_SetSpriteRotation(angle, ptr) +// +// Specifies how much to fake a sprite rotation. +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpriteRotation) +{ + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(angle) { angle = 0.; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *mobj = COPY_AAPTR(self, ptr); + + if (mobj == nullptr) + { + ACTION_RETURN_BOOL(false); + } + mobj->SpriteRotation = angle; + ACTION_RETURN_BOOL(true); +} diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 0768f80c8..3b114fbee 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -259,6 +259,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, ALLOWTHRUFLAGS, AActor, flags7), DEFINE_FLAG(MF7, USEKILLSCRIPTS, AActor, flags7), DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7), + DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index db6ef14a0..372f444cd 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1345,6 +1345,24 @@ DEFINE_PROPERTY(gravity, F, Actor) defaults->Gravity = i; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(spriteangle, F, Actor) +{ + PROP_DOUBLE_PARM(i, 0); + defaults->SpriteAngle = i; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(spriterotation, F, Actor) +{ + PROP_DOUBLE_PARM(i, 0); + defaults->SpriteRotation = i; +} + //========================================================================== // //========================================================================== diff --git a/src/version.h b/src/version.h index 9aa4ad799..cffa25bdd 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4548 +#define SAVEVER 4549 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 77250b3df..1d27ad01a 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -35,6 +35,8 @@ ACTOR Actor native //: Thinker BloodType "Blood", "BloodSplatter", "AxeBlood" ExplosionDamage 128 MissileHeight 32 + SpriteAngle 0 + SpriteRotation 0 // Functions native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); @@ -48,6 +50,8 @@ ACTOR Actor native //: Thinker native float GetCrouchFactor(int ptr = AAPTR_PLAYER1); native float GetCVar(string cvar); native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT); + native float GetSpriteAngle(int ptr = AAPTR_DEFAULT); + native float GetSpriteRotation(int ptr = AAPTR_DEFAULT); // Action functions // Meh, MBF redundant functions. Only for DeHackEd support. @@ -331,6 +335,8 @@ ACTOR Actor native //: Thinker action native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT); action native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true); action native bool A_CopySpriteFrame(int from, int to, int flags = 0); + action native bool A_SetSpriteAngle(float angle = 0, int ptr = AAPTR_DEFAULT); + action native bool A_SetSpriteRotation(float angle = 0, int ptr = AAPTR_DEFAULT); native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0);