Skip to content

Commit

Permalink
Emplacements use visual thinker fake operators.
Browse files Browse the repository at this point in the history
Emplacements now use a VisualThinker for the fake operator visual effect, as I originally intended. Thanks to DileepVR helping me get the damn sprite rotation code working finally. Also helps bypass this engine bug (ZDoom/gzdoom#2716) on the placeholder actor version of the effect.
  • Loading branch information
inkoalawetrust committed Sep 19, 2024
1 parent 973f855 commit 96de20e
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 106 deletions.
70 changes: 70 additions & 0 deletions ZScript/Bases/Base.zsc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,77 @@ Class KAI_MixinActor : Actor Abstract
Mixin KAI_UniversalFunctions;
Mixin KAI_CheckFunctions;
}
Class emit : Actor
{
TextureID tex;
Default
{
+NOINTERACTION
+NOBLOCKMAP
+BRIGHT
Scale 0.25;
}

override void PostBeginPlay()
{
Super.PostBeginPlay();
tex = TexMan.CheckForTexture("TRCHA1");
}

States
{
Spawn:
MISL A 1;
Looping:
MISL A 1
{
angle = random(0,359);
pitch = random(-90,90);
Vel3DFromAngle(random(2,6), angle, pitch);
let p = Level.SpawnVisualThinker("ZRocketBoom");
if (p)
{
p.Texture = tex;
p.pos = pos;
p.vel = vel;
p.scolor = "FF0000";
p.SetRenderStyle(STYLE_Add);
p.flags = SPF_ROLL|SPF_FULLBRIGHT;
p.roll = random(0,359);
p.alpha = 1.0;
p.Scale = (1,1);
}
vel = (0,0,0);

}
Loop;
}
}

Class ZRocketBoom : VisualThinker
{
double RollVel;

override void PostBeginPlay()
{
Super.PostBeginPlay();
RollVel = frandom(-10.0, 10.0);
Alpha = 1.0;
}

override void Tick()
{
if (bDESTROYED || IsFrozen())
return;

Super.Tick();
Roll += RollVel;
Alpha -= 0.05;
if (Alpha <= 0.0)
Destroy();

}
}
Class KAI_Actor : Actor Abstract
{
Default
Expand Down
149 changes: 43 additions & 106 deletions ZScript/Bases/Humanoid/Emplacement.zsc
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
//TODO: Uh, I am JUST getting started with this new major feature, very unsure how ANYTHING should look like.
//- I guess KAI_Emplacement probably doesn't need to be based on KAI_Actor, it's basically an interactive prop.
//- Figure out the minor (Huge) design issue of how to map an NPC using an emplacement to the proper morph. And also the same problem but with player skins. Fun!!!!!
//- Will probably need an associative map, at least for mapping NPC operators to the correct morphs. i.e KAI_HellKnight = HellKnightMorph, KAI_Imp = ImpMorph etc
//- Maybe add a basic player morph class? Or rather the handling for a purely visual pseudo-player that can move relative to the emplacement, for basic morph classes.

//The base emplacement class for the library. Emplacements can be used by both players and KAI_Humanoid NPCs by default.
Class KAI_Emplacement : Actor Abstract
{
Expand Down Expand Up @@ -157,7 +151,22 @@ Class KAI_Emplacement : Actor Abstract
}

//Create a fake operator visual effect to serve as a placeholder for NPC and player operators if you have no unique emplacement sprites.
Actor CreateFakeOperator (Vector3 Position)
VisualThinker CreateFakeOperator (Vector3 Offsets = (0,0,0))
{
Let Illusion = KAI_EmplacementFakeOperator(Level.SpawnVisualThinker("KAI_EmplacementFakeOperator"));
If (Illusion)
{
Illusion.Pos = Level.Vec3Offset (Pos,Offsets);
Illusion.Offsets = Level.Vec3Diff (Pos, Illusion.Pos);
Illusion.Operator = Operator;
Illusion.Emplacement = Self;
Illusion.Texture = CurState.GetSpriteTexture (0); //Just get some placeholder graphic for now so the thinker won't immediately self-destruct.
Return Illusion;
}
Return Null;
}
//Create a fake operator visual effect to serve as a placeholder for NPC and player operators if you have no unique emplacement sprites.
/*Actor CreateFakeOperator (Vector3 Position)
{
Let FakeOp = KAI_EmplacementFakeOperator(Spawn ("KAI_EmplacementFakeOperator",Level.Vec3Offset(Pos,Position)));

Expand All @@ -170,7 +179,7 @@ Class KAI_Emplacement : Actor Abstract
}

Return FakeOp;
}
}*/
}

Class KAI_EmplacementNPC : KAI_Actor Abstract
Expand Down Expand Up @@ -263,127 +272,48 @@ Class KAI_EmplacementPlayer : PlayerPawn
}
}

//HACK: I can't get the sprite rotation math right on the intended VisualThinker version. And nobody can help me with it. So this serves as a placeholder class.
Class KAI_EmplacementFakeOperator : Actor
Class KAI_EmplacementFakeOperator : VisualThinker
{
Vector3 Offsets;
Actor Operator;
KAI_Emplacement Emplacement;
Mixin KAI_CheckFunctions;
State SpriteState; //The state which we get the sprite to use.
//Int PlayerSkinID; //The number of the players' skin. Only relevant if the operator is both a player, and of course, is using a skin.

Name SpriteName;

Override Void PostBeginPlay()
{
Super.PostBeginPlay();

//Set the first idle frame of the operator as the texture.
If (Operator)
{
//Acquire the first valid see state sprite of the operator to use as the fallback graphic. If the graphic is TNT1A0, look for the next state's sprite.
{
Int SkinNum = Emplacement.OperatorMorph.Player ? Emplacement.OperatorMorph.Player.GetSkin() : 0;
State LeState = GetDefaultByType(Operator.GetClass()).SeeState;
TextureID Graphic;
For (Int I; I < 32; I++)
{
LeState = LeState.NextState;
Graphic = LeState.GetSpriteTexture (0,SkinNum);
}
String SpriteString;
SpriteString = TexMan.GetName(Graphic);
SpriteString.Truncate (4);
SpriteName = SpriteString;
SpriteState = LeState;
}
}
}
Override Void Tick()
{
If (!Operator || !Emplacement || !KAI_Emplacement(Emplacement).Operator)
{
Destroy();
Return;
}

If (IsFrozen())
Return;

SetOrigin(KAI_Math.Vec3OffsetRelative (Emplacement, Offsets),True);
A_Face (Emplacement);

// Advance the state
if (tics != -1)
{
if (tics > 0) tics--;
while (!tics)
{
if (!SetState (CurState.NextState))
{ // mobj was removed
return;
}
}
}
}

States
{
Spawn:
#### A 1
{
If (SpriteState)
{
Sprite = GetSpriteIndex(SpriteName);
Frame = SpriteState.Frame;
}
}
Loop;
}
}

/*Class KAI_EmplacementFakeOperator : VisualThinker
{
Vector3 Offsets;
Actor Operator;
Actor Emplacement;
Mixin KAI_CheckFunctions;
State SpriteState; //The state which we get the sprite to use.
Int PlayerSkinID; //The number of the players' skin. Only relevant if the operator is both a player, and of course, is using a skin.

//Cut down version of GetSpriteAngleFromPos().
//Cut down version of GetSpriteAngleFromPos().
//CREDIT: DileepVR for helping me fucking finally get this stupid shit to work.
/*NOTE: OH YEAH, WHEN *YOU* USE THIS IN CONJUNCTION WITH GETSPRITETEXTURE() IN YOUR OWN CODE, ALSO MAKE SURE TO TAKE ITS' SECOND RETURN TO CONTROL IF THE
VISUALTHINKER SHOULD BE FLIPPED.*/
Int FakeOpGetSpriteAngle (Vector3 CamPos, Bool SixteenAngles)
{
Vector3 Coords = Level.SphericalCoords (Pos,CamPos);
Double Ang = -Coords.X;

Double Angle = Emplacement.Angle + 180;
Double Angle = Emplacement.Angle - 180; //This code's for a visualthinker, so no angle of its' own, so it takes the angle of the actor it's attached to.
Double SprAng = Angle - Ang;
Double Result;
If (!SixteenAngles)
{
Result = BAM (SprAng - (Angle/* + SpriteRotation/) + 45.0 / 2 * 9) >> 28;
}
Result = BAM (-SprAng + 45.0 / 2 * 9) >> 28;
Else
{
Result = BAM (SprAng - (Angle/* + SpriteRotation/) + 45.0 / 2 * 9 - 180.0 / 16) >> 28;
}
Result = BAM (-SprAng + 45.0 / 2 * 9 - 180.0 / 16) >> 28;
Return Int(Result);
}


Override Void PostBeginPlay()
{
Super.PostBeginPlay();

Flags = SPF_NO_XY_BILLBOARD;
//Set the first idle frame of the operator as the texture.
//TODO: Need to also make the sprites have working rotations, fuck...
If (Operator)
{
//If (!Texture)
//Acquire the first valid see state sprite of the operator to use as the fallback graphic. If the graphic is TNT1A0, look for the next state's sprite.
{
Int SkinNum = Operator.Player ? Operator.Player.GetSkin() : 0;
Translation = Operator.Translation;
Int SkinNum = Emplacement.OperatorMorph.Player ? Emplacement.OperatorMorph.Player.GetSkin() : 0;
State LeState = GetDefaultByType(Operator.GetClass()).SeeState;
TextureID Graphic = LeState.GetSpriteTexture (0,SkinNum);
For (Int I; I < 32; I++)
Expand All @@ -396,27 +326,34 @@ Class KAI_EmplacementFakeOperator : Actor
SpriteState = LeState;
Texture = Graphic;
PlayerSkinID = SkinNum;
console.printf ("fake operator: took actors' idle sprite (%s)",texman.getname(texture));
}
}
Else
{console.printf ("fake operator: no actual operator");Destroy();}
}
override void ondestroy(){console.printf ("fake operator: we got removed for some other reason");if (!Texture) console.printf ("cuz we got no texture");}
Override Void Tick()
{
Super.Tick();

If (!Operator || !Emplacement || !KAI_Emplacement(Emplacement).Operator)
{console.printf ("fake operator: no operator or emplacement");
{
Destroy();
Return;
}

Texture = SpriteState.GetSpriteTexture (FakeOpGetSpriteAngle(Players[ConsolePlayer].Camera.Pos,True),PlayerSkinID);
If (Players[ConsolePlayer].Camera)
{
If (PlayerSkinID != 0)
[Texture,bXFlip,Scale] = SpriteState.GetSpriteTexture (FakeOpGetSpriteAngle(Players[ConsolePlayer].Camera.Pos,True),PlayerSkinID);
Else //GetSpriteTexture's scale return is only for skins.
{
Vector2 Garbage;
[Texture,bXFlip,Garbage] = SpriteState.GetSpriteTexture (FakeOpGetSpriteAngle(Players[ConsolePlayer].Camera.Pos,True),PlayerSkinID);
}
}
//console.printf ("RENDERING STATS: GRAPHIC %s, MIRRORED %d, SCALE %.2f %.2f",texman.getname(texture),bxflip,scale);
If (IsFrozen())
Return;

Pos = KAI_Math.Vec3OffsetRelative (Emplacement, Offsets);
Pos = KAI_Math.Vec3OffsetRelative (Emplacement, Offsets,flags:KAI_Math.V3R_ANGLEONLY);
}
}*/
}

0 comments on commit 96de20e

Please sign in to comment.