Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-implement Chrono Dampener to properly use firing cycle + VFX fixes #5883

Merged
merged 16 commits into from
Jun 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog/snippets/balance.5883.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- (#5883) Allow Chrono Dampener to fire immediately when a unit comes into range.

Previously, Chrono was synced to game time to prevent stunlocking. Now, units have a cooldown before they can be stunned by any Chrono, which prevents stunlocking while allowing the new Chrono to be more responsive.

- (#5883) Fix Chrono uselessly firing at structures and landed aircraft.
3 changes: 3 additions & 0 deletions changelog/snippets/fix.5883.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- (#5883) Fix Chrono Dampener's visual effect not scaling with gun range upgrades.

- (#5883) Fix the initial stun effects of Chrono Dampener and make it a flash of energy when a unit gets stunned.
1 change: 1 addition & 0 deletions changelog/snippets/other.5883.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- (#5883) Make Chrono Dampener fire rate, stun categories, and range adjustable with blueprint values. Range is also adjustable with `UnitWeapon:ChangeMaxRadius`.
4 changes: 2 additions & 2 deletions effects/emitters/aeon_chrono_dampener_large_01_emit.bp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ EmitterBlueprint {
LowFidelity = true,
MedFidelity = true,
HighFidelity = true,
Texture = [[/textures/particles/half_moon_01.dds]],
RampTexture = [[/textures/particles/ramp_quantum_warhead_flash_01.dds]],
Texture = '/textures/particles/half_moon_01.dds',
RampTexture = '/textures/particles/ramp_quantum_warhead_flash_01.dds',
XDirectionCurve = {
XRange = 2.00,
Keys = {
Expand Down
6 changes: 3 additions & 3 deletions effects/emitters/aeon_chrono_dampener_large_02_emit.bp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ EmitterBlueprint {
AlignToBone = false,
Flat = true,
LODCutoff = 250.00,
EmitIfVisible = true,
EmitIfVisible = false,
CatchupEmit = true,
CreateIfVisible = false,
SnapToWaterline = false,
Expand All @@ -23,8 +23,8 @@ EmitterBlueprint {
LowFidelity = true,
MedFidelity = true,
HighFidelity = true,
Texture = [[/textures/particles/ring_white_06.dds]],
RampTexture = [[/textures/particles/ramp_chrono_dampener.dds]],
Texture = '/textures/particles/ring_white_06.dds',
RampTexture = '/textures/particles/ramp_chrono_dampener.dds',
XDirectionCurve = {
XRange = 1.00,
Keys = {
Expand Down
4 changes: 2 additions & 2 deletions effects/emitters/aeon_chrono_dampener_large_03_emit.bp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ EmitterBlueprint {
LowFidelity = true,
MedFidelity = true,
HighFidelity = true,
Texture = [[/textures/particles/glow_offset.dds]],
RampTexture = [[/textures/particles/ramp_quantum_warhead_flash_01.dds]],
Texture = '/textures/particles/glow_offset.dds',
RampTexture = '/textures/particles/ramp_quantum_warhead_flash_01.dds',
XDirectionCurve = {
XRange = 2.00,
Keys = {
Expand Down
6 changes: 3 additions & 3 deletions effects/emitters/aeon_chrono_dampener_large_04_emit.bp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ EmitterBlueprint {
AlignToBone = false,
Flat = true,
LODCutoff = 250.00,
EmitIfVisible = true,
EmitIfVisible = false,
CatchupEmit = true,
CreateIfVisible = false,
SnapToWaterline = false,
Expand All @@ -23,8 +23,8 @@ EmitterBlueprint {
LowFidelity = true,
MedFidelity = true,
HighFidelity = true,
Texture = [[/textures/particles/ring_07.dds]],
RampTexture = [[/textures/particles/ramp_quantum_warhead_flash_01.dds]],
Texture = '/textures/particles/ring_07.dds',
RampTexture = '/textures/particles/ramp_quantum_warhead_flash_01.dds',
XDirectionCurve = {
XRange = 1.00,
Keys = {
Expand Down
2 changes: 1 addition & 1 deletion loc/US/strings_db.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1750,7 +1750,7 @@ Unit_Description_s204="Constructs Tech 3 Naval units. Buildable for a much cheap
-- AEON -- Armored Commander Unit/Upgrades
Unit_Description_0305="The Armored Command Unit (ACU) is a combination of barracks and command center. Contains all the blueprints necessary to build a basic army from scratch. Upgradeable with combat enhancements, advanced engineering suites, resource allocation system, and teleportation."
Unit_Description_0156="Grants Tech 2 schematic access and increases the ACU's build speed and maximum health.\n\n+32 Buildpower\n+2000 Health\n+10 Regen"
Unit_Description_0157="Creates a Quantum Stasis Field around the ACU. Immobilizes enemy units within the ACU's main cannon range.\n\n+3000 Health"
Unit_Description_0157="Creates a Quantum Stasis Field around the ACU. Immobilizes enemy units within the ACU's main cannon range. Multiple Quantum Stasis Fields interfere with each other, having a limited effect.\n\n+3000 Health"
Unit_Description_0158="Increases the range of the ACU's main cannon and that of Overcharge.\n\n+8 Main cannon range"
Unit_Description_0159="Grants the ACU a long range omni Sensor and increased optical range.\n\n+54 Vision Radius\n+54 Omni Radius"
Unit_Description_0160="Grants Tech 3 and Experimental schematic access and further increases the ACU's build speed and maximum health.\n\n+58 Buildpower\n+1000 Health\n+10 Regen"
Expand Down
8 changes: 4 additions & 4 deletions lua/EffectTemplates.lua
Original file line number Diff line number Diff line change
Expand Up @@ -832,10 +832,10 @@ AChronoDampener = {
}

AChronoDampenerLarge = {
EmtBpPath .. 'aeon_chrono_dampener_large_01_emit.bp',
EmtBpPath .. 'aeon_chrono_dampener_large_02_emit.bp',
EmtBpPath .. 'aeon_chrono_dampener_large_03_emit.bp',
EmtBpPath .. 'aeon_chrono_dampener_large_04_emit.bp',
EmtBpPath .. 'aeon_chrono_dampener_large_01_emit.bp', -- Body Glow
EmtBpPath .. 'aeon_chrono_dampener_large_02_emit.bp', -- Small dark ring
EmtBpPath .. 'aeon_chrono_dampener_large_03_emit.bp', -- Body Sparks
EmtBpPath .. 'aeon_chrono_dampener_large_04_emit.bp', -- Large bright ring
}

ACommanderOverchargeFlash01 = {
Expand Down
181 changes: 101 additions & 80 deletions lua/sim/weapons/aeon/ADFChronoDampener.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,108 +26,129 @@ local DefaultProjectileWeapon = import("/lua/sim/defaultweapons.lua").DefaultPro
local EffectTemplate = import("/lua/effecttemplates.lua")
local utilities = import('/lua/utilities.lua')

local CategoriesChronoDampener = categories.MOBILE - (categories.COMMAND + categories.EXPERIMENTAL + categories.AIR)

---@class ADFChronoDampener : DefaultProjectileWeapon
ADFChronoDampener = Class(DefaultProjectileWeapon) {
FxMuzzleFlash = EffectTemplate.AChronoDampenerLarge,
FxMuzzleFlashScale = 0.5,
FxUnitStun = EffectTemplate.Aeon_HeavyDisruptorCannonMuzzleCharge,
FxUnitStunFlash = EffectTemplate.ADisruptorCannonMuzzle01,

RackSalvoFiringState = State(DefaultProjectileWeapon.RackSalvoFiringState) {
Main = function(self)
local bp = self.Blueprint
---@type Unit
local unit = self.unit
local primaryWeapon = unit:GetWeaponByLabel('RightDisruptor')
FxUnitStunFlash = EffectTemplate.Aeon_HeavyDisruptorCannonUnitHit,

-- Align to a tick which is a multiple of 50
WaitTicks(51 - math.mod(GetGameTick(), 50))

while true do
---@param self ADFChronoDampener
OnCreate = function(self)
DefaultProjectileWeapon.OnCreate(self)
-- Stores the original FX scale so it can be adjusted by range changes
self.OriginalFxMuzzleFlashScale = self.FxMuzzleFlashScale

if bp.Audio.Fire then
self:PlaySound(bp.Audio.Fire)
end
local buff = self.Blueprint.Buffs[1]
self.CategoriesToStun = ParseEntityCategory(buff.TargetAllow) - ParseEntityCategory(buff.TargetDisallow)
end,

self:PlayFxMuzzleSequence(1)
self:StartEconomyDrain()
self:OnWeaponFired()
---@param self ADFChronoDampener
---@param muzzle string
CreateProjectileAtMuzzle = function(self, muzzle)
local bp = self.Blueprint

-- some constants that need to go into blueprint
local slices = 10
if bp.Audio.Fire then
self:PlaySound(bp.Audio.Fire)
end

-- extract information from the buff blueprint
local buff = bp.Buffs[1]
local stunDuration = buff.Duration
local radius = (primaryWeapon and primaryWeapon:GetMaxRadius()) or buff.Radius
local sliceSize = radius / slices
self.Trash:Add(ForkThread(self.ExpandingStunThread, self))
end,

for i = 1, slices do
--- Thread to avoid waiting in the firing cycle and stalling the main cannon.
---@param self ADFChronoDampener
ExpandingStunThread = function(self)
-- extract information from the buff blueprint
local bp = self.Blueprint
local reloadTimeTicks = MATH_IRound(10/bp.RateOfFire)
local buff = bp.Buffs[1]
local stunDuration = buff.Duration
local radius = self:GetMaxRadius()
local slices = 10
local sliceSize = radius / slices
local sliceTime = stunDuration * 10 / slices + 1
local initialStunFxAppliedUnits = {}
local fireTick = GetGameTick()

for i = 1, slices do

local radius = i * sliceSize
local targets = utilities.GetTrueEnemyUnitsInSphere(
self,
self.unit:GetPosition(),
radius,
self.CategoriesToStun
)
local fxUnitStunFlashScale = (0.5 + (slices-i) / (slices-1) * 1.5)
local currentTick = GetGameTick()

for k, target in targets do

-- add stun effect only on targets our Chrono Dampener stunned
if initialStunFxAppliedUnits[target] then
local count = target:GetBoneCount()
for k, effect in self.FxUnitStun do
local emit = CreateEmitterAtBone(
target, Random(0, count - 1), target.Army, effect
)

-- scale the effect a bit
emit:ScaleEmitter(0.5)

-- change lod to match outer lod of unit
local lods = target.Blueprint.Display.Mesh.LODs
if lods then
emit:SetEmitterParam("LODCUTOFF", lods[table.getn(lods)].LODCutoff)
end
end
end

local radius = i * sliceSize
local targets = utilities.GetTrueEnemyUnitsInSphere(
self,
self.unit:GetPosition(),
radius,
CategoriesChronoDampener
)
-- prevent multiple Chrono Dampeners from stunlocking units with desynchronized firings
if target.chronoProtectionTick > currentTick then
continue
end

for k, target in targets do
-- add stun
if not target:BeenDestroyed() then
if buff.BuffType == 'STUN' then
target:SetStunned(stunDuration * (slices - i + 1) / slices + 0.1)
target.chronoProtectionTick = fireTick + reloadTimeTicks
end
end

if not target:BeenDestroyed() then
if buff.BuffType == 'STUN' then
target:SetStunned(0.1 * stunDuration / slices + 0.1)
end
end
-- add initial flash effect
for k, effect in self.FxUnitStunFlash do
local emit = CreateEmitterOnEntity(target, target.Army, effect)
emit:ScaleEmitter(fxUnitStunFlashScale * math.max(target.Blueprint.SizeX, target.Blueprint.SizeZ))
end
initialStunFxAppliedUnits[target] = true

-- add initial effect
if not target.InitialStunFxApplied then
for k, effect in self.FxUnitStunFlash do
local emit = CreateEmitterOnEntity(target, target.Army, effect)
emit:ScaleEmitter(math.max(target.Blueprint.SizeX, target.Blueprint.SizeZ))
end
-- add initial stun effect on target
local count = target:GetBoneCount()
for k, effect in self.FxUnitStun do
local emit = CreateEmitterAtBone(
target, Random(0, count - 1), target.Army, effect
)

target.InitialStunFxApplied = true
end
-- scale the effect a bit
emit:ScaleEmitter(0.5)

-- add effect on target
local count = target:GetBoneCount()
for k, effect in self.FxUnitStun do
local emit = CreateEmitterAtBone(
target, Random(0, count - 1), target.Army, effect
)

-- scale the effect a bit
emit:ScaleEmitter(0.5)

-- change lod to match outer lod of unit
local lods = target.Blueprint.Display.Mesh.LODs
if lods then
emit:SetEmitterParam("LODCUTOFF", lods[table.getn(lods)].LODCutoff)
end
end
-- change lod to match outer lod of unit
local lods = target.Blueprint.Display.Mesh.LODs
if lods then
emit:SetEmitterParam("LODCUTOFF", lods[table.getn(lods)].LODCutoff)
end

WaitTicks(stunDuration / slices + 1)
end

WaitTicks(51 - stunDuration)
end
end,

OnFire = function(self)
end,

OnLostTarget = function(self)
ChangeState(self, self.IdleState)
DefaultProjectileWeapon.OnLostTarget(self)
end,
},
WaitTicks(sliceTime)
end
end,

---@param self ADFChronoDampener
---@param muzzle string
CreateProjectileAtMuzzle = function(self, muzzle)
---@param radius number
ChangeMaxRadius = function(self, radius)
DefaultProjectileWeapon.ChangeMaxRadius(self, radius)
self.FxMuzzleFlashScale = self.OriginalFxMuzzleFlashScale * radius / self.Blueprint.MaxRadius
end,
}
2 changes: 1 addition & 1 deletion lua/ui/help/unitdescription.lua
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ Description = {
-- AEON -- Armored Commander Unit/Upgrades
['ual0001'] = "<LOC Unit_Description_0305> Armored Commander is a combination of barracks and command center. Contains all the blueprints necessary to build a basic army from scratch. Upgradeable with combat enhancements, advanced engineering suits, resource allocation system, and teleporting.",
['ual0001-aes'] = "<LOC Unit_Description_0156> Expands the number of available schematics and increases the ACU's build speed and maximum health.",
['ual0001-cd'] = "<LOC Unit_Description_0157> Creates a Quantum Stasis Field around the ACU. Immobilizes enemy units within its radius. High Energy Consumption. Range of the Field Adapts with the range of the Gun",
['ual0001-cd'] = "<LOC Unit_Description_0157> Creates a Quantum Stasis Field around the ACU. Immobilizes enemy units within the ACU's main cannon range. Multiple Quantum Stasis Fields interfere with each other, having a limited effect.",
['ual0001-cba'] = "<LOC Unit_Description_0158>Increases the range of the ACU's main cannon and that of Overcharge.",
['ual0001-ecba'] = "<LOC Unit_Description_0466_faf>Massively increases the range of the ACU's main cannon and that of Overcharge.",
['ual0001-ess'] = "<LOC Unit_Description_0159> Greatly expands the range of the standard on-board ACU sensor systems.",
Expand Down
12 changes: 12 additions & 0 deletions units/UAL0001/UAL0001_script.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ UAL0001 = ClassUnit(ACUUnit) {
self:HideBone('Back_Upgrade', true)
self:HideBone('Right_Upgrade', true)
self:HideBone('Left_Upgrade', true)
-- Set initial range of Chrono here so that max range can be displayed in the UI
local bpDisrupt = self:GetBlueprint().Weapon[1].MaxRadius
local cd = self:GetWeaponByLabel('ChronoDampener')
cd:ChangeMaxRadius(bpDisrupt)
-- Restrict what enhancements will enable later
self:AddBuildRestriction(categories.AEON * (categories.BUILTBYTIER2COMMANDER + categories.BUILTBYTIER3COMMANDER))
end,
Expand Down Expand Up @@ -218,6 +222,8 @@ UAL0001 = ClassUnit(ACUUnit) {
oc:ChangeMaxRadius(bp.NewMaxRadius or 30)
local aoc = self:GetWeaponByLabel('AutoOverCharge')
aoc:ChangeMaxRadius(bp.NewMaxRadius or 30)
local cd = self:GetWeaponByLabel('ChronoDampener')
cd:ChangeMaxRadius(bp.NewMaxRadius or 30)
elseif enh == 'CrysalisBeamRemove' then
local wep = self:GetWeaponByLabel('RightDisruptor')
local bpDisrupt = self:GetBlueprint().Weapon[1].MaxRadius
Expand All @@ -226,6 +232,8 @@ UAL0001 = ClassUnit(ACUUnit) {
oc:ChangeMaxRadius(bpDisrupt or 22)
local aoc = self:GetWeaponByLabel('AutoOverCharge')
aoc:ChangeMaxRadius(bpDisrupt or 22)
local cd = self:GetWeaponByLabel('ChronoDampener')
cd:ChangeMaxRadius(bpDisrupt or 22)
-- Advanced Cryslised Beam
elseif enh == 'FAF_CrysalisBeamAdvanced' then
local wep = self:GetWeaponByLabel('RightDisruptor')
Expand All @@ -234,6 +242,8 @@ UAL0001 = ClassUnit(ACUUnit) {
oc:ChangeMaxRadius(bp.NewMaxRadius or 35)
local aoc = self:GetWeaponByLabel('AutoOverCharge')
aoc:ChangeMaxRadius(bp.NewMaxRadius or 35)
local cd = self:GetWeaponByLabel('ChronoDampener')
cd:ChangeMaxRadius(bp.NewMaxRadius or 35)
elseif enh == 'FAF_CrysalisBeamAdvancedRemove' then
local wep = self:GetWeaponByLabel('RightDisruptor')
local bpDisrupt = self:GetBlueprint().Weapon[1].MaxRadius
Expand All @@ -242,6 +252,8 @@ UAL0001 = ClassUnit(ACUUnit) {
oc:ChangeMaxRadius(bpDisrupt or 22)
local aoc = self:GetWeaponByLabel('AutoOverCharge')
aoc:ChangeMaxRadius(bpDisrupt or 22)
local cd = self:GetWeaponByLabel('ChronoDampener')
cd:ChangeMaxRadius(bpDisrupt or 22)
-- Heat Sink Augmentation
elseif enh == 'HeatSink' then
local wep = self:GetWeaponByLabel('RightDisruptor')
Expand Down
Loading