library GetShortestPathUnit requires optional IsPointReachable//Duckfarter
/* Configuration:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯ */
globals
private constant integer TRANSMITTER = 'nipt'
private constant integer RECIEVER = 'nipr'
private constant integer C1 = 'Aipt'
private constant integer C2 = 'Aipr'
/* Reciever amount. 4 low, 8 medium, 12 high, 16 very high */
private constant integer RA = 4
/* Closest distance. I dont recommend changing this */
private constant real DC = 16
endglobals
/*
GetShortestPathUnit 1.0
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Description:
¯¯¯¯¯¯¯¯¯¯¯¯
This library takes advantage of some of Wc3's own pathfinding from the ability Call to Arms
to detect the shortest path unit in a group from xy co-ordinates which has two limitations:
1. Can only detect the shortest path unit for ground units with less than 32 collision size
2. Has limited "range" to find each shortest path unit
NOTE: Requires xy co-ordinates to have terrain walkability
API:
¯¯¯¯
| function GetShortestPathUnit takes group g, real x, real y returns unit
How to import:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯
1. Copy abilities Call to Arms (Transmitter) ID: Aipt, and Call To Arms (Reciever) ID: Aipr
2. Copy units Transmitter (1) ID: nipt, and Reciever (2) ID: nipr
3. Copy trigger GetClosestPathUnit
Link:
¯¯¯¯¯
*/
globals
private unit uT
private unit array uR
private unit array uF
private unit uC
private unit uSP
private integer i
private integer j
private integer gSize
private real xF
private real yF
private real d
private real dC
private boolean array disabled
private group swap = CreateGroup()
endglobals
private function FilterShortestPathUnit takes real x, real y returns unit
set uC = null
set i = 1
loop
exitwhen uF[i] == null
set xF = GetUnitX(uF[i])
set yF = GetUnitY(uF[i])
//Stops false negatives with ~ equal XY
set d = SquareRoot((xF-x)*(xF-x) + (yF-y)*(yF-y))
if d <= dC then
set dC = d
set uC = uF[i]
elseif dC == DC then
call SetUnitX(uR[i], xF)
call SetUnitY(uR[i], yF)
endif
set i = i + 1
endloop
set i = i - 1
//If a shortest path unit exists within 16 range it skips the Call to Arms check
if dC < DC then
if uC != null then
set gSize = gSize + 1
endif
return uC
endif
//Disables Reciever abilities when gSize < DA
set j = RA
loop
exitwhen i >= j
if disabled[j] == false then
set disabled[j] = true
call BlzUnitDisableAbility(uR[j], C2, true, false)
set uF[j] = null
endif
set j = j - 1
endloop
//Initiate Call to Arms check
call IssueImmediateOrderById(uT, 852072)
//Initial check to see if there is a shortest path unit in the batch
if GetUnitCurrentOrder(uT) == 0 then
return null
endif
//Unhides and hides Recievers to interrupt the Call to Arms order
set j = 1
loop
exitwhen j > i
call ShowUnit(uR[j], true)
call ShowUnit(uR[j], false)
if GetUnitCurrentOrder(uT) == 0 then
set gSize = gSize + 1
return uF[j]
endif
set j = j + 1
endloop
return null
endfunction
function GetShortestPathUnit takes group g, real x, real y returns unit
//Aborts if gSize is 0
set gSize = BlzGroupAddGroupFast(g, swap)
if gSize == 0 then
return null
endif
set dC = DC
set uSP = null
call SetUnitX(uT, x)
call SetUnitY(uT, y)
//Enables abilities
call BlzUnitDisableAbility(uT, C1, false, false)
call BlzUnitDisableAbility(uT, 'Amov', false, false)
set i = 1
loop
exitwhen i > RA or i > gSize
set disabled[i] = false
call BlzUnitDisableAbility(uR[i], C2, false, false)
set i = i + 1
endloop
//Loops through g in batches of DA to find the shortest path unit
set i = 1
loop
exitwhen gSize == 0
set uF[i] = FirstOfGroup(swap)
call GroupRemoveUnit(swap, uF[i])
set gSize = gSize - 1
if i == RA or gSize == 0 then
set uSP = FilterShortestPathUnit(x, y)
call GroupAddUnit(swap, uSP)
exitwhen gSize == 1 and uSP != null
set i = 0
endif
set i = i + 1
endloop
call GroupRemoveUnit(swap, uSP)
set uC = null
//Disables abilities
call BlzUnitDisableAbility(uT, C1, true, false)
call BlzUnitDisableAbility(uT, 'Amov', true, false)
set i = 1
loop
exitwhen i > RA
if disabled[i] == false then
set disabled[i] = true
call BlzUnitDisableAbility(uR[i], C2, true, false)
set uF[i] = null
endif
set i = i + 1
endloop
return uSP
endfunction
//For future use
function GetRecieverAmount takes nothing returns integer
return RA
endfunction
function GetRecieverUnitByIndex takes integer i returns unit
return uR[i]
endfunction
private module Init
private static method onInit takes nothing returns nothing
call init()
endmethod
endmodule
private struct InitStruct extends array
private static method init takes nothing returns nothing
static if LIBRARY_IsPointReachable then
set uT = GetTransmitterUnit()
set uR[1] = GetRecieverUnit()
set disabled[1] = true
set i = 2
else
set uT = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), TRANSMITTER, 0, 0, 0)
call BlzUnitDisableAbility(uT, C1, true, false)
call BlzUnitDisableAbility(uT, 'Amov', true, false)
call ShowUnit(uT, false)
set i = 1
endif
loop
exitwhen i > RA
set uR[i] = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), RECIEVER, 0, 0, 0)
set disabled[i] = true
call BlzUnitDisableAbility(uR[i], C2, true, false)
call ShowUnit(uR[i], false)
set i = i + 1
endloop
endmethod
implement Init
endstruct
endlibrary