##########################################################################################
## --Teleport Move & Teleport Move Field
##########################################################################################
--[[
These intel types will only work IF the unit has them as a custom intel type..
--]]
--Teleport Move
CreateTeleportMoveEnhancement = function(self, spec)
if not spec or table.getsize(spec) == 0 then
spec = self:GetDefaultTeleportMoveParams('single')
end
self:AddCustomUnitIntel('TeleportMove', spec)
end,
RemoveTeleportMoveEnhancement = function(self)
self:RemoveCustomUnitIntel('TeleportMove')
end,
Activate_TeleportMove = function(self, intelType)
self:SetTeleportMoveStatus(true, intelType)
end,
Deactivate_TeleportMove = function(self,intelType)
self:SetTeleportMoveStatus(false, intelType)
end,
SetTeleportMoveStatus = function(self, enabled, intelType)
if enabled then
self:SetUnitParam('CanTeleportMove', true)
self:RemoveUnitThread('TeleportUnitToDestination')
self:RemoveUnitThread('WaitForTeleportMoveReady')
self:RemoveUnitThread('TeleportUnitsInRange')
self:RemoveUnitThread('TeleportCoolDownTimer')
if self:GetMotionStatus() == 'TopSpeed' then
self:TeleportToDestination()
end
elseif not enabled then
self:SetUnitParam('CanTeleportMove', false)
self:RemoveUnitThread('WaitForTeleportMoveReady')
self:RemoveUnitThread('TeleportUnitsInRange')
self:RemoveUnitThread('TeleportCoolDownTimer')
end
end,
GetTeleportMoveStatus = function(self)
return self:GetUnitParam('CanTeleportMove')
end,
IsBeingTeleported = function(self)
return self:GetUnitParam('IsBeingTeleported') or false
end,
SetIsBeingTeleported = function(self, Param)
if Param and not self:IsBeingTeleported() then
self:SetUnitParam('IsBeingTeleported', true)
elseif not Param and self:IsBeingTeleported() then
self:SetUnitParam('IsBeingTeleported', false)
end
end,
TeleportToDestination = function(self)
local MyPos = self:GetPosition()
local Destination = self:GetNavigator():GetGoalPos()
local ValidDestination = import('/lua/AI/aiutilities.lua').CheckUnitPathingEx(Destination, MyPos, self)
if ValidDestination then
if not EntityCategoryContains(categories.CANNOTTELEPORT, self) then
self:ForkThread(self.InitializeTeleportToDestination)
else
ShowMouseText(self, '--> Teleport Denied, Invalid Unit <--')
end
else
ShowMouseText(self, '--> Teleport Denied, Invalid Destination <--')
end
end,
InitializeTeleportToDestination = function(self)
local bp = self:GetBlueprint().Economy
local MyCats = bp.Categories or {}
local TeleportParams = self:GetCustomIntelParams('TeleportMove') or self:GetCustomIntelParams('TeleportMoveField') or {}
local ExcludedCats = TeleportParams.ExcludeCats
local IsUnitExcluded = false
--before we go further we need to check this..
for id, Cat in MyCats do
if table.find(ExcludedCats, Cat) then
IsUnitExcluded = true
break
end
end
if IsUnitExcluded then
ShowMouseText(self, '--> Teleport Denied, Unit Cannot Be Teleported <--' )
return
end
if self:HasThread('WaitForTeleportMoveReady') then
self:RemoveUnitThread('WaitForTeleportMoveReady')
end
--here we go...
local CanTeleport = false
local EnoughEnergy = false
local InRange = false
local CoolDownTime = TeleportParams.CoolDownTime or false
local FreeEnergy = self:Get_Econ('FreeEnergy')
local energyCost = self:GetUnitParam('TeleportEnergyCost') or bp.BuildCostEnergy or 0 * (self:GetUnitParam('TeleportEnergyMod') or bp.TeleportEnergyMod or 0.3)
local MyPos = table.deepcopy(self:GetPosition())
local Destination = self:GetNavigator():GetGoalPos()
local CurrDistance = VDist3(MyPos, Destination)
local MaxDistance = TeleportParams.MaxDistance or CurrDistance + 2
local FreeTeleport = TeleportParams.FreeTeleport or false
local ValidDestination = import('/lua/AI/aiutilities.lua').CheckUnitPathingEx(Destination, MyPos, self)
local InAntiTeleportField = self:IsInField('AntiTeleportField')
local DesNotInAntiTeleportField = self:CheckDestinationForAntiTeleport(Destination)
local Orientation = table.deepcopy(self:GetOrientation())
local CoolDownStatus = self:GetUnitParam('TeleportCoolDownStatus') or false
if self:GetUnitParam('TeleportCoolDownProgress') != nil then
if CoolDownTime then
if type(CoolDownTime) == 'number' and CoolDownTime > 0 then
if not self:HasThread('TeleportCoolDownTimer') and not CoolDownStatus then
local CoolDownParams = { CoolDownTime = CoolDownTime }
self:AddUnitThread('TeleportCoolDownTimer', CoolDownParams)
end
if not CoolDownStatus then
return
end
else
CoolDownStatus = true
end
else
CoolDownStatus = true
end
else
self:SetUnitParam('TeleportCoolDownProgress', 0)
CoolDownStatus = true
end
if FreeTeleport then
energyCost = 0
end
if FreeEnergy >= energyCost then
EnoughEnergy = true
else
ShowMouseText(self, '--> Teleport Denied, Energy Required ' .. energyCost .. ' <--')
end
if CurrDistance <= MaxDistance then
InRange = true
else
ShowMouseText(self, '--> Teleport Denied, Moving InTo TeleportRange <--')
end
if InAntiTeleportField then
ShowMouseText(self, '--> Teleport Denied, Scrambled <--')
end
if not DesNotInAntiTeleportField then
ShowMouseText(self, '--> Teleport Denied, Destination Scrambled <--')
end
if MaxDistance == 0 then
InRange = true
end
if InRange and EnoughEnergy and ValidDestination and not InAntiTeleportField and DesNotInAntiTeleportField and CoolDownStatus then
CanTeleport = true
end
if CanTeleport then
if not self:HasThread('TeleportUnitToDestination') then
local Params = { energyCost = energyCost, Destination = Destination, CurrPos = MyPos, Orientation = Orientation, CoolDownTime = CoolDownTime, ExcludedCats = ExcludedCats }
self:AddUnitThread('TeleportUnitToDestination', Params)
end
else
if not self:HasThread('WaitForTeleportMoveReady') then
local Params = { energyCost = energyCost, maxDistance = MaxDistance, CurrPos = MyPos, Orientation = Orientation, CoolDownTime = CoolDownTime, ExcludedCats = ExcludedCats }
--self:AddUnitThread('WaitForTeleportMoveReady', Params)
end
end
end,
TeleportCoolDownTimer = function(self, Params)
local CurrProgress = self:GetUnitParam('TeleportCoolDownProgress') or 0
local CoolDownTime = Params.CoolDownTime or 0
if CoolDownTime == 0 then
self:SetUnitParam('TeleportCoolDownStatus', true)
if self:GetMotionStatus() != 'Stopped' then
self:TeleportToDestination()
end
else
--the charge doesnt cost energy because the unit should already be using a consumption..
while CurrProgress <= CoolDownTime do
CurrProgress = CurrProgress + 1
self:SetUnitParam('TeleportCoolDownProgress', CurrProgress)
WaitSeconds(1)
end
if CurrProgress >= CoolDownTime then
self:SetUnitParam('TeleportCoolDownStatus', true)
self:SetUnitParam('TeleportCoolDownProgress', 0)
if self:GetMotionStatus() != 'Stopped' then
self:TeleportToDestination()
end
end
end
self:RemoveUnitThread('TeleportCoolDownTimer')
end,
TeleportUnitToDestination = function(self, Params)
self:SetIsBeingTeleported(true)
if self:UnitHasRallyPoint() then
self:HideUnitRallyPointsWhenMoving()
end
local aiBrain = self:GetAIBrain()
aiBrain:TakeResource( 'ENERGY', Params.energyCost or 0 )
WaitTicks(2)
self:SetUnitHidden(true)
local Destination = Params.Destination
local Orientation = Params.Orientation
local TeleportParams = self:GetCustomIntelParams('TeleportMove') or self:GetCustomIntelParams('TeleportMoveField')
local CoolDownTime = Params.CoolDownTime
--Default Pods
local HasPod = false
local LeftPod = false
local RightPod = false
if EntityCategoryContains(categories.PODSTAGINGPLATFORM, self) then
if self.HasLeftPod then
LeftPod = self.LeftPod
HasPod = true
end
if self.HasRightPod then
RightPod = self.RightPod
HasPod = true
end
end
self:PlayTeleportMoveOutEffects()
Warp(self, Destination, Orientation)
self:SetUnitParam('TeleportCoolDownStatus', false)
if TeleportParams.HasField then
if not self:HasThread('TeleportUnitsInRange') then
local UnitsInRangeParams = { Destination = Destination, Pos = Params.CurrPos, FreeTeleport = TeleportParams.FreeTeleport or false, Orientation = Params.Orientation, ExcludedCats = Params.ExcludedCats }
self:AddUnitThread('TeleportUnitsInRange', UnitsInRangeParams)
end
end
if HasPod then
if LeftPod then
IssueClearCommands( { LeftPod } )
LeftPod:SetUnitHidden(true)
Warp(LeftPod, Destination, Orientation)
end
if RightPod then
IssueClearCommands( { RightPod } )
RightPod:SetUnitHidden(true)
Warp(RightPod, Destination, Orientation)
end
end
WaitTicks(2)
self:PlayTeleportMoveInEffects()
WaitSeconds(.3)
self:GetNavigator():AbortMove()
self:SetUnitHidden(false)
self:RemoveUnitThread('TeleportCoolDownTimer')
self:DestroyMovementEffects()
self:SetIsBeingTeleported(false)
if HasPod then
if LeftPod then
LeftPod:SetUnitHidden(false)
end
if RightPod then
RightPod:SetUnitHidden(false)
end
end
if self:UnitHasRallyPoint() then
self:ShowUnitRallyPointsWhenStopped()
end
if CoolDownTime then
if type(CoolDownTime) == 'number' and CoolDownTime > 0 then
if not self:HasThread('TeleportCoolDownTimer') then
local CoolDownParams = { CoolDownTime = CoolDownTime }
self:AddUnitThread('TeleportCoolDownTimer', CoolDownParams)
end
end
end
self:RemoveUnitThread('TeleportUnitToDestination')
self:RemoveUnitThread('WaitForTeleportMoveReady')
end,
--we have this run all the time if we cant teleport, just in case the destination changes...
--saves doing alot of coding work with the orders...
--not currently used.
WaitForTeleportMoveReady = function(self, Params)
local CanTeleport = false
local Destination = self:GetNavigator():GetGoalPos()
while not self:IsDead() and not CanTeleport do
local MyPos = self:GetPosition()
Destination = self:GetNavigator():GetGoalPos()
local CurrDistance = VDist3(MyPos, Destination)
local MaxDistance = Params.maxDistance or CurrDistance + 2
local FreeEnergy = self:Get_Econ('FreeEnergy')
local ValidDestination = import('/lua/AI/aiutilities.lua').CheckUnitPathingEx(Destination, MyPos, self)
local DesNotInAntiTeleportField = self:CheckDestinationForAntiTeleport(Destination)
local InAntiTeleportField = self:IsInField('AntiTeleportField')
if FreeEnergy >= Params.energyCost and CurrDistance <= MaxDistance and ValidDestination and not InAntiTeleportField and DesNotInAntiTeleportField then
CanTeleport = true
end
WaitTicks(5)
end
if CanTeleport then
Params.Destination = Destination
self:AddUnitThread('TeleportUnitToDestination', Params)
self:RemoveUnitThread('WaitForTeleportMoveReady')
end
end,
CheckDestinationForAntiTeleport = function(self, Destination)
local ValidDestination = true
for num, brain in ArmyBrains do
if brain:GetArmyIndex() != self:GetArmy() then
local units = brain:GetIntelTypeUnits('AntiTeleportField')
for id, unit in units do
if unit and not unit:IsDead() or not unit:BeenDestroyed() and IsEnemy(self:GetArmy(), unit:GetArmy()) then
if unit:HasCustomIntelType('AntiTeleportField') and unit:IsIntelEnabled('AntiTeleportField') then
local AntiTeleportParams = unit:GetCustomIntelParams('AntiTeleportField')
local AntiTeleRadius = AntiTeleportParams.Radius
local UnitPos = unit:GetPosition()
local GenDistToDest = VDist2(Destination[1], Destination[3], UnitPos[1], UnitPos[3])
if GenDistToDest < AntiTeleRadius then
ValidDestination = false
break
end
end
end
end
if not ValidDestination then break end
end
end
return ValidDestination
end,
GetDefaultTeleportMoveParams = function(self, Type)
local spec = {}
local Type = Type or 'single'
if Type != 'field' then
spec = {
MaintenanceConsumptionPerSecondEnergy = 75,
WatchPower = true,
AddToggles = true,
Toggles = { RULEETC_TeleportMoveToggle = { StartEnabled = false } },
EnabledOnTransport = false,
MaxDistance = 20,
MinDistance = 5,
FreeTeleport = true,
CoolDownTime = 15,
ExcludeCats = {'POD', 'HOLOGRAM', 'STRUCTURE', 'WALL', 'IMMOBILE' },
ExcludeUnitIds = {},
}
else
spec = {
MaintenanceConsumptionPerSecondEnergy = 10,
WatchPower = true,
AddToggles = true,
Toggles = { RULEETC_TeleportMoveFieldToggle = { StartEnabled = false } },
EnabledOnTransport = false,
MaxDistance = 200,
MinDistance = 5,
FreeTeleport = true,
CoolDownTime = 5,
HasField = true,
Radius = 20,
FieldEffects = 'AlliedUnits',
IncludeGenerator = false,
ExcludeCats = {'POD', 'HOLOGRAM', 'STRUCTURE', 'WALL', 'IMMOBILE'},
ExcludeUnitIds = {},
}
end
return spec
end,
--id love to shoot off a projectile with trail from the unit before it telports.. to the destination..
--that would be a cool effect.. however im not to sure how to make that happen... (yet)
PlayTeleportMoveOutEffects = function(self)
local army = self:GetArmy()
explosion.CreateFlash( self, -1, explosion.GetAverageBoundingXZRadius(self), army )
self:PlayUnitSound('GateOut')
end,
PlayTeleportMoveInEffects = function(self)
local TeleportInEffects = {
'/effects/emitters/generic_teleportin_01_emit.bp',
'/effects/emitters/generic_teleportin_02_emit.bp',
'/effects/emitters/generic_teleportin_03_emit.bp',
}
local bp = self:GetBlueprint()
local army = self:GetArmy()
local UnitRadius = explosion.GetAverageBoundingXZRadius(self)
--explosion.CreateFlash( self, -1, UnitRadius, army )
for k, v in TeleportInEffects do
emit = CreateEmitterAtEntity(self,army,v):ScaleEmitter((UnitRadius or 1) * 2):OffsetEmitter(0, (bp.Physics.MeshExtentsY or 1) / 2, 0)
end
self:PlayUnitSound('GateIn')
end,
--Teleport Move Field
CreateTeleportMoveFieldEnhancement = function(self, spec)
if not spec or table.getsize(spec) == 0 then
spec = self:GetDefaultTeleportMoveParams('field')
end
self:AddCustomUnitIntel('TeleportMoveField', spec)
end,
RemoveTeleportMoveFieldEnhancement = function(self)
self:RemoveCustomUnitIntel('TeleportMoveField')
end,
TeleportUnitsInRange = function(self, Params)
local FieldUnits = GetIntelFieldUnits(self, 'TeleportMoveField')
if table.getsize(FieldUnits) > 0 then
for id, unit in FieldUnits do
if not table.equal(unit, self) then
local Destination = unit:CalculateTeleportPosition(Params.Pos, Params.Destination)
local TeleParams = { Destination = Destination, FreeTeleport = Params.FreeTeleport, Orientation = Params.Orientation, ExcludedCats = Params.ExcludedCats }
unit:AddUnitThread('TeleportUnitToDestinationInField', TeleParams)
end
end
end
self:RemoveUnitThread('TeleportUnitsInRange')
end,
TeleportUnitToDestinationInField = function(self, Params)
local bp = self:GetBlueprint().Economy
local MyCats = bp.Categories or {}
local ExcludedCats = Params.ExcludeCats
local FreeEnergy = self:Get_Econ('FreeEnergy')
local energyCost = self:GetUnitParam('TeleportEnergyCost') or bp.BuildCostEnergy or 0 * (self:GetUnitParam('TeleportEnergyMod') or bp.TeleportEnergyMod or 0.3)
local Destination = Params.Destination
local MyPos = self:GetPosition()
local CanTeleport = false
local EnoughEnergy = false
local ValidUnit = false
local ValidDestination = import('/lua/AI/aiutilities.lua').CheckUnitPathingEx(Destination, MyPos, self)
local DesNotInAntiTeleportField = self:CheckDestinationForAntiTeleport(Destination)
local InAntiTeleportField = self:IsInField('AntiTeleportField')
local TeleportIntelEnabled = false
local Orientation = Params.Orientation
local IsUnitExcluded = false
--before we go further we need to check this..
for id, Cat in MyCats do
if table.find(ExcludedCats, Cat) then
IsUnitExcluded = true
break
end
end
if IsUnitExcluded then
return
end
--here we go
if Params.FreeTeleport then
energyCost = 0
end
if FreeEnergy >= energyCost then
EnoughEnergy = true
end
--put this in blueprints add the category to all structures, walls, immobile, pods,
if not EntityCategoryContains(categories.CANNOTTELEPORT, self) then
ValidUnit = true
end
if self:HasCustomIntelType('TeleportMove') and self:IsIntelEnabled('TeleportMove') then
TeleportIntelEnabled = true
end
if self:HasCustomIntelType('TeleportMoveField') and self:IsIntelEnabled('TeleportMoveField') then
TeleportIntelEnabled = true
end
if EnoughEnergy and ValidUnit and ValidDestination and not InAntiTeleportField and DesNotInAntiTeleportField and not TeleportIntelEnabled then
CanTeleport = true
end
if CanTeleport then
self:SetIsBeingTeleported(true)
if self:UnitHasRallyPoint() then
self:HideUnitRallyPointsWhenMoving()
end
WaitTicks(Random(3, 25))
local aiBrain = self:GetAIBrain()
aiBrain:TakeResource( 'ENERGY', energyCost or 0 )
WaitTicks(2)
self:SetUnitHidden(true)
self:PlayTeleportMoveOutEffects()
Warp(self, Destination, Orientation)
WaitTicks(2)
self:PlayTeleportMoveInEffects()
WaitSeconds(.3)
self:GetNavigator():AbortMove()
self:DestroyMovementEffects()
self:SetUnitHidden(false)
self:SetIsBeingTeleported(false)
if self:UnitHasRallyPoint() then
self:ShowUnitRallyPointsWhenStopped()
end
self:RemoveUnitThread('TeleportUnitToDestinationInField')
else
self:RemoveUnitThread('TeleportUnitToDestinationInField')
end
end,
CalculateTeleportPosition = function(self, Pos, Destination)
local MyPosX, MyPosY, MyPosZ = unpack(self:GetPosition())
local PosX, PosY, PosZ = unpack(Pos)
local DifX = PosX - MyPosX
local DifY = PosY - MyPosY
local DifZ = PosZ - MyPosZ
local DesX, DesY, DesZ = unpack(Destination)
DesX = DesX - DifX
DesY = DesY - DifY
DesZ = DesZ - DifZ
return Vector(DesX, DesY, DesZ)
end,
##########################################################################################
## --Anti Teleport Field
##########################################################################################
CreateAntiTeleportFieldEnhancement = function(self, spec)
if not spec or table.getsize(spec) == 0 then
spec = self:GetDefaultAntiTeleportParams()
end
self:AddCustomUnitIntel('AntiTeleportField', spec)
end,
RemoveAntiTeleportFieldEnhancement = function(self)
self:RemoveCustomUnitIntel('AntiTeleportField')
end,
SetUnitInAntiTeleportField = function(self, generator, param)
if param then
elseif not param then
end
end,
SetAntiTeleportFieldStatus = function(self, Param, intelType)
if Param and not self:GetUnitParam('AntiTeleportFieldEnabled') then
self:SetUnitParam('AntiTeleportFieldEnabled', true)
local MyBrain = self:GetAIBrain()
MyBrain:SetAntiTeleportUnit(self, true)
elseif not Param and self:GetUnitParam('AntiTeleportFieldEnabled') then
self:SetUnitParam('AntiTeleportFieldEnabled', nil)
local MyBrain = self:GetAIBrain()
MyBrain:SetAntiTeleportUnit(self, false)
end
end,
GetDefaultAntiTeleportParams = function(self)
spec = {
MaintenanceConsumptionPerSecondEnergy = 10,
WatchPower = true,
AddToggles = true,
Toggles = { RULEETC_AntiTeleportFieldToggle = { StartEnabled = true } },
EnabledOnTransport = false,
HasField = true,
Radius = 20,
FieldEffects = 'EnemyUnits',
ExcludeCats = {},
ExcludeUnitIds = {},
}
return spec
end,