Sgqvur
FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi
- Reaction score
- 62
Okay so what exactly is [ljass]TriggerRegisterUnitOutOfRange[/ljass], you may ask... well it's this:
[ljass] function TriggerRegisterUnitOutOfRange takes trigger t, unit u, real range returns r17field[/ljass]
i.e the "opposite" of:
[ljass] native TriggerRegisterUnitInRange takes trigger whichTrigger, unit whichUnit, real range, boolexpr filter returns event[/ljass]
they almost look the same except for the boolexpr and that r17filed thing... What is that you say [you don't =)?]? Heh...
Well it's simple an approximation (did I spell that right?) of a circle using 17 rectangles (r[ECTANGLE]17field).
Is it any good? Well I think the 17 rects approximate a circle with minor margin of error for ranges of up to 3000.
So basically what happens is that [ljass]TriggerRegisterUnitInRange[/ljass] attaches a circle to the unit
which listens for entering units and [ljass]TriggerRegisterUnitOutOfRange[/ljass] attaches a "circle" which listens for leaving units.
For what things can this be used? Well I am thinking of it as a "proper" projectile2projectile collision detector, having a square around your circle
of radius R is not that great you know...
But it can also be used for other things "efficiently" as the example I hope will demonstrate.
The snippet:
The example/demo:
[ljass] function TriggerRegisterUnitOutOfRange takes trigger t, unit u, real range returns r17field[/ljass]
i.e the "opposite" of:
[ljass] native TriggerRegisterUnitInRange takes trigger whichTrigger, unit whichUnit, real range, boolexpr filter returns event[/ljass]
they almost look the same except for the boolexpr and that r17filed thing... What is that you say [you don't =)?]? Heh...
Well it's simple an approximation (did I spell that right?) of a circle using 17 rectangles (r[ECTANGLE]17field).
Is it any good? Well I think the 17 rects approximate a circle with minor margin of error for ranges of up to 3000.
So basically what happens is that [ljass]TriggerRegisterUnitInRange[/ljass] attaches a circle to the unit
which listens for entering units and [ljass]TriggerRegisterUnitOutOfRange[/ljass] attaches a "circle" which listens for leaving units.
For what things can this be used? Well I am thinking of it as a "proper" projectile2projectile collision detector, having a square around your circle
of radius R is not that great you know...
But it can also be used for other things "efficiently" as the example I hope will demonstrate.
The snippet:
JASS:
library r17field initializer init requires optional TimerUtils
globals
private hashtable HT
private constant real TIMEX = 1.0 / 32.0
endglobals
private function dummy_field_loop takes nothing returns nothing
local r17field r17f
static if LIBRARY_TimerUtils then
set r17f = GetTimerData(GetExpiredTimer())
else
set r17f = LoadInteger(HT, GetHandleId(GetExpiredTimer()), 039;TROR039;)
endif
call r17f.field_loop()
endfunction
struct r17field
unit particle
rect r0
rect r1
rect r2
rect r3
rect r4
rect r5
rect r6
rect r7
rect r8
rect r9
rect r10
rect r11
rect r12
rect r13
rect r14
rect r15
rect r16
region field
real radius
// trigger enter_field_trigger
trigger leave_field_trigger
timer atomic_timer
method setup takes unit for_which_particle, real field_radius returns nothing
set particle = for_which_particle
set radius = field_radius
// set enter_field_trigger = CreateTrigger()
// set leave_field_trigger = CreateTrigger()
set r0 = Rect(0, 0, 0, 0)
set r1 = Rect(0, 0, 0, 0)
set r2 = Rect(0, 0, 0, 0)
set r3 = Rect(0, 0, 0, 0)
set r4 = Rect(0, 0, 0, 0)
set r5 = Rect(0, 0, 0, 0)
set r6 = Rect(0, 0, 0, 0)
set r7 = Rect(0, 0, 0, 0)
set r8 = Rect(0, 0, 0, 0)
set r9 = Rect(0, 0, 0, 0)
set r10 = Rect(0, 0, 0, 0)
set r12 = Rect(0, 0, 0, 0)
set r13 = Rect(0, 0, 0, 0)
set r14 = Rect(0, 0, 0, 0)
set r15 = Rect(0, 0, 0, 0)
set r16 = Rect(0, 0, 0, 0)
set field = CreateRegion()
call TriggerRegisterLeaveRegion(leave_field_trigger, field, null)
static if LIBRARY_TimerUtils then
set atomic_timer = NewTimer()
call SetTimerData(atomic_timer, this)
else
set atomic_timer = CreateTimer()
call SaveInteger(HT, GetHandleId(atomic_timer), 039;TROR039;, this)
endif
call TimerStart(atomic_timer, TIMEX, true, function dummy_field_loop)
endmethod
method field_loop takes nothing returns nothing
local real width = radius * 4.0 / 3.0
local real hw = width / 2.0
local real cx = GetUnitX(particle)
local real cy = GetUnitY(particle)
local real r0_minx = cx - hw
local real r0_miny = cy - hw
local real r0_maxx = cx + hw
local real r0_maxy = cy + hw
local real r1_minx = r0_minx + width * 0.15
local real r1_miny = r0_miny - width * 0.15
local real r1_maxx = r0_maxx - width * 0.15
local real r1_maxy = r0_miny
local real r2_minx = r1_minx
local real r2_miny = r0_maxy
local real r2_maxx = r1_maxx
local real r2_maxy = r0_maxy + width * 0.15
local real r3_minx = r0_minx - width * 0.15
local real r3_miny = r0_miny + width * 0.15
local real r3_maxx = r0_minx
local real r3_maxy = r0_maxy - width * 0.15
local real r4_minx = r0_maxx
local real r4_miny = r3_miny
local real r4_maxx = r4_minx + width * 0.15
local real r4_maxy = r3_maxy
local real r5_minx = r0_minx + width * 0.3
local real r5_miny = r0_miny - width * 0.225
local real r5_maxx = r0_maxx - width * 0.3
local real r5_maxy = r1_miny
local real r6_minx = r5_minx
local real r6_miny = r2_maxy
local real r6_maxx = r5_maxx
local real r6_maxy = r0_maxy + width * 0.225
local real r7_minx = r0_minx - width * 0.225
local real r7_miny = r0_miny + width * 0.3
local real r7_maxx = r3_minx
local real r7_maxy = r0_maxy - width * 0.3
local real r8_minx = r4_maxx
local real r8_miny = r7_miny
local real r8_maxx = r0_maxx + width * 0.225
local real r8_maxy = r7_maxy
local real r9_minx = r1_minx - width * 0.10
local real r9_miny = r0_miny - width * 0.10
local real r9_maxx = r1_minx
local real r9_maxy = r0_miny
local real r10_minx = r0_minx - width * 0.10
local real r10_miny = r3_miny - width * 0.10
local real r10_maxx = r0_minx
local real r10_maxy = r3_miny
local real r11_minx = r1_maxx
local real r11_miny = r9_miny
local real r11_maxx = r11_minx + width * 0.10
local real r11_maxy = r9_maxy
local real r12_minx = r0_maxx
local real r12_miny = r10_miny
local real r12_maxx = r12_minx + width * 0.10
local real r12_maxy = r10_maxy
local real r13_minx = r10_minx
local real r13_miny = r3_maxy
local real r13_maxx = r10_maxx
local real r13_maxy = r13_miny + width * 0.10
local real r14_minx = r9_minx
local real r14_miny = r0_maxy
local real r14_maxx = r9_maxx
local real r14_maxy = r14_miny + width * 0.10
local real r15_minx = r12_minx
local real r15_miny = r13_miny
local real r15_maxx = r12_maxx
local real r15_maxy = r13_maxy
local real r16_minx = r11_minx
local real r16_miny = r14_miny
local real r16_maxx = r11_maxx
local real r16_maxy = r14_maxy
call RegionClearRect(field, r0)
call RegionClearRect(field, r1)
call RegionClearRect(field, r2)
call RegionClearRect(field, r3)
call RegionClearRect(field, r4)
call RegionClearRect(field, r5)
call RegionClearRect(field, r6)
call RegionClearRect(field, r7)
call RegionClearRect(field, r8)
call RegionClearRect(field, r9)
call RegionClearRect(field, r10)
call RegionClearRect(field, r11)
call RegionClearRect(field, r12)
call RegionClearRect(field, r13)
call RegionClearRect(field, r14)
call RegionClearRect(field, r15)
call RegionClearRect(field, r16)
call SetRect(r0, r0_minx, r0_miny, r0_maxx, r0_maxy)
call SetRect(r1, r1_minx, r1_miny, r1_maxx, r1_maxy)
call SetRect(r2, r2_minx, r2_miny, r2_maxx, r2_maxy)
call SetRect(r3, r3_minx, r3_miny, r3_maxx, r3_maxy)
call SetRect(r4, r4_minx, r4_miny, r4_maxx, r4_maxy)
call SetRect(r5, r5_minx, r5_miny, r5_maxx, r5_maxy)
call SetRect(r6, r6_minx, r6_miny, r6_maxx, r6_maxy)
call SetRect(r7, r7_minx, r7_miny, r7_maxx, r7_maxy)
call SetRect(r8, r8_minx, r8_miny, r8_maxx, r8_maxy)
call SetRect(r9, r9_minx, r9_miny, r9_maxx, r9_maxy)
call SetRect(r10, r10_minx, r10_miny, r10_maxx, r10_maxy)
call SetRect(r11, r11_minx, r11_miny, r11_maxx, r11_maxy)
call SetRect(r12, r12_minx, r12_miny, r12_maxx, r12_maxy)
call SetRect(r13, r13_minx, r13_miny, r13_maxx, r13_maxy)
call SetRect(r14, r14_minx, r14_miny, r14_maxx, r14_maxy)
call SetRect(r15, r15_minx, r15_miny, r15_maxx, r15_maxy)
call SetRect(r16, r16_minx, r16_miny, r16_maxx, r16_maxy)
call RegionAddRect(field, r0)
call RegionAddRect(field, r1)
call RegionAddRect(field, r2)
call RegionAddRect(field, r3)
call RegionAddRect(field, r4)
call RegionAddRect(field, r5)
call RegionAddRect(field, r6)
call RegionAddRect(field, r7)
call RegionAddRect(field, r8)
call RegionAddRect(field, r9)
call RegionAddRect(field, r10)
call RegionAddRect(field, r11)
call RegionAddRect(field, r12)
call RegionAddRect(field, r13)
call RegionAddRect(field, r14)
call RegionAddRect(field, r15)
call RegionAddRect(field, r16)
endmethod
method stop takes nothing returns nothing
call RemoveRect(r0)
call RemoveRect(r1)
call RemoveRect(r2)
call RemoveRect(r3)
call RemoveRect(r4)
call RemoveRect(r5)
call RemoveRect(r6)
call RemoveRect(r7)
call RemoveRect(r8)
call RemoveRect(r9)
call RemoveRect(r10)
call RemoveRect(r11)
call RemoveRect(r12)
call RemoveRect(r13)
call RemoveRect(r14)
call RemoveRect(r15)
call RemoveRect(r16)
call RemoveRegion(field)
call DisableTrigger(leave_field_trigger)
call TriggerClearConditions(leave_field_trigger)
call DestroyTrigger(leave_field_trigger)
static if LIBRARY_TimerUtils then
call ReleaseTimer(atomic_timer)
else
call PauseTimer(atomic_timer)
call DestroyTimer(atomic_timer)
endif
endmethod
endstruct
private function init takes nothing returns nothing
static if LIBRARY_TimerUtils then
// do nothing
else
set HT = InitHashtable()
endif
endfunction
function TriggerRegisterUnitOutOfRange takes trigger t, unit u, real range returns r17field
local r17field r17f = r17field.create()
set r17f.leave_field_trigger = t
call r17f.setup(u, range)
return r17f
endfunction
endlibrary
The example/demo:
JASS:
// Daura - Dummy aura
// Notes: has some "nostalgic" handle vars bits (okay... maybe bytes) =)
//
scope Daura initializer init
globals
private hashtable HT = InitHashtable()
private constant integer ABIL_ID = 039;A000039;
private constant integer BUFF_ID = 039;dabf039; // "extends" 'Aasl'
private constant string EFFECT = "Abilities\\Spells\\Other\\GeneralAuraTarget\\GeneralAuraTarget.mdl"
private constant string ATTACH_POINT = "origin"
private constant string SOURCE_EFFECT = "Abilities\\Spells\\Human\\Brilliance\\Brilliance.mdl"
private constant string SOURCE_EFFECT_AP = "origin"
private constant real CLEAN_UP_PERIOD = 0.5
private group tmpg = CreateGroup()
private group tmpg2 = null
private unit tmpu = null
endglobals
private function AoE takes integer lvl returns real
return 600.0 + lvl * 100.0
endfunction
private function targets_allowed takes unit u returns boolean
return true
endfunction
private function daura_do_for_unit takes unit u returns nothing
call UnitAddAbility(u, BUFF_ID)
call SaveEffectHandle(HT, GetHandleId(u), StringHash("daura_effect"), /*
*/ AddSpecialEffectTarget(EFFECT, u, ATTACH_POINT))
call GroupAddUnit(tmpg2, u)
call SaveInteger(HT, GetHandleId(u), StringHash("already_under_daura"), 1)
endfunction
private function daura_do takes nothing returns boolean
local unit u = GetTriggerUnit()
if not targets_allowed(u) or LoadInteger(HT, GetHandleId(u), StringHash("already_under_daura")) == 1 then
return false
endif
set tmpg2 = LoadGroupHandle(HT, GetHandleId(GetTriggeringTrigger()), StringHash("clean_up_group"))
call daura_do_for_unit(u)
// could imagine all kind of attribute manipulation with some library but nah...
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetUnitName(u) + " is within range")
set u = null
return false
endfunction
private function daura_undo_for_unit takes unit u returns nothing
call UnitRemoveAbility(u, BUFF_ID)
call DestroyEffect(LoadEffectHandle(HT, GetHandleId(u), StringHash("daura_effect")))
call GroupRemoveUnit(tmpg2, u)
call SaveInteger(HT, GetHandleId(u), StringHash("already_under_daura"), 0)
endfunction
private function daura_undo takes nothing returns boolean
local unit u = GetTriggerUnit()
if not targets_allowed(u) or LoadInteger(HT, GetHandleId(u), StringHash("already_under_daura")) == 0 then
return false
endif
set tmpg2 = LoadGroupHandle(HT, GetHandleId(GetTriggeringTrigger()), StringHash("clean_up_group"))
call daura_undo_for_unit(u)
// if attribute manipulation did take place we reverse their effect here but nah... =)
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetUnitName(u) + " is out of range")
set u = null
return false
endfunction
private function daura_clean_up takes nothing returns nothing
local timer t = GetExpiredTimer()
local group g = LoadGroupHandle(HT, GetHandleId(t), StringHash("clean_up_group"))
local unit source = LoadUnitHandle(HT, GetHandleId(t), StringHash("source"))
local real radius = AoE(GetUnitAbilityLevel(source, ABIL_ID))
local group swap = null
set tmpu = FirstOfGroup(g)
loop
exitwhen tmpu == null
if not IsUnitInRange(tmpu, source, radius) then
call daura_undo_for_unit(tmpu)
call GroupRemoveUnit(g, tmpu)
else
call GroupRemoveUnit(g, tmpu)
call GroupAddUnit(tmpg, tmpu)
endif
set tmpu = FirstOfGroup(g)
endloop
set swap = g
set g = tmpg
set tmpg = swap
call SaveGroupHandle(HT, GetHandleId(t), StringHash("clean_up_group"), g)
set t = null
set g = null
set source = null
set swap = null
endfunction
private function source_only_do takes unit u returns nothing
call SaveEffectHandle(HT, GetHandleId(u), StringHash("source_only_effect"), /*
*/ AddSpecialEffectTarget(SOURCE_EFFECT, u, SOURCE_EFFECT_AP))
endfunction
private function add_daura_to_unit takes unit u, integer level returns nothing
local trigger t = null
local trigger t2 = null
local r17field r17f = 0
local real r = 0
local integer uid = 0
local timer tmr = null
local group g = null
set uid = GetHandleId(u)
if IsUnitType(u, UNIT_TYPE_HERO) then
set r = AoE(level)
else
set r = AoE(1)
endif
set t = CreateTrigger()
call TriggerRegisterUnitInRange(t, u, r, null)
call TriggerAddCondition(t, Condition(function daura_do))
call SaveTriggerHandle(HT, uid, StringHash("in_range_trigger"), t)
set t2 = CreateTrigger()
set r17f = TriggerRegisterUnitOutOfRange(t2, u, r + 32.0)
call TriggerAddCondition(t2, Condition(function daura_undo))
call SaveInteger(HT, uid, StringHash("out_of_range_trigger"), r17f)
call SaveInteger(HT, uid, StringHash("has_daura"), 1)
if targets_allowed(u) then
// source of the aura can use it right? =)
call daura_do_for_unit(u)
endif
call source_only_do(u)
static if LIBRARY_GroupUtils then
set g = NewGroup()
else
set g = CreateGroup()
endif
call SaveGroupHandle(HT, GetHandleId(t), StringHash("clean_up_group"), g)
call SaveGroupHandle(HT, GetHandleId(t2), StringHash("clean_up_group"), g)
static if LIBRARY_TimerUtils then
set tmr = NewTimer()
else
set tmr = CreateTimer()
endif
call SaveUnitHandle(HT, GetHandleId(tmr), StringHash("source"), u)
call SaveTimerHandle(HT, uid, StringHash("cleaner"), tmr)
call SaveGroupHandle(HT, GetHandleId(tmr), StringHash("clean_up_group"), g)
call TimerStart(tmr, CLEAN_UP_PERIOD, true, function daura_clean_up)
set t = null
set t2 = null
set tmr = null
set g = null
endfunction
private function source_only_undo takes unit u returns nothing
call DestroyEffect(LoadEffectHandle(HT, GetHandleId(u), StringHash("source_only_effect")))
endfunction
private function remove_daura_from_unit takes unit u returns nothing
local trigger t = null
local r17field r17f = 0
local real r = 0
local integer uid = 0
set uid = GetHandleId(u)
set t = LoadTriggerHandle(HT, uid, StringHash("in_range_trigger"))
set r17f = LoadInteger(HT, uid, StringHash("out_of_range_trigger"))
call DisableTrigger(t)
call TriggerClearConditions(t)
call DestroyTrigger(t)
call r17f.stop()
call SaveInteger(HT, uid, StringHash("has_daura"), 0)
if targets_allowed(u) then
call daura_undo_for_unit(u)
endif
call source_only_undo(u)
set t = null
endfunction
//------------------------------------------------------------------------------
private function on_learn_skill takes nothing returns boolean
local unit u = null
if ABIL_ID != GetLearnedSkill() then
return false
endif
set u = GetTriggerUnit()
if LoadInteger(HT, GetHandleId(u), StringHash("has_daura")) == 1 then
call remove_daura_from_unit(u)
call add_daura_to_unit(u, GetLearnedSkillLevel())
else
call add_daura_to_unit(u, 1)
endif
set u = null
return false
endfunction
private function on_death takes nothing returns boolean
local unit u = null
local integer uid = 0
local timer t = null
local group g = null
set u = GetTriggerUnit()
set uid = GetHandleId(u)
if LoadInteger(HT, uid, StringHash("has_daura")) != 1 then
return false
endif
set t = LoadTimerHandle(HT, uid, StringHash("cleaner"))
set g = LoadGroupHandle(HT, GetHandleId(t), StringHash("clean_up_group"))
set tmpu = FirstOfGroup(g)
loop
exitwhen tmpu == null
call daura_undo_for_unit(tmpu)
call GroupRemoveUnit(g, tmpu)
set tmpu = FirstOfGroup(g)
endloop
call source_only_undo(u)
call remove_daura_from_unit(u)
static if LIBRARY_GroupUtils then
call ReleaseGroup(g)
else
call DestroyGroup(g)
endif
static if LIBRARY_TimerUtils then
call ReleaseTimer(t)
else
call PauseTimer(t)
call DestroyTimer(t)
endif
set u = null
set t = null
set g = null
return false
endfunction
private function on_revive takes nothing returns boolean
local unit u = GetTriggerUnit()
if LoadInteger(HT, GetHandleId(u), StringHash("has_daura")) == 1 then
call add_daura_to_unit(u, GetUnitAbilityLevel(u, ABIL_ID))
endif
set u = null
return false
endfunction
private function on_retrain takes nothing returns boolean
local unit u = GetTriggerUnit()
if GetItemTypeId(GetManipulatedItem()) == 039;tret039; then
if LoadInteger(HT, GetHandleId(u), StringHash("has_daura")) == 1 then
call remove_daura_from_unit(u)
endif
endif
set u = null
return false
endfunction
private function init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
call TriggerAddCondition(t, Condition(function on_learn_skill))
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function on_death))
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_REVIVE_FINISH)
call TriggerAddCondition(t, Condition(function on_revive))
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_USE_ITEM)
call TriggerAddCondition(t, Condition(function on_retrain))
endfunction
endscope