//*************************************************************************************
//*
//* Escort by Almia
//*
//*************************************************************************************
//*
//* Artificial Intelligence System Member
//*
//* Allows you to apply an escort to a unit. The system is mainly created
//* for summoned AI units. You can use non-summon units if you want(esp. custom
//* summon spells such as with the action Create Unit)
//*
//*************************************************************************************
//*
//* API
//*
//* function AddEscort takes unit s, unit m returns nothing
//* s = summon : summoned unit
//* m = master : summoning unit
//* - applies "s" as an escort of "m"
//* - can also work on other units not just summons.
//*
//*************************************************************************************
//*
//* Credits
//*
//* mckill2009 - SummonedEscort, the code where the system was based on.
//* - I converted this to JASS and also optimized some parts of it.
//*
//* Sylvenon - GetClosestUnit snippet
//*
//* Bribe - Unit Indexer
//*
//* spasorc and Magtheridon96 - bug and minor mistakes
//*
//*************************************************************************************
//*
//* GetClosestUnit
//* - retrieves the closest unit from a coordinate.
//*
//*************************************************************************************
function GetClosestUnit takes real x, real y, boolexpr e returns unit
local real md = 100000
local real d
local group g = CreateGroup()
local unit u
local real dx
local real dy
call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, e)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
set dx = GetUnitX(u) - x
set dy = GetUnitY(u) - y
if (dx * dx + dy * dy) / 100000 < md then
set udg_ClosestUnit = u
set md = (dx * dx + dy * dy) / 100000
endif
endloop
call DestroyGroup(g)
call DestroyBoolExpr(e)
set g = null
return udg_ClosestUnit
endfunction
//*************************************************************************************
//*
//* GetClosestUnitInRange
//* - retrieves the closest unit from a coordinate in a given radius/range.
//*
//*************************************************************************************
function GetClosestUnitInRange takes real x, real y, real range, boolexpr e returns unit
local real md = 100000
local real d
local group g = CreateGroup()
local unit u
local real dx
local real dy
local real r
call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, e)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g, u)
set dx = GetUnitX(u) - x
set dy = GetUnitY(u) - y
set r = (dx * dx + dy * dy)
if r / 100000 < md and r < range * range then
set udg_ClosestUnit = u
set md = (dx * dx + dy * dy) / 100000
endif
endloop
call DestroyGroup(g)
call DestroyBoolExpr(e)
set g = null
return udg_ClosestUnit
endfunction
//*************************************************************************************
//*
//* SETTINGS
//*
//*************************************************************************************
//*
//* Escort Periodic Interval value
//*
//*************************************************************************************
constant function EscortInterval takes nothing returns real
return 1.
endfunction
//*************************************************************************************
//*
//* Escort Auto Run
//* - if true, automatically applies summoned units as an escort.
//*
//*************************************************************************************
constant function EscortAutoRun takes nothing returns boolean
return true
endfunction
//*************************************************************************************
//*
//* Escort Search New Owner
//* - if true, summoned unit who lost its master searches a new owner.
//*
//*************************************************************************************
constant function EscortSearchNewOwner takes nothing returns boolean
return true
endfunction
//*************************************************************************************
//*
//* Escort Allow Ally Player
//* - if true, summoned units will find the nearest ally unit owned by an ally
//* player or the player that owns it.
//*
//*************************************************************************************
constant function EscortAllowAllyPlayer takes nothing returns boolean
return false
endfunction
//*************************************************************************************
//*
//* Escort Follow Hero
//* - if true, summoned units will find the nearest ally unit owned by an ally
//* player or the player that owns it that must be a hero.
//*
//*************************************************************************************
constant function EscortFollowHero takes nothing returns boolean
return true
endfunction
//*************************************************************************************
//*
//* Escort Follow Structures
//* - if true, summoned units will find the nearest ally unit owned by an ally
//* player or the player that owns it that must be a structure.
//*
//*************************************************************************************
constant function EscortFollowStructures takes nothing returns boolean
return false
endfunction
//*************************************************************************************
//*
//* Escort Offset
//* - distance of the escort from its master(max). Doesn't affect the summons if
//* it has a current order such as attacking.
//*
//*************************************************************************************
constant function EscortOffset takes nothing returns real
return 200.0
endfunction
//*************************************************************************************
//*
//* Escort Closest Ally
//* - maximum distance where the summons will search their new owner. Depends on
//* the boolean EscortSearchNewOwner.
//*
//*************************************************************************************
constant function EscortClosestAlly takes nothing returns real
return 400.0
endfunction
//*************************************************************************************
//*
//* Escort Closest Enemy
//* - range of the escort where it will acquire a target.
//*
//*************************************************************************************
constant function EscortClosestEnemy takes nothing returns real
return 600.0
endfunction
//*************************************************************************************
//*
//* Alive Filter
//*
//*************************************************************************************
function EscortAliveFilter takes unit u returns boolean
return not (GetUnitTypeId(u) == 0 and null == u and IsUnitType(u, UNIT_TYPE_DEAD))
endfunction
//*************************************************************************************
//*
//* Escort Ally Filter
//*
//*************************************************************************************
function EscortAllyFilter takes nothing returns boolean
local boolean b
local boolean b2
set udg_Escort_TempU = GetFilterUnit()
set b = EscortAliveFilter(udg_Escort_TempU) and udg_Escort_TempU != udg_Escort_Summon[udg_Escort_Data] and GetUnitMoveSpeed(udg_Escort_TempU) > 0
set b2 = IsUnitType(udg_Escort_TempU, UNIT_TYPE_STRUCTURE)
if EscortFollowStructures() then
set b = b and b2
else
set b = b and not b2
endif
if EscortFollowHero() and not b2 then
set b = b and IsUnitType(udg_Escort_TempU, UNIT_TYPE_HERO)
endif
if EscortAllowAllyPlayer() then
return b and IsUnitAlly(udg_Escort_TempU, udg_Escort_Player[udg_Escort_Data])
else
return b and udg_Escort_Player[udg_Escort_Data] == GetOwningPlayer(udg_Escort_TempU)
endif
endfunction
//*************************************************************************************
//*
//* Escort Enemy Filter
//*
//*************************************************************************************
function EscortEnemyFilter takes nothing returns boolean
set udg_Escort_TempU = GetFilterUnit()
return IsUnitEnemy(udg_Escort_TempU, udg_Escort_Player[udg_Escort_Data]) and EscortAliveFilter(udg_Escort_TempU)
endfunction
//*************************************************************************************
//*
//* Escort Loop
//*
//*************************************************************************************
function EscortLoop takes nothing returns nothing
local unit t
local integer order
local real a
local real mx
local real my
local real sx
local real sy
set udg_Escort_Data = udg_Escort_N[0]
loop
exitwhen 0 == udg_Escort_Data
if EscortAliveFilter(udg_Escort_Summon[udg_Escort_Data]) then
// Random attack offset.
set a = GetRandomReal(0, 6.28318)
set order = GetUnitCurrentOrder(udg_Escort_Summon[udg_Escort_Data])
if EscortAliveFilter(udg_Escort_Master[udg_Escort_Data]) then
if 0 == order then
// Acquire new attack offset
set mx = GetUnitX(udg_Escort_Master[udg_Escort_Data]) + EscortOffset() * Cos(a)
set my = GetUnitY(udg_Escort_Master[udg_Escort_Data]) + EscortOffset() * Sin(a)
// Order summon to attack the acquired offset
call IssuePointOrderById(udg_Escort_Summon[udg_Escort_Data], 851983, mx, my)
// Get nearest unit and set it as its target.
set t = GetClosestUnitInRange(mx, my, EscortClosestEnemy(), Filter(function EscortEnemyFilter))
if null != t then
if IsUnitType(t,UNIT_TYPE_SLEEPING) then
// if unit is sleeping, attack target.
call IssueTargetOrderById(udg_Escort_Summon[udg_Escort_Data], 851983, t)
else
// attack-move to the target.
call IssuePointOrderById(udg_Escort_Summon[udg_Escort_Data], 851983, GetUnitX(t), GetUnitY(t))
endif
set t = null
endif
endif
else
// if master is dead, acquire new master.
set sx = GetUnitX(udg_Escort_Summon[udg_Escort_Data])
set sy = GetUnitY(udg_Escort_Summon[udg_Escort_Data])
if EscortSearchNewOwner() then
set udg_Escort_Master[udg_Escort_Data] = GetClosestUnitInRange(sx, sy, EscortClosestAlly(), Filter(function EscortAllyFilter))
else
set udg_Escort_Master[udg_Escort_Data] = GetClosestUnit(sx, sy, Filter(function EscortAllyFilter))
endif
// if alive and no orders, attack-move to the new master's position.
if null != udg_Escort_Master[udg_Escort_Data] and 0 == order then
call IssuePointOrderById(udg_Escort_Summon[udg_Escort_Data], 851983, udg_Escort_UnitX[udg_Escort_Data] + EscortOffset() * Cos(a), udg_Escort_UnitY[udg_Escort_Data] + EscortOffset() * Sin(a))
endif
endif
else
set udg_Escort_N[udg_Escort_P[udg_Escort_Data]] = udg_Escort_N[udg_Escort_Data]
set udg_Escort_P[udg_Escort_N[udg_Escort_Data]] = udg_Escort_P[udg_Escort_Data]
// Move last indexed variables to the to-be-allocated index.
set udg_Escort_Summon[udg_Escort_Data] = null
set udg_Escort_Master[udg_Escort_Data] = null
set udg_Escort_UnitX[udg_Escort_Data] = 0
set udg_Escort_UnitY[udg_Escort_Data] = 0
set udg_Escort_Player[udg_Escort_Data] = null
// Decrement count
set udg_Escort_Count = udg_Escort_Count - 1
// Pause if count is equal to 0
if 0 == udg_Escort_Count then
call PauseTimer(udg_EscortTimer)
endif
endif
set udg_Escort_Data = udg_Escort_N[udg_Escort_Data]
endloop
endfunction
//*************************************************************************************
//*
//* Add Escort
//*
//*************************************************************************************
function AddEscort takes unit s, unit m returns nothing
local integer i = GetUnitUserData(s)
set udg_Escort_Master[i] = m
set udg_Escort_UnitX[i] = GetUnitX(m)
set udg_Escort_UnitY[i] = GetUnitY(m)
set udg_Escort_Player[i] = GetOwningPlayer(s)
if not udg_Escort_IsInLoop[i] then
set udg_Escort_Summon[i] = s
set udg_Escort_N[i] = 0
set udg_Escort_P[i] = 0
set udg_Escort_N[udg_Escort_P[0]] = i
set udg_Escort_P[0] = i
set udg_Escort_Count = udg_Escort_Count + 1
if 1 == udg_Escort_Count then
call TimerStart(udg_EscortTimer, EscortInterval(), true, function EscortLoop)
endif
call RemoveGuardPosition(s)
endif
endfunction
//*************************************************************************************
//*
//* Escort Run Auto-Add Escort
//*
//*************************************************************************************
function EscortRun takes nothing returns boolean
call AddEscort(GetSummonedUnit(), GetSummoningUnit())
return false
endfunction
//*************************************************************************************
//*
//* Escort Init
//*
//*************************************************************************************
function EscortInit takes nothing returns nothing
local trigger t
set udg_EscortTimer = CreateTimer()
if EscortAutoRun() then
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SUMMON)
call TriggerAddCondition(t, Condition(function EscortRun))
set t = null
endif
endfunction