FAForever Forums
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Login

    How to add Phase shields to a unit and create custom unit meshes

    Scheduled Pinned Locked Moved Modding & Tools
    13 Posts 3 Posters 493 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • R
      Resin_Smoker
      last edited by Resin_Smoker

      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..
      8c390484-b466-4fab-a05f-798f47b4e125-image.png

      Unphased the unit looks like this...
      526c70c6-d966-420b-a1a7-69242391157f-image.png

      Kykhu Oss https://youtu.be/JUgyGTgeZb8
      Unit Thrower https://youtu.be/iV8YBXVxxeI
      Beam Tentacle https://youtu.be/le5SNwHvC4c
      Blackhole https://www.youtube.com/watch?v=D9NGQC5rr0c
      Resurection https://www.youtube.com/watch?v=WdbIQ4vHkMs

      1 Reply Last reply Reply Quote 2
      • R
        Resin_Smoker
        last edited by

        Video of the completed unit: https://youtu.be/Z8-xmlCReQs

        Kykhu Oss https://youtu.be/JUgyGTgeZb8
        Unit Thrower https://youtu.be/iV8YBXVxxeI
        Beam Tentacle https://youtu.be/le5SNwHvC4c
        Blackhole https://www.youtube.com/watch?v=D9NGQC5rr0c
        Resurection https://www.youtube.com/watch?v=WdbIQ4vHkMs

        1 Reply Last reply Reply Quote 0
        • JipJ
          Jip
          last edited by

          That looks really epic 👍

          A work of art is never finished, merely abandoned

          R 1 Reply Last reply Reply Quote 0
          • R
            Resin_Smoker @Jip
            last edited by Resin_Smoker

            @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.

            Kykhu Oss https://youtu.be/JUgyGTgeZb8
            Unit Thrower https://youtu.be/iV8YBXVxxeI
            Beam Tentacle https://youtu.be/le5SNwHvC4c
            Blackhole https://www.youtube.com/watch?v=D9NGQC5rr0c
            Resurection https://www.youtube.com/watch?v=WdbIQ4vHkMs

            R 1 Reply Last reply Reply Quote 0
            • R
              Resin_Smoker @Resin_Smoker
              last edited by

              Uploaded V5 with the core UEF, Aeon and Seraphim units.
              822898c5-3a53-4c1c-b7be-1e3159892a62-image.png

              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

              Kykhu Oss https://youtu.be/JUgyGTgeZb8
              Unit Thrower https://youtu.be/iV8YBXVxxeI
              Beam Tentacle https://youtu.be/le5SNwHvC4c
              Blackhole https://www.youtube.com/watch?v=D9NGQC5rr0c
              Resurection https://www.youtube.com/watch?v=WdbIQ4vHkMs

              1 Reply Last reply Reply Quote 1
              • R
                Resin_Smoker
                last edited by

                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.

                Kykhu Oss https://youtu.be/JUgyGTgeZb8
                Unit Thrower https://youtu.be/iV8YBXVxxeI
                Beam Tentacle https://youtu.be/le5SNwHvC4c
                Blackhole https://www.youtube.com/watch?v=D9NGQC5rr0c
                Resurection https://www.youtube.com/watch?v=WdbIQ4vHkMs

                1 Reply Last reply Reply Quote 0
                • JipJ
                  Jip
                  last edited by

                  Do you have a Github repository for what you're converting/building here? 🙂

                  A work of art is never finished, merely abandoned

                  R 1 Reply Last reply Reply Quote 0
                  • R
                    Resin_Smoker @Jip
                    last edited by

                    @jip No i do everything local as I'm not a fan of Github.

                    Kykhu Oss https://youtu.be/JUgyGTgeZb8
                    Unit Thrower https://youtu.be/iV8YBXVxxeI
                    Beam Tentacle https://youtu.be/le5SNwHvC4c
                    Blackhole https://www.youtube.com/watch?v=D9NGQC5rr0c
                    Resurection https://www.youtube.com/watch?v=WdbIQ4vHkMs

                    1 Reply Last reply Reply Quote 0
                    • JipJ
                      Jip
                      last edited by

                      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.

                      A work of art is never finished, merely abandoned

                      R 1 Reply Last reply Reply Quote 0
                      • R
                        Resin_Smoker @Jip
                        last edited by Resin_Smoker

                        @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.

                        Kykhu Oss https://youtu.be/JUgyGTgeZb8
                        Unit Thrower https://youtu.be/iV8YBXVxxeI
                        Beam Tentacle https://youtu.be/le5SNwHvC4c
                        Blackhole https://www.youtube.com/watch?v=D9NGQC5rr0c
                        Resurection https://www.youtube.com/watch?v=WdbIQ4vHkMs

                        RoweyR 1 Reply Last reply Reply Quote 0
                        • RoweyR
                          Rowey @Resin_Smoker
                          last edited by

                          @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

                          "The needs of the many outweigh the needs of the few" - Spock

                          R 1 Reply Last reply Reply Quote 0
                          • R
                            Resin_Smoker @Rowey
                            last edited by

                            @rowey Someone could of asked me or Domino.

                            Kykhu Oss https://youtu.be/JUgyGTgeZb8
                            Unit Thrower https://youtu.be/iV8YBXVxxeI
                            Beam Tentacle https://youtu.be/le5SNwHvC4c
                            Blackhole https://www.youtube.com/watch?v=D9NGQC5rr0c
                            Resurection https://www.youtube.com/watch?v=WdbIQ4vHkMs

                            1 Reply Last reply Reply Quote 0
                            • JipJ
                              Jip
                              last edited by

                              The reason I was asking is because ideally, when you're done with your current goals, it would turn into something such as this:

                              • https://github.com/FAForever/fa-total-mayhem

                              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 🙂

                              A work of art is never finished, merely abandoned

                              1 Reply Last reply Reply Quote 1
                              • First post
                                Last post