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

    Predator Camouflage

    Scheduled Pinned Locked Moved Modding & Tools
    11 Posts 3 Posters 386 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 Offline
      Resin_Smoker
      last edited by Resin_Smoker

      Did a short little script to allow my bot to look like any prop its standing next to.

      Video (or it didn't happen): https://youtu.be/frnP8V9ZPW8

      Script...

      -----------------------------------------------------------------------------
      --	File	 : /units/ual0204/ual0204_script.lua
      --
      --	Author(s): EbolaSoup, Resin Smoker, Optimus Prime, Vissroid
      --
      --	Summary  : Aeon T2 Sniper Bot
      --
      --	Copyright © 2024 4DFAF, All rights reserved.
      -----------------------------------------------------------------------------
      
      -- Misc Lua called
      local AWalkingLandUnit = import('/lua/aeonunits.lua').AWalkingLandUnit
      local EffectUtils = import('/lua/EffectUtilities.lua')
      local EffectTemplate = import('/lua/effecttemplates.lua')
      local Custom_4D_EffectTemplate = import('/mods/4DFAF/lua/4D_EffectTemplates.lua')
      local utilities = import('/lua/utilities.lua')
      
      local myDebug = false
      
      -- Weapon Local lua called
      local SniperWeapon = import('/lua/aeonweapons.lua').ADFDisruptorCannonWeapon
      
      -- Bones for weapon recoil effects
      local weaponBones = { 'sniper_rifle', 'sniper_barrel' }
      
      ual0204 = Class(AWalkingLandUnit) {
      	Weapons = {
      		-- Shield Piercing Rifle
      		Sniper_Piercing_Rifle = Class(SniperWeapon) {
      			PlayFxMuzzleSequence = function(self, muzzle)
      				for k, v in weaponBones do
      				   local steamEffects = EffectUtils.CreateBoneEffects( self.unit, v, self.unit:GetArmy(), EffectTemplate.WeaponSteam01 )
      				end
      				local groundEffects = EffectUtils.CreateBoneEffects( self.unit, 'ual0204', self.unit:GetArmy(), Custom_4D_EffectTemplate.ConcussionRing )
      				if self.unit.CamoEntity then
      					self.unit.CamoEntity:Destroy()
      					self.unit.CamoEntity = nil
      					self.unit:DisableIntel('Cloak')
      					self.unit:SetVizToFocusPlayer('Always')
      					self.unit:SetVizToAllies('Always')
      				end
      				SniperWeapon.PlayFxMuzzleSequence(self)
      			end,
      		},
      	},
      
      	OnCreate = function(self,builder,layer)
      		AWalkingLandUnit.OnCreate(self)
      		self:DisableIntel('Cloak')
      		self.CamoEntity = nil
      	end,
      
      	OnMotionHorzEventChange = function(self, new, old)
      		if myDebug then WARN('OnMotionHorzEventChange') end
      		if self and not self:IsDead() then
      			if new == 'Stopped' then
      				if myDebug then WARN('	Stopped') end
      				local propTbl = self:GetPropsInRadius(2)
      				local propBp = propTbl[1].prop.Blueprint
      				if myDebug then WARN('	prop blueprint '..repr(propBp) ) end
      				local mesh = propBp.Display.MeshBlueprint or nil
      				local scale = propBp.Display.UniformScale
      				if myDebug then WARN('	Mesh / Scale: ', mesh, scale) end
      				if mesh then
      					self:EnableIntel('Cloak')
      					self:SetVizToFocusPlayer('Never')
      					self:SetVizToAllies('Never')
      					self.CreateCamoEntity(self, mesh, scale)
      				end
      			else
      				if myDebug then WARN('	moving') end
      				if self.CamoEntity then
      					self.CamoEntity:Destroy()
      					self.CamoEntity = nil
      					self:DisableIntel('Cloak')
      					self:SetVizToFocusPlayer('Always')
      					self:SetVizToAllies('Always')
      				end
      
      			end
      		end
      		AWalkingLandUnit.OnMotionHorzEventChange(self, new, old)
      	end,
      
      	CreateCamoEntity = function(self, mesh, scale)
      		if myDebug then WARN('CreateCloakEntity') end
      		ent = import('/lua/sim/Entity.lua').Entity({Owner = self,})
      		ent:AttachBoneTo( -1, self, 'ual0204' )
      		ent:SetMesh(mesh)
      		ent:SetDrawScale(scale or 1)
      		ent:SetVizToFocusPlayer('Always')
      		ent:SetVizToAllies('Always')
      		ent:SetVizToNeutrals('Intel')
      		ent:SetVizToEnemies('Intel')
      		self.CamoEntity = ent
      		self.Trash:Add(ent)
      	end,
      
      	GetPropsInRadius = function(self, radius)
      		if myDebug then WARN('GetPropsInRadius') end
      		radius = radius or 1
      		local pos = self:GetPosition()
      		local props = GetReclaimablesInRect(Rect(pos[1] - radius, pos[3] - radius, pos[1] + radius, pos[3] + radius))
      		if table.getn(props) then
      			local propsByDist = {}
      			for a, b in props do
      				if not b:BeenDestroyed() then
      					if not IsUnit(b) and not b.IsWreckage then
      						table.insert(propsByDist, {dist = utilities.XZDistanceTwoVectors(pos, b:GetPosition()), prop = b})
      					end
      				end
      			end
      			if myDebug then WARN('	num props after filter: ', table.getn(propsByDist)) end
      			table.sort(propsByDist, sort_by('dist'))
      			return propsByDist
      		else
      			if myDebug then WARN('	no props in radius') end
      			return false
      		end
      	end,
      
      }
      TypeClass = ual0204
      

      Still a lot of work to do on this concept, but at least the hard part is done.

      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 4
      • JipJ Offline
        Jip
        last edited by

        I absolutely love it 👍

        A work of art is never finished, merely abandoned

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

          @jip Thanks! Will tie it into to units movement and its attack. So it could remain unseen until it moves are fires. Which will force it to decloak. Figured this would be way cooler than just another phase mesh swapout.

          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
          • R Offline
            Resin_Smoker
            last edited by

            Woot got everything working! I love having the terrain specific stealth.

            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
            • R Offline
              Resin_Smoker
              last edited by Resin_Smoker

              Updated the script above. Only need to have the weapon charge timer (RenderFireClock) display correctly. Currently it works off of the weapons rate of fire but as this unit must charge to fire, I need to make something custom for it to display correctly.

              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 Offline
                Resin_Smoker @Resin_Smoker
                last edited by Resin_Smoker

                OK here is a proper fire clock that uses the weapons energy drain as its basis.

                OnCreate = function(self,builder,layer)
                	AWalkingLandUnit.OnCreate(self)
                	self:DisableIntel('Cloak')
                	self.CamoEntity = nil
                	self:SetWorkProgress(100)
                end,
                	
                RenderChargeClockThread = function(self, eRequired, eDrain)
                	local clockTime = math.round(10 * (eRequired / eDrain))
                	local totalTime = clockTime
                	while clockTime >= 0 and not self:BeenDestroyed() and not self:IsDead() do
                		self:SetWorkProgress(1 - clockTime / totalTime)
                		clockTime = clockTime - 1
                		WaitSeconds(0.1)
                	end
                end,
                

                Its called from the weapons PlayFxMuzzleSequence via...

                	-- Reset the units reload bar
                	local eDrain = self.EnergyDrainPerSecond
                	local eRequired = self.EnergyRequired
                	self.unit:ForkThread(self.unit.RenderChargeClockThread, eRequired, eDrain)
                

                While it does work, I've noticed that there is a short delay between when the clock finished and when the weapon fires. I'm thinking that the weapons internal reload may have some delays involved that don't show properly in the units UI. Currently the unit shows as 10 seconds but with that delay I'd say its more like 11 seconds.

                10f2075e-4f3a-4ec4-8c60-5ebc20cf1aa0-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 0
                • IndexLibrorumI Offline
                  IndexLibrorum Global Moderator
                  last edited by

                  Not making this part of the Cybran faction is a criminal oversight, however.

                  "Design is an iterative process. The required number of iterations is one more than the number you have currently done. This is true at any point in time."

                  See all my projects:

                  R 2 Replies Last reply Reply Quote 0
                  • R Offline
                    Resin_Smoker @IndexLibrorum
                    last edited by

                    @indexlibrorum IKR... Anyways, I've been pondering making the script into a superclass, so it can later be applied to other units quickly. Including the nasty Cybrans.

                    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
                    • R Offline
                      Resin_Smoker @IndexLibrorum
                      last edited by

                      @indexlibrorum

                      Ok made the script into a SuperClass so it can be easily added to other units, including your Nasty Cybrans!

                      ----------------------------------------------------------------------------
                      --	File		  : /mods/4DFAF/lua/4D_TerrainCamo/4D_TerrainCamo.lua
                      --
                      --	Author		  : Resin_Smoker
                      --
                      --	Summary 	  : Allows a unit to take the appearance of nearby props.
                      --
                      
                      --	Copyright © 2024 4DFAF,  All rights reserved.
                      ----------------------------------------------------------------------------
                      --
                      --	Add the following within a units PlayFxMuzzleSequence or other OnFire type event to remove Terrain Camo	
                      --
                      -- 	-- Remove the Camo entity and cloaking during the units weapon firing event
                      -- 	if self.unit.TerrainCamoEntity then
                      --		self.unit.TerrainCamoEntity:Destroy()
                      --		self.unit.TerrainCamoEntity = nil
                      --		if self.TerrainCamo_Unit_BP.Intel.Cloak then self.unit:DisableIntel('Cloak') end
                      --		if self.TerrainCamo_Unit_BP.Intel.RadarStealth then self.unit:DisableIntel('RadarStealth') end
                      --		self.unit:SetVizToFocusPlayer('Always')
                      --		self.unit:SetVizToAllies('Always')
                      --	end
                      --
                      --	Add these two line within the units lua script, adjusting the local unit info called as nessisary
                      --
                      --	local CLandUnit = import('/lua/cybranunits.lua').CLandUnit
                      --	ClandUnit = import('/mods/4DFAF/lua/CustomAbilities/4D_TerrainCamo/4D_TerrainCamo.lua').TerrainCamo( CLandUnit )
                      --
                      ----------------------------------------------------------------------------
                      
                      -- Misc Lua called
                      local utilities = import('/lua/utilities.lua')
                      
                      -- Set flag "true" to see script progress within the error log
                      local myDebug = false
                      
                      ### Start of TerrainCamo(SuperClass) ###
                      function TerrainCamo(SuperClass)
                      	return Class(SuperClass) {
                      	
                      	OnCreate = function(self,builder,layer)
                      		SuperClass.OnCreate(self)
                      		self.TerrainCamo_Unit_BP = self:GetBlueprint()
                      		
                      		-- Disable unit cloak / stealth until TerrainCamo goes active
                      		if self.TerrainCamo_Unit_BP.Intel.Cloak then
                      			self:DisableIntel('Cloak')
                      		end
                      		if self.TerrainCamo_Unit_BP.Intel.RadarStealth then
                      			self:DisableIntel('RadarStealth')
                      		end
                      		
                      		-- Global for our camo entity		
                      		self.TerrainCamoEntity = nil
                      	end,	
                      	
                      	
                      	OnMotionHorzEventChange = function(self, new, old)
                      		if myDebug then WARN('OnMotionHorzEventChange') end
                      		if self and not self:IsDead() then
                      			
                      			-- When the units stops, engage cloak / camo
                      			if new == 'Stopped' then
                      				if myDebug then WARN('	Stopped') end
                      				local propTbl = self:GetPropsInRadius(2)
                      				local propBp = propTbl[1].prop.Blueprint
                      				if myDebug then WARN('	prop blueprint '..repr(propBp) ) end
                      				local mesh = propBp.Display.MeshBlueprint or nil
                      				local scale = propBp.Display.UniformScale
                      				if myDebug then WARN('	Mesh / Scale: ', mesh, scale) end
                      				if mesh and scale then
                      					if self.TerrainCamo_Unit_BP.Intel.Cloak then self:EnableIntel('Cloak') end
                      					if self.TerrainCamo_Unit_BP.Intel.RadarStealth then self:EnableIntel('RadarStealth') end					
                      					self:SetVizToFocusPlayer('Never')
                      					self:SetVizToAllies('Never')
                      					self:ForkThread(self.CreateFlashFX)
                      					self.CreateTerrainCamoEntity(self, mesh, scale)
                      				end
                      			else
                      				-- When unit moves, remove cloak / camo
                      				if myDebug then WARN('	moving') end
                      				if self.TerrainCamoEntity then
                      					self.TerrainCamoEntity:Destroy()
                      					self.TerrainCamoEntity = nil
                      					if self.TerrainCamo_Unit_BP.Intel.Cloak then self:DisableIntel('Cloak') end
                      					if self.TerrainCamo_Unit_BP.Intel.RadarStealth then self:DisableIntel('RadarStealth') end					
                      					self:SetVizToFocusPlayer('Always')
                      					self:SetVizToAllies('Always')
                      				end
                      
                      			end
                      		end
                      		SuperClass.OnMotionHorzEventChange(self, new, old)
                      	end,
                      		
                      	CreateFlashFX = function(self)
                      		--	Simple FX to make the transition nicer looking
                      		self:PlayUnitSound('EnhanceStart')
                      		local fx = CreateAttachedEmitter(self, -1, self.Army, '/effects/emitters/aeon_sacrifice_02_emit.bp'):ScaleEmitter(1)
                      		WaitTicks(5)
                      		fx:Destroy()
                      	end,
                      
                      	CreateTerrainCamoEntity = function(self, mesh, scale)
                      		if myDebug then WARN('CreateCloakEntity') end	
                      		ent = import('/lua/sim/Entity.lua').Entity({Owner = self,})
                      		ent:AttachBoneTo( -1, self, 0 )	
                      		ent:SetMesh(mesh)	
                      		ent:SetDrawScale(scale or 1)
                      		ent:SetVizToFocusPlayer('Always')
                      		ent:SetVizToAllies('Always')
                      		ent:SetVizToNeutrals('Intel')
                      		ent:SetVizToEnemies('Intel')
                      		self.TerrainCamoEntity = ent
                      		self.Trash:Add(ent)
                      	end,
                      	
                      	GetPropsInRadius = function(self, radius)
                      		if myDebug then WARN('GetPropsInRadius') end
                      		radius = radius or 1
                      		local pos = self:GetPosition()
                      		local props = GetReclaimablesInRect(Rect(pos[1] - radius, pos[3] - radius, pos[1] + radius, pos[3] + radius))
                      		if table.getn(props) then
                      			local propsByDist = {}
                      			for a, b in props do
                      				if not b:BeenDestroyed() then
                      					if not IsUnit(b) and not b.IsWreckage then
                      						table.insert(propsByDist, {dist = utilities.XZDistanceTwoVectors(pos, b:GetPosition()), prop = b})
                      					end
                      				end
                      			end
                      			if myDebug then WARN('	num props after filter: ', table.getn(propsByDist)) end
                      			table.sort(propsByDist, sort_by('dist'))
                      			return propsByDist
                      		else
                      			if myDebug then WARN('	no props in radius') end
                      			return false
                      		end
                      	end,	
                      
                      }
                      end
                      ### End of TerrainCamo(SuperClass) ###
                      

                      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 Offline
                        Resin_Smoker
                        last edited by

                        I've added this ability to the 4DFAF URL0216 Insurgent and will remove it from the Predator. It will instead have a custom unit mesh for cloaking. (need to make it)

                        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
                        • R Offline
                          Resin_Smoker
                          last edited by

                          Made some improvements to the Terrain Camo. It now has a phase out effect before the units takes on the mesh of the nearby trees.

                          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
                          • First post
                            Last post