Files
Dota-Zombie-Invasion/scripts/vscripts/ai/ai_demon_dragon_satyr.lua
T
2026-05-29 15:11:31 +07:00

310 lines
10 KiB
Lua

--[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]
local ____exports = {}
local ____dota_ts_adapter = require("lib.dota_ts_adapter")
local registerEntityFunction = ____dota_ts_adapter.registerEntityFunction
local THINK_INTERVAL = 0.25
local TARGET_SEARCH_RADIUS = 2600
local FEAR_CAST_RADIUS = 900
local GRAB_CAST_RANGE = 170
local FACE_CAST_RANGE = 420
local BACK_CAST_RANGE = 720
local abilityGrab
local abilityFear
local abilityBackStun
local abilityFaceStun
local lastOrderGameTime = -999
local lastAttackOrderGameTime = -999
local lastAttackTargetIndex = -1
local function refreshAbilities(self)
if not thisEntity or thisEntity:IsNull() then
return
end
abilityGrab = thisEntity:FindAbilityByName("ability_grab") or nil
abilityFear = thisEntity:FindAbilityByName("fear") or nil
abilityBackStun = thisEntity:FindAbilityByName("back_stun") or nil
abilityFaceStun = thisEntity:FindAbilityByName("face_stun") or nil
end
local function findClosestEnemy(self)
local enemies = FindUnitsInRadius(
thisEntity:GetTeamNumber(),
thisEntity:GetAbsOrigin(),
nil,
TARGET_SEARCH_RADIUS,
DOTA_UNIT_TARGET_TEAM_ENEMY,
bit.bor(DOTA_UNIT_TARGET_HERO, DOTA_UNIT_TARGET_BASIC),
DOTA_UNIT_TARGET_FLAG_FOW_VISIBLE,
FIND_CLOSEST,
false
)
for ____, unit in ipairs(enemies) do
do
if not unit or unit:IsNull() or not unit:IsAlive() then
goto __continue5
end
return unit
end
::__continue5::
end
return nil
end
local function getDistance2D(self, from, to)
return (to - from):Length2D()
end
local function isTargetBehind(self, target)
local toTarget = (target:GetAbsOrigin() - thisEntity:GetAbsOrigin()):Normalized()
local forward = thisEntity:GetForwardVector()
return forward:Dot(toTarget) < -0.25
end
local function isTargetInFront(self, target)
local toTarget = (target:GetAbsOrigin() - thisEntity:GetAbsOrigin()):Normalized()
local forward = thisEntity:GetForwardVector()
return forward:Dot(toTarget) > 0.25
end
local function isPointInFront(self, point)
local toPoint = (point - thisEntity:GetAbsOrigin()):Normalized()
local forward = thisEntity:GetForwardVector()
return forward:Dot(toPoint) > 0.25
end
local function isPointBehind(self, point)
local toPoint = (point - thisEntity:GetAbsOrigin()):Normalized()
local forward = thisEntity:GetForwardVector()
return forward:Dot(toPoint) < -0.25
end
local function issueCastPosition(self, ability, position)
local now = GameRules:GetGameTime()
if now - lastOrderGameTime < 0.15 then
return false
end
ExecuteOrderFromTable({
UnitIndex = thisEntity:entindex(),
OrderType = DOTA_UNIT_ORDER_CAST_POSITION,
AbilityIndex = ability:entindex(),
Position = position,
Queue = false
})
lastOrderGameTime = now
return true
end
local function issueCastNoTarget(self, ability)
local now = GameRules:GetGameTime()
if now - lastOrderGameTime < 0.15 then
return false
end
ExecuteOrderFromTable({
UnitIndex = thisEntity:entindex(),
OrderType = DOTA_UNIT_ORDER_CAST_NO_TARGET,
AbilityIndex = ability:entindex(),
Queue = false
})
lastOrderGameTime = now
return true
end
local function issueMove(self, target)
local now = GameRules:GetGameTime()
if now - lastOrderGameTime < 0.25 then
return
end
if not target or target:IsNull() or not target:IsAlive() then
return
end
local targetPosition = target:GetAbsOrigin()
ExecuteOrderFromTable({
UnitIndex = thisEntity:entindex(),
OrderType = DOTA_UNIT_ORDER_MOVE_TO_POSITION,
Position = targetPosition,
Queue = false
})
lastOrderGameTime = now
end
local function issueAttackTarget(self, target)
local now = GameRules:GetGameTime()
if now - lastOrderGameTime < 0.25 then
return
end
if not target or target:IsNull() or not target:IsAlive() then
return
end
local targetIndex = target:entindex()
if targetIndex == nil or targetIndex < 0 then
return
end
if lastAttackTargetIndex == targetIndex and now - lastAttackOrderGameTime < 1 then
return
end
ExecuteOrderFromTable({
UnitIndex = thisEntity:entindex(),
OrderType = DOTA_UNIT_ORDER_ATTACK_TARGET,
TargetIndex = targetIndex,
Queue = false
})
lastOrderGameTime = now
lastAttackOrderGameTime = now
lastAttackTargetIndex = targetIndex
end
local function areAllAbilitiesOnCooldown(self)
if not abilityGrab or not abilityFear or not abilityBackStun or not abilityFaceStun then
return false
end
return abilityGrab:GetCooldownTimeRemaining() > 0 and abilityFear:GetCooldownTimeRemaining() > 0 and abilityBackStun:GetCooldownTimeRemaining() > 0 and abilityFaceStun:GetCooldownTimeRemaining() > 0
end
local function findStunnedEnemyPoint(self)
local enemies = FindUnitsInRadius(
thisEntity:GetTeamNumber(),
thisEntity:GetAbsOrigin(),
nil,
BACK_CAST_RANGE,
DOTA_UNIT_TARGET_TEAM_ENEMY,
bit.bor(DOTA_UNIT_TARGET_HERO, DOTA_UNIT_TARGET_BASIC),
DOTA_UNIT_TARGET_FLAG_FOW_VISIBLE,
FIND_CLOSEST,
false
)
for ____, enemy in ipairs(enemies) do
do
if not enemy or enemy:IsNull() or not enemy:IsAlive() then
goto __continue28
end
if enemy:HasModifier("modifier_face_stunned") or enemy:HasModifier("modifier_back_stunned") then
return enemy:GetAbsOrigin()
end
end
::__continue28::
end
return nil
end
local function tryChainStunAtPoint(self, point)
local distance = getDistance2D(
nil,
thisEntity:GetAbsOrigin(),
point
)
if abilityFaceStun and not abilityFaceStun:IsNull() and abilityFaceStun:IsFullyCastable() and distance <= FACE_CAST_RANGE then
thisEntity:FaceTowards(point)
return issueCastPosition(nil, abilityFaceStun, point)
end
if abilityBackStun and not abilityBackStun:IsNull() and abilityBackStun:IsFullyCastable() and distance <= BACK_CAST_RANGE then
local casterOrigin = thisEntity:GetAbsOrigin()
local faceAwayPoint = casterOrigin:__mul(2):__sub(point)
thisEntity:FaceTowards(faceAwayPoint)
return issueCastNoTarget(nil, abilityBackStun)
end
return false
end
local function tryCastFear(self)
if not abilityFear or abilityFear:IsNull() or not abilityFear:IsFullyCastable() then
return false
end
local enemies = FindUnitsInRadius(
thisEntity:GetTeamNumber(),
thisEntity:GetAbsOrigin(),
nil,
FEAR_CAST_RADIUS,
DOTA_UNIT_TARGET_TEAM_ENEMY,
bit.bor(DOTA_UNIT_TARGET_HERO, DOTA_UNIT_TARGET_BASIC),
DOTA_UNIT_TARGET_FLAG_NONE,
FIND_ANY_ORDER,
false
)
if #enemies < 2 then
return false
end
return issueCastNoTarget(nil, abilityFear)
end
local function tryCastGrab(self, target, distance)
if not abilityGrab or abilityGrab:IsNull() or not abilityGrab:IsFullyCastable() then
return false
end
if distance > GRAB_CAST_RANGE then
return false
end
return issueCastPosition(
nil,
abilityGrab,
target:GetAbsOrigin()
)
end
local function tryCastFaceStun(self, target, distance)
if not abilityFaceStun or abilityFaceStun:IsNull() or not abilityFaceStun:IsFullyCastable() then
return false
end
if distance > FACE_CAST_RANGE or not isTargetInFront(nil, target) then
return false
end
return issueCastPosition(
nil,
abilityFaceStun,
target:GetAbsOrigin()
)
end
local function tryCastBackStun(self, target, distance)
if not abilityBackStun or abilityBackStun:IsNull() or not abilityBackStun:IsFullyCastable() then
return false
end
if distance > BACK_CAST_RANGE or not isTargetBehind(nil, target) then
return false
end
return issueCastNoTarget(nil, abilityBackStun)
end
local function DemonDragonSatyrThink(self)
if not IsServer() or not thisEntity or thisEntity:IsNull() or not thisEntity:IsAlive() then
return THINK_INTERVAL
end
if GameRules:IsGamePaused() or thisEntity:IsChanneling() then
return THINK_INTERVAL
end
if not abilityGrab or not abilityFear or not abilityBackStun or not abilityFaceStun then
refreshAbilities(nil)
end
local target = findClosestEnemy(nil)
if not target then
return THINK_INTERVAL
end
local distance = getDistance2D(
nil,
thisEntity:GetAbsOrigin(),
target:GetAbsOrigin()
)
local stunnedEnemyPoint = findStunnedEnemyPoint(nil)
if stunnedEnemyPoint then
if tryChainStunAtPoint(nil, stunnedEnemyPoint) then
return THINK_INTERVAL
end
if isPointInFront(nil, stunnedEnemyPoint) and tryCastFaceStun(nil, target, distance) then
return THINK_INTERVAL
end
if isPointBehind(nil, stunnedEnemyPoint) and tryCastBackStun(nil, target, distance) then
return THINK_INTERVAL
end
end
if tryCastFear(nil) then
return THINK_INTERVAL
end
if tryCastGrab(nil, target, distance) then
return THINK_INTERVAL
end
if tryCastFaceStun(nil, target, distance) then
return THINK_INTERVAL
end
if tryCastBackStun(nil, target, distance) then
return THINK_INTERVAL
end
if areAllAbilitiesOnCooldown(nil) then
issueAttackTarget(nil, target)
return THINK_INTERVAL
end
issueMove(nil, target)
return THINK_INTERVAL
end
registerEntityFunction(
nil,
"Spawn",
function()
if not IsServer() or not thisEntity or thisEntity:IsNull() then
return
end
refreshAbilities(nil)
thisEntity:SetContextThink("DemonDragonSatyrThink", DemonDragonSatyrThink, THINK_INTERVAL)
end
)
return ____exports