I took something from the old DMS files and modified it to create a custom phase mesh for any unit with "Phasing" in its unit blue print.
Snippet from my custom hook'd BluePrint.lua
function Custom_4DFAF_ExtractPhaseMeshBlueprint(bp)
--Recover the mesh ID or return
local meshid = bp.Display.MeshBlueprint
if not meshid then return end
--Pull the original unit blueprints by its mesh ID
local meshbp = original_blueprints.Mesh[meshid]
if not meshbp then return end
--Verify the unit type is one that we are allowed to enhance with Phasing
if not table.find(bp.Categories, 'PHASING') then
return
else
local LODCutoff, LookupName, NormalsName, SecondaryName, ShaderName, SpecularName
--Custom mesh modifications
LODCutoff = 195
LookupName = '/effects/entities/PhaseShield/PhaseShieldLookup.dds'
NormalsName = '/mods/4DFAF/lua/CustomAbilities/4D_UnitPhasing/4D_Phase_Texture.dds'
ShaderName = 'ShieldSeraphim'
SpecularName = '/mods/4DFAF/lua/CustomAbilities/4D_UnitPhasing/4D_Phase_Texture.dds'
--Create the new mesh
local phasemeshbp = table.deepcopy(meshbp)
phasemeshbp.Merge = true
if phasemeshbp.LODs then
for i,lod in phasemeshbp.LODs do
lod.LookupName = LookupName
lod.NormalsName = NormalsName
lod.ShaderName = ShaderName
lod.SpecularName = SpecularName
lod.LODCutoff = LODCutoff
end
end
--Save the new mesh
phasemeshbp.BlueprintId = meshid .. '_phaseshield'
bp.Display.PhaseMeshBlueprint = phasemeshbp.BlueprintId
MeshBlueprint(phasemeshbp)
end
end
The above Script called for the following textures...
4D_Phase_Texture.zip
My unit blue print has the following...
Categories = {
'MODCONTENT4D',
'AIR',
'DIRECTFIRE',
'MOBILE',
'OVERLAYANTINAVY',
'OVERLAYDIRECTFIRE',
'PHASING',
'RECLAIMABLE',
'SELECTABLE',
'SERAPHIM',
'TECH3',
'VISIBLETORECON',
},
Phasing = {
PhasePercent = 35,
StartEnabled = true,
},
The unit enables the phase shield via toggle bit "7" or via the following function...
self:ForkThread(self.PhaseEnable)
Which in turn runs... /mods/4DFAF/lua/CustomAbilities/4D_UnitPhasing/4D_UnitPhasing.lua
-----------------------------------------------------------------------------
-- File : /lua/UnitPhasing.lua
--
-- Author : Resin_Smoker
--
-- Summary : Unit Phasing: Allows a unit so enhanced to shift it's molecules
-- around into extra spatial dimensions becoming translucent and
-- semi-ethereal, almost completely non corporeal.
-- The advantage to this is that a unit so enhanced can avoid a
-- percentage direct fire weapons by allowing them to pass thru it
-- harmlessly! While protected from directfire projectiles, a Phased
-- unit is still very vunerable from laser weapons, damage over time
-- weapons, and projectile with signifigant splash damage.
--
-- Copyright © 2024 4DFAF, All rights reserved.
-----------------------------------------------------------------------------
--
-- The following is required in the units script for UnitPhasing
-- This calls into action the UnitPhasing scripts for SAirUnit
--
-- local SAirUnit = import('/lua/seraphimunits.lua').SAirUnit
-- SAirUnit = import('/mods/4DFAF/lua/CustomAbilities/4D_UnitPhasing/4D_UnitPhasing.lua').UnitPhasing( SAirUnit )
--
-----------------------------------------------------------------------------
local myDebug = true
-- Start of UnitPhasing(SuperClass)
function UnitPhasing(SuperClass)
return Class(SuperClass) {
OnStopBeingBuilt = function(self, builder, layer)
SuperClass.OnStopBeingBuilt(self, builder, layer)
if myDebug then WARN('UnitPhasing OnStopBeingBuilt') end
--Phase Global Variables
self.MyBp = self:GetBlueprint()
self.PhaseBp = self.MyBp.Phasing
if myDebug then WARN(' PhaseBP = '..repr(self.PhaseBp)) end
self.OldPhaseImpact = nil
self.PhaseAbilityEnabled = false
self.PriorPhaseStatus = false
self:SetMaintenanceConsumptionInactive()
--Enable Phasing if StartsOn true in BP
if self.PhaseBp.StartEnabled == true then
self:SetScriptBit('RULEUTC_SpecialToggle', true)
end
--self:ForkThread(self.PhaseEconomyHeartBeat)
end,
PhaseEconomyHeartBeat = function(self)
local cost = self.MyBp.Economy.MaintenanceConsumptionPerSecondEnergy
while self and not ( self:IsDead() or self:BeenDestroyed() ) do
--Verify that economy is capabile of supporting phasing and that the unit isnt in transport
local econ = self:GetAIBrain():GetEconomyStored('Energy')
if (econ < cost and self.PhaseAbilityEnabled == true and self.PriorPhaseStatus == false) or ((self:IsUnitState('Attached') or self:IsUnitState('TransportLoading')) and (self.PhaseAbilityEnabled == true and self.PriorPhaseStatus == false)) then
self.PriorPhaseStatus = true
self:ForkThread(self.PhaseDisable)
elseif (econ > cost and self.PriorPhaseStatus == true and self.PhaseAbilityEnabled == false) and (not self:IsUnitState('Attached') and not self:IsUnitState('TransportUnloading') and not self:IsUnitState('TransportLoading')) then
self.PriorPhaseStatus = false
self:ForkThread(self.PhaseEnable)
end
--Short delay between checks
WaitTicks(Random(2, 4))
end
end,
OnScriptBitSet = function(self, bit)
if bit == 7 then
if myDebug then WARN('OnScriptBitSet: ', bit)end
self:ForkThread(self.PhaseEnable)
end
SuperClass.OnScriptBitSet(self, bit)
end,
OnScriptBitClear = function(self, bit)
if bit == 7 then
if self.PriorPhaseStatus == true then
self.PriorPhaseStatus = false
end
if myDebug then WARN('OnScriptBitClear: ', bit, ' Prior Status: ', self.PriorPhaseStatus) end
self:ForkThread(self.PhaseDisable)
end
SuperClass.OnScriptBitClear(self, bit)
end,
PhaseEnable = function(self)
WaitSeconds(1)
if self and not ( self:IsDead() or self:BeenDestroyed() ) then
if myDebug then WARN('PhaseEnable called') end
if self.PhaseAbilityEnabled == false and not self:IsUnitState('Attached') then
if myDebug then WARN(' Adding mesh and economy') end
self:SetMesh(self.MyBp.Display.PhaseMeshBlueprint, true)
self.PhaseAbilityEnabled = true
self:SetMaintenanceConsumptionActive()
end
end
end,
PhaseDisable = function(self)
if self and not ( self:IsDead() or self:BeenDestroyed() ) then
if myDebug then WARN('PhaseDisable called') end
if self.PhaseAbilityEnabled == true then
if myDebug then WARN(' Removing mesh and economy') end
self.PhaseAbilityEnabled = false
self:SetMaintenanceConsumptionInactive()
self:SetMesh(self.MyBp.Display.MeshBlueprint, true)
end
end
end,
OnCollisionCheck = function(self, other, firingWeapon)
if self and not ( self:IsDead() or self:BeenDestroyed() ) then
if myDebug then WARN('OnCollisionCheck, % chance of Phasing = ', self.PhaseBp.PhasePercent) end
if self.PhaseAbilityEnabled then
if EntityCategoryContains(categories.PROJECTILE, other) then
--Process phase chance, allows % of projectiles to pass
if myDebug then WARN(' Hit by projectile') end
local ran = Random(1,100)
if ran <= self.PhaseBp.PhasePercent or other == self.OldPhaseImpact then
--Remember what last impacted to prevent the same projectile from being checked twice
self.OldPhaseImpact = other
--Returning false allows the projectile to pass thru
if myDebug then WARN(' Passing projectile through') end
return false
else
--Projectile impacts normally
if myDebug then WARN(' Normal impact') end
self.OldPhaseImpact = nil
return true
end
end
end
return SuperClass.OnCollisionCheck(self, other, firingWeapon)
end
end,
}
end
-- End of UnitPhasing(UnitPhasing)
With the resulting unit looking like this..
Unphased the unit looks like this...