How to add Phase shields to a unit and create custom unit meshes
-
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.zipMy 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...
-
Video of the completed unit: https://youtu.be/Z8-xmlCReQs
-
That looks really epic
-
@jip At once point we had a "phase" drone, similar in concept to the shield drone.... We abandoned this idea as it was too easy for the Phasing to be applied to a unit and become very unbalancing. (Especially if applied to an experimental) Thus we limited the Phasing to a select number of units that were non-offensive or had a non-offensive mode(s) such as the Flying Walker.
-
Uploaded V5 with the core UEF, Aeon and Seraphim units.
Side note: The mod manager leaves a lot to be desired. Having a hard time navigating things. Would like to clean out the old versions but I'm afraid to touch anything.
Resin
-
Forgot to add that I've updated the look of the unit phasing as it was too cloudy. It's much nicer now but I will continue to play with it till its clear but with signifigant details. I.E. Kinda of ghostly in appearance.
-
Do you have a Github repository for what you're converting/building here?
-
@jip No i do everything local as I'm not a fan of Github.
-
For Github or Git in general? If it is specifically Github, you can also use Gitlab.
The reason I am asking is because if everything is local on your machine then it becomes more difficult for people to collaborate.
-
@jip The core files have been around for over 10 years and in that time no one picked up the project. With that I hardly see the notion of collaboration thru Github as real possibility.
Edit: After the core units are done, sure let's Github them. Until then, changing my process this far in would be more harmful than helpful.
-
@resin_smoker the issue with say they been around for 10 years if they didn't have a licence that allowed other to fix them nothing we could do
-
@rowey Someone could of asked me or Domino.
-
The reason I was asking is because ideally, when you're done with your current goals, it would turn into something such as this:
Specifically the license here is what matters. It does not have to be MIT, but at least permissive enough to allow the community to (help) maintain the mod when you decide to move on again.
At the moment we have some struggles with various well known mod packs - we can't make certain game changes because it would break them. And as we are unable to contact the authors we can also not get the permission and/or a license to setup a Github repository and maintain them. As a result we did not make those game changes.
We're lucky that you got back here and started contributing again with your mod. We have much trouble contacting the original authors simply because all we usually have is a nickname and there's no way to verify that a person with a similar nickname is the original author. Which makes it all difficult