Skip to content

Commit c59efb3

Browse files
committed
ForcedHFlip and make cannon aim smoothing better-ish
1 parent 11a3f40 commit c59efb3

File tree

12 files changed

+137
-111
lines changed

12 files changed

+137
-111
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5050

5151
- New `AEmitter` and `PEmitter` INI and Lua (R/W) property `PlayBurstSound` which denotes whether the BurstSound should play when appropriate. This should not be confused for a trigger - it's just a enable/disable toggle to avoid having to remove and add BurstSound altogether.
5252

53+
- New `MOSprite` INI and Lua (R/W) integer property `ForcedHFlip` which forces a certain flippedness and disallows anything else from ever changing it without clearing the forced value first. 0 is forced not flipped, 1 forced flipped, and -1 is no force.
54+
5355
- Allow lua scripts to use LuaJIT's BitOp module (see https://bitop.luajit.org/api.html)
5456

5557
</details>

Data/Browncoats.rte/Actors/Turrets/Thunderer/Thunderer.ini

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -607,8 +607,7 @@ AddActor = ACrab
607607
// GibSound = SoundContainer
608608
// AddSound = ContentFile
609609
// FilePath = Base.rte/Cool explosion sound here
610-
AddCustomValue = NumberValue
611-
KeepUnflipped = 1
610+
ForcedHFlip = 0
612611

613612

614613
AddActor = ACrab
@@ -628,8 +627,7 @@ AddActor = ACrab
628627
SpriteOffset = Vector
629628
X = -5
630629
Y = -35
631-
AddCustomValue = NumberValue
632-
KeepUnflipped = -1
630+
ForcedHFlip = 1
633631

634632
AddActor = ACrab
635633
CopyOf = AA-50 Thunderer A

Data/Browncoats.rte/Actors/Turrets/Thunderer/ThundererBase.lua

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,9 @@ function Create(self)
1212
end
1313

1414
self.AIMode = Actor.AIMODE_SENTRY;
15-
16-
if self:GetNumberValue("KeepUnflipped") == -1 then
17-
self.keepFlipped = true;
18-
else
19-
self.keepFlipped = false;
20-
end
21-
22-
if self.Turret then
23-
if self.Turret.MountedDevice then
24-
self.Turret.MountedDevice:SendMessage("SetKeepUnflipped", self:GetNumberValue("KeepUnflipped"));
25-
end
26-
end
2715
end
2816

2917
function Update(self)
3018
-- keep anything from moving us
3119
self.Pos = self.pinPos;
32-
33-
self.HFlipped = self.keepFlipped;
3420
end

Data/Browncoats.rte/Actors/Turrets/Thunderer/ThundererGun.lua

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
function OnMessage(self, message, context)
2-
if message == "SetKeepUnflipped" then
3-
self.keepFlipped = context == -1 and true or false;
4-
end
5-
end
6-
71
function OnFire(self)
82
CameraMan:AddScreenShake(7, self.Pos);
93

@@ -59,45 +53,61 @@ function Create(self)
5953
self.reloadSmokeTimer = Timer();
6054

6155
self.rotationSpeed = 0.08;
62-
self.smoothedRotAngle = self.RotAngle;
63-
self.InheritedRotAngleTarget = 0;
56+
self.rotAngleDeviation = 0;
6457

65-
self.keepFlipped = false;
58+
if self.HFlipped then
59+
self.RotAngle = math.pi;
60+
end
61+
62+
self.LastHFlipped = self.HFlipped;
63+
self.LastRotAngle = self.RotAngle;
6664
end
6765

6866
function Update(self)
6967
--self.servoLoopSound.Pos = self.Pos;
7068

71-
self.HFlipped = self.keepFlipped;
72-
73-
self.parent = IsActor(self:GetRootParent()) and ToActor(self:GetRootParent()) or nil;
69+
if self.LastHFlipped ~= nil then
70+
if self.LastHFlipped ~= self.HFlipped then
71+
self.LastHFlipped = self.HFlipped
72+
self.rotAngleDeviation = 0;
73+
end
74+
end
7475

76+
self.parent = IsActor(self:GetRootParent()) and ToActor(self:GetRootParent()) or nil;
7577
self.playerControlled = (self.parent and self.parent:IsPlayerControlled()) and true or false;
7678

77-
-- reticule of actual aim line so the gun feels cannon-y rather than unresponsive
78-
79-
local actingRotAngle = self.RotAngle - self.InheritedRotAngleOffset;
80-
81-
if self.playerControlled and self.parent.SharpAimProgress > 0.13 then
82-
for i = 1, 24 do
83-
if i % 3 == 0 then
84-
local dotVec = Vector(i*self.FlipFactor, 0):RadRotate(actingRotAngle) + self.Pos + Vector((self.SharpLength + 15) * self.FlipFactor, 0):RadRotate(actingRotAngle)*self.parent.SharpAimProgress;
85-
PrimitiveMan:DrawLinePrimitive(dotVec, dotVec, 116, 2);
79+
-- Rotation smoothing related stuff
80+
if self.parent then
81+
local actingRotAngle = self.parent:GetAimAngle(true)
82+
local aimAngle = self.parent:GetAimAngle(false) * self.FlipFactor;
83+
84+
-- Reticule
85+
if self.playerControlled and self.parent.SharpAimProgress > 0.13 then
86+
for i = 1, 24 do
87+
if i % 3 == 0 then
88+
local dotVec = Vector(i*self.FlipFactor, 0):RadRotate(aimAngle) + self.Pos + Vector((self.SharpLength + 15) * self.FlipFactor, 0):RadRotate(aimAngle)*self.parent.SharpAimProgress;
89+
PrimitiveMan:DrawLinePrimitive(dotVec, dotVec, 116, 2);
90+
end
8691
end
8792
end
93+
94+
self.rotAngleDeviation = self.rotAngleDeviation + (self.LastRotAngle - actingRotAngle);
95+
96+
if self.rotAngleDeviation ~= 0 then
97+
self.rotAngleDeviation = self.rotAngleDeviation - (self.rotAngleDeviation * self.rotationSpeed);
98+
if math.abs(self.rotAngleDeviation) < 0.001 then
99+
self.rotAngleDeviation = 0;
100+
end
101+
end
102+
103+
self.InheritedRotAngleOffset = self.rotAngleDeviation * self.FlipFactor;
104+
self.LastRotAngle = actingRotAngle;
105+
106+
--self.servoLoopSoundVolumeTarget = 0 + math.abs(self.rotAngleDeviation)
107+
--self.servoLoopSound.Volume = self.servoLoopSound.Volume - (0.5 * (self.servoLoopSound.Volume - self.servoLoopSoundVolumeTarget));
108+
--self.servoLoopSoundPitchTarget = 1 + math.abs(self.rotAngleDeviation)
109+
--self.servoLoopSound.Pitch = self.servoLoopSound.Pitch - (0.1 * (self.servoLoopSound.Pitch - self.servoLoopSoundPitchTarget));
88110
end
89-
-- rotation smoothing, for a cannon-y feel:
90-
91-
if self.smoothedRotAngle ~= actingRotAngle then
92-
self.smoothedRotAngle = self.smoothedRotAngle - (self.rotationSpeed * (self.smoothedRotAngle - (actingRotAngle)));
93-
end
94-
95-
--self.servoLoopSoundVolumeTarget = 0 + math.abs(self.smoothedRotAngle - actingRotAngle)
96-
--self.servoLoopSound.Volume = self.servoLoopSound.Volume - (0.5 * (self.servoLoopSound.Volume - self.servoLoopSoundVolumeTarget));
97-
--self.servoLoopSoundPitchTarget = 1 + math.abs(self.smoothedRotAngle - actingRotAngle)
98-
--self.servoLoopSound.Pitch = self.servoLoopSound.Pitch - (0.1 * (self.servoLoopSound.Pitch - self.servoLoopSoundPitchTarget));
99-
100-
self.InheritedRotAngleOffset = self.smoothedRotAngle - actingRotAngle;
101111

102112
if self:DoneReloading() then
103113
self.currentBaseFrame = 0;

Data/Coalition.rte/Actors/Turrets/BunkerCannon/BunkerCannon.ini

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -773,8 +773,7 @@ AddActor = ACrab
773773
// GibSound = SoundContainer
774774
// AddSound = ContentFile
775775
// FilePath = Base.rte/Cool explosion sound here
776-
AddCustomValue = NumberValue
777-
KeepUnflipped = 1
776+
ForcedHFlip = 0
778777

779778

780779
AddTerrainObject = TerrainObject
@@ -829,6 +828,7 @@ AddActor = Turret
829828
ParentOffset = Vector
830829
X = 0
831830
Y = 0
831+
ForcedHFlip = 1
832832

833833
AddActor = ACrab
834834
CopyOf = Coalition Bunker Cannon Right
@@ -840,8 +840,7 @@ AddActor = ACrab
840840
ParentOffset = Vector
841841
X = 0
842842
Y = -2
843-
AddCustomValue = NumberValue
844-
KeepUnflipped = -1
843+
ForcedHFlip = 1
845844

846845

847846
AddTerrainObject = TerrainObject

Data/Coalition.rte/Actors/Turrets/BunkerCannon/BunkerCannonBrace.lua

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,9 @@ function Create(self)
1212
end
1313

1414
self.AIMode = Actor.AIMODE_SENTRY;
15-
16-
if self:GetNumberValue("KeepUnflipped") == -1 then
17-
self.keepFlipped = true;
18-
else
19-
self.keepFlipped = false;
20-
end
21-
22-
if self.Turret then
23-
if self.Turret.MountedDevice then
24-
self.Turret.MountedDevice:SendMessage("SetKeepUnflipped", self:GetNumberValue("KeepUnflipped"));
25-
end
26-
end
2715
end
2816

2917
function Update(self)
3018
-- keep anything from moving us
3119
self.Pos = self.pinPos;
32-
33-
self.HFlipped = self.keepFlipped;
3420
end

Data/Coalition.rte/Actors/Turrets/BunkerCannon/BunkerCannonGun.lua

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
-- This script incorporates Filipawn Industries code and the vanilla burstfire script together
22
-- There is likely better ways of doing a lot of this, potentially even standardizing it so it can be easily used more widely
33

4-
function OnMessage(self, message, context)
5-
if message == "SetKeepUnflipped" then
6-
self.keepFlipped = context == -1 and true or false;
7-
end
8-
end
9-
104
function OnFire(self)
115

126
self.FireTimer:Reset();
@@ -44,51 +38,67 @@ function Create(self)
4438

4539
self.reloadSmokeTimer = Timer();
4640

47-
self.rotationSpeed = 0.04;
48-
self.smoothedRotAngle = self.RotAngle;
49-
self.InheritedRotAngleTarget = 0;
41+
self.rotationSpeed = 0.05;
42+
self.rotAngleDeviation = 0;
5043

5144
self.shotsPerBurst = self:NumberValueExists("ShotsPerBurst") and self:GetNumberValue("ShotsPerBurst") or 3;
5245
self.coolDownDelay = 500;
5346

54-
self.keepFlipped = false;
47+
if self.HFlipped then
48+
self.RotAngle = math.pi;
49+
end
50+
51+
self.LastHFlipped = self.HFlipped;
52+
self.LastRotAngle = self.RotAngle;
5553
end
5654

5755
function Update(self)
5856

5957
self.servoLoopSound.Pos = self.Pos;
60-
61-
self.HFlipped = self.keepFlipped;
6258

63-
self.parent = IsActor(self:GetRootParent()) and ToActor(self:GetRootParent()) or nil;
59+
if self.LastHFlipped ~= nil then
60+
if self.LastHFlipped ~= self.HFlipped then
61+
self.LastHFlipped = self.HFlipped
62+
self.rotAngleDeviation = 0;
63+
end
64+
end
6465

66+
self.parent = IsActor(self:GetRootParent()) and ToActor(self:GetRootParent()) or nil;
6567
self.playerControlled = (self.parent and self.parent:IsPlayerControlled()) and true or false;
6668

67-
-- reticule of actual aim line so the gun feels cannon-y rather than unresponsive
68-
69-
local actingRotAngle = self.RotAngle - self.InheritedRotAngleOffset;
70-
71-
if self.playerControlled and self.parent.SharpAimProgress > 0.13 then
72-
for i = 1, 24 do
73-
if i % 3 == 0 then
74-
local dotVec = Vector(i*self.FlipFactor, 0):RadRotate(actingRotAngle) + self.Pos + Vector((self.SharpLength + 15) * self.FlipFactor, 0):RadRotate(actingRotAngle)*self.parent.SharpAimProgress;
75-
PrimitiveMan:DrawLinePrimitive(dotVec, dotVec, 116, 2);
69+
-- Rotation smoothing related stuff
70+
if self.parent then
71+
local actingRotAngle = self.parent:GetAimAngle(true)
72+
local aimAngle = self.parent:GetAimAngle(false) * self.FlipFactor;
73+
74+
-- Reticule
75+
if self.playerControlled and self.parent.SharpAimProgress > 0.13 then
76+
for i = 1, 24 do
77+
if i % 3 == 0 then
78+
local dotVec = Vector(i*self.FlipFactor, 0):RadRotate(aimAngle) + self.Pos + Vector((self.SharpLength + 15) * self.FlipFactor, 0):RadRotate(aimAngle)*self.parent.SharpAimProgress;
79+
PrimitiveMan:DrawLinePrimitive(dotVec, dotVec, 116, 2);
80+
end
7681
end
7782
end
83+
84+
self.rotAngleDeviation = self.rotAngleDeviation + (self.LastRotAngle - actingRotAngle);
85+
86+
if self.rotAngleDeviation ~= 0 then
87+
self.rotAngleDeviation = self.rotAngleDeviation - (self.rotAngleDeviation * self.rotationSpeed);
88+
if math.abs(self.rotAngleDeviation) < 0.001 then
89+
self.rotAngleDeviation = 0;
90+
end
91+
end
92+
93+
self.InheritedRotAngleOffset = self.rotAngleDeviation * self.FlipFactor;
94+
self.LastRotAngle = actingRotAngle;
95+
96+
self.servoLoopSoundVolumeTarget = 0 + math.abs(self.rotAngleDeviation)
97+
self.servoLoopSound.Volume = self.servoLoopSound.Volume - (0.5 * (self.servoLoopSound.Volume - self.servoLoopSoundVolumeTarget));
98+
self.servoLoopSoundPitchTarget = 1 + math.abs(self.rotAngleDeviation)
99+
self.servoLoopSound.Pitch = self.servoLoopSound.Pitch - (0.1 * (self.servoLoopSound.Pitch - self.servoLoopSoundPitchTarget));
78100
end
79-
-- rotation smoothing, for a cannon-y feel:
80-
81-
if self.smoothedRotAngle ~= actingRotAngle then
82-
self.smoothedRotAngle = self.smoothedRotAngle - (self.rotationSpeed * (self.smoothedRotAngle - (actingRotAngle)));
83-
end
84-
85-
self.servoLoopSoundVolumeTarget = 0 + math.abs(self.smoothedRotAngle - actingRotAngle)
86-
self.servoLoopSound.Volume = self.servoLoopSound.Volume - (0.5 * (self.servoLoopSound.Volume - self.servoLoopSoundVolumeTarget));
87-
self.servoLoopSoundPitchTarget = 1 + math.abs(self.smoothedRotAngle - actingRotAngle)
88-
self.servoLoopSound.Pitch = self.servoLoopSound.Pitch - (0.1 * (self.servoLoopSound.Pitch - self.servoLoopSoundPitchTarget));
89-
90-
self.InheritedRotAngleOffset = self.smoothedRotAngle - actingRotAngle;
91-
101+
92102
-- Mathemagical firing anim by filipex
93103
local f = math.max(1 - math.min((self.FireTimer.ElapsedSimTimeMS) / 200, 1), 0)
94104
self.Frame = math.floor(f * 8 + 0.55);

Source/Entities/ACrab.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ void ACrab::PreControllerUpdate() {
825825
m_Paths[side][BGROUND][m_MovementState].SetHFlip(m_Controller.IsState(MOVE_LEFT));
826826
}
827827
} else if ((m_Controller.IsState(MOVE_RIGHT) && m_HFlipped) || (m_Controller.IsState(MOVE_LEFT) && !m_HFlipped)) {
828-
m_HFlipped = !m_HFlipped;
828+
SetHFlipped(!m_HFlipped);
829829
m_CheckTerrIntersection = true;
830830
MoveOutOfTerrain(g_MaterialGrass);
831831
for (int side = 0; side < SIDECOUNT; ++side) {
@@ -892,7 +892,7 @@ void ACrab::PreControllerUpdate() {
892892

893893
// Check for flip change
894894
if ((analogAim.m_X > 0 && m_HFlipped) || (analogAim.m_X < 0 && !m_HFlipped)) {
895-
m_HFlipped = !m_HFlipped;
895+
SetHFlipped(!m_HFlipped);
896896
// Instead of simply carving out a silhouette of the now flipped actor, isntead disable any atoms which are embedded int eh terrain until they emerge again
897897
// m_ForceDeepCheck = true;
898898
m_CheckTerrIntersection = true;

Source/Entities/AHuman.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,7 +1532,7 @@ void AHuman::PreControllerUpdate() {
15321532
m_Paths[FGROUND][m_MovementState].SetHFlip(m_Controller.IsState(MOVE_LEFT));
15331533
m_Paths[BGROUND][m_MovementState].SetHFlip(m_Controller.IsState(MOVE_LEFT));
15341534
} else if ((m_Controller.IsState(MOVE_RIGHT) && m_HFlipped) || (m_Controller.IsState(MOVE_LEFT) && !m_HFlipped)) {
1535-
m_HFlipped = !m_HFlipped;
1535+
SetHFlipped(!m_HFlipped);
15361536
m_CheckTerrIntersection = true;
15371537
if (m_ProneState == NOTPRONE) {
15381538
MoveOutOfTerrain(g_MaterialGrass);
@@ -1656,7 +1656,7 @@ void AHuman::PreControllerUpdate() {
16561656
m_AimAngle = analogAim.GetAbsRadAngle();
16571657

16581658
if ((analogAim.m_X > 0 && m_HFlipped) || (analogAim.m_X < 0 && !m_HFlipped)) {
1659-
m_HFlipped = !m_HFlipped;
1659+
SetHFlipped(!m_HFlipped);
16601660
m_CheckTerrIntersection = true;
16611661
if (m_ProneState == NOTPRONE) {
16621662
MoveOutOfTerrain(g_MaterialGrass);

Source/Entities/MOSprite.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ void MOSprite::Clear() {
2929
m_SpriteAnimTimer.Reset();
3030
m_SpriteAnimIsReversingFrames = false;
3131
m_HFlipped = false;
32+
m_ForcedHFlip = -1;
3233
m_SpriteRadius = 1.0F;
3334
m_SpriteDiameter = 2.0F;
3435
m_Rotation.Reset();
@@ -44,7 +45,7 @@ void MOSprite::Clear() {
4445
int MOSprite::Create() {
4546
if (MovableObject::Create() < 0)
4647
return -1;
47-
48+
4849
// Post-process reading
4950
m_aSprite.clear();
5051
m_SpriteFile.GetAsAnimation(m_aSprite, m_FrameCount);
@@ -81,6 +82,9 @@ int MOSprite::Create(ContentFile spriteFile,
8182
m_SpriteOffset.SetXY(static_cast<float>(-m_aSprite[0]->w) / 2.0F, static_cast<float>(-m_aSprite[0]->h) / 2.0F);
8283

8384
m_HFlipped = false;
85+
if (m_ForcedHFlip == 1) {
86+
m_HFlipped = true;
87+
}
8488

8589
// Calc maximum dimensions from the Pos, based on the sprite
8690
float maxX = std::max(std::fabs(m_SpriteOffset.GetX()), std::fabs(static_cast<float>(m_aSprite[0]->w) + m_SpriteOffset.GetX()));
@@ -108,6 +112,12 @@ int MOSprite::Create(const MOSprite& reference) {
108112
m_SpriteAnimMode = reference.m_SpriteAnimMode;
109113
m_SpriteAnimDuration = reference.m_SpriteAnimDuration;
110114
m_HFlipped = reference.m_HFlipped;
115+
m_ForcedHFlip = reference.m_ForcedHFlip;
116+
if (m_ForcedHFlip == 0) {
117+
m_HFlipped = false;
118+
} else if (m_ForcedHFlip == 1) {
119+
m_HFlipped = true;
120+
}
111121
m_SpriteRadius = reference.m_SpriteRadius;
112122
m_SpriteDiameter = reference.m_SpriteDiameter;
113123

@@ -157,6 +167,7 @@ int MOSprite::ReadProperty(const std::string_view& propName, Reader& reader) {
157167
});
158168
MatchProperty("SpriteAnimDuration", { reader >> m_SpriteAnimDuration; });
159169
MatchProperty("HFlipped", { reader >> m_HFlipped; });
170+
MatchProperty("ForcedHFlip", { reader >> m_ForcedHFlip; });
160171
MatchProperty("Rotation", { reader >> m_Rotation; });
161172
MatchProperty("AngularVel", { reader >> m_AngularVel; });
162173
MatchProperty("SettleMaterialDisabled", { reader >> m_SettleMaterialDisabled; });

0 commit comments

Comments
 (0)