//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
BS_Caster | unit | No | |
BS_Player | player | No | |
BS_Target | unit | No | |
CF_Ability | abilcode | No | |
CF_Attacktype | attacktype | No | |
CF_BurnAttach | string | No | |
CF_BurnEff | string | No | |
CF_Caster | unit | Yes | |
CF_CEff | string | No | |
CF_CurrentIndex | integer | No | |
CF_Damage | real | Yes | |
CF_Damagetype | damagetype | No | |
CF_Gap | real | No | |
CF_HitAttach | string | No | |
CF_HitEff | string | No | |
CF_Level | integer | Yes | |
CF_LineEff | string | No | |
CF_Loop | integer | Yes | |
CF_MaxEff | integer | No | |
CF_MaxIndex | integer | No | |
CF_Neutral | player | No | |
CF_PeriodicDamage | real | Yes | |
CF_Target | unit | Yes | |
CF_Waves | integer | Yes |
//TESH.scrollpos=270
//TESH.alwaysfold=0
globals
//strange ones at bottom
constant integer ORDER_OFFSET=851970
constant integer ORDER_wandillusion=852274
constant integer ORDER_absorb=852529
constant integer ORDER_acidbomb=852662
constant integer ORDER_acolyteharvest=852185
constant integer ORDER_AImove=851988
constant integer ORDER_ambush=852131
constant integer ORDER_ancestralspirit=852490
constant integer ORDER_ancestralspirittarget=852491
constant integer ORDER_animatedead=852217
constant integer ORDER_antimagicshell=852186
constant integer ORDER_attack=851983
constant integer ORDER_attackground=851984
constant integer ORDER_attackonce=851985
constant integer ORDER_attributemodskill=852576
constant integer ORDER_auraunholy=852215
constant integer ORDER_auravampiric=852216
constant integer ORDER_autodispel=852132
constant integer ORDER_autodispeloff=852134
constant integer ORDER_autodispelon=852133
constant integer ORDER_autoentangle=852505
constant integer ORDER_autoentangleinstant=852506
constant integer ORDER_autoharvestgold=852021
constant integer ORDER_autoharvestlumber=852022
constant integer ORDER_avatar=852086
constant integer ORDER_avengerform=852531
constant integer ORDER_awaken=852466
constant integer ORDER_banish=852486
constant integer ORDER_barkskin=852135
constant integer ORDER_barkskinoff=852137
constant integer ORDER_barkskinon=852136
constant integer ORDER_battleroar=852099
constant integer ORDER_battlestations=852099
constant integer ORDER_bearform=852138
constant integer ORDER_berserk=852100
constant integer ORDER_blackarrow=852577
constant integer ORDER_blackarrowoff=852579
constant integer ORDER_blackarrowon=852578
constant integer ORDER_blight=852187
constant integer ORDER_blink=852525
constant integer ORDER_blizzard=852089
constant integer ORDER_bloodlust=852101
constant integer ORDER_bloodlustoff=852103
constant integer ORDER_bloodluston=852102
constant integer ORDER_board=852043
constant integer ORDER_breathoffire=852580
constant integer ORDER_breathoffrost=852560
constant integer ORDER_build=851994
constant integer ORDER_burrow=852533
constant integer ORDER_cannibalize=852188
constant integer ORDER_carrionscarabs=852551
constant integer ORDER_carrionscarabsinstant=852554
constant integer ORDER_carrionscarabsoff=852553
constant integer ORDER_carrionscarabson=852552
constant integer ORDER_carrionswarm=852218
constant integer ORDER_chainlightning=852119
constant integer ORDER_channel=852600
constant integer ORDER_charm=852581
constant integer ORDER_chemicalrage=852663
constant integer ORDER_cloudoffog=852473
constant integer ORDER_clusterrockets=852652
constant integer ORDER_coldarrows=852244
constant integer ORDER_coldarrowstarg=852243
constant integer ORDER_controlmagic=852474
constant integer ORDER_corporealform=852493
constant integer ORDER_corrosivebreath=852140
constant integer ORDER_coupleinstant=852508
constant integer ORDER_coupletarget=852507
constant integer ORDER_creepanimatedead=852246
constant integer ORDER_creepdevour=852247
constant integer ORDER_creepheal=852248
constant integer ORDER_creephealoff=852250
constant integer ORDER_creephealon=852249
constant integer ORDER_creepthunderbolt=852252
constant integer ORDER_creepthunderclap=852253
constant integer ORDER_cripple=852189
constant integer ORDER_curse=852190
constant integer ORDER_curseoff=852192
constant integer ORDER_curseon=852191
constant integer ORDER_cyclone=852144
constant integer ORDER_darkconversion=852228
constant integer ORDER_darkportal=852229
constant integer ORDER_darkritual=852219
constant integer ORDER_darksummoning=852220
constant integer ORDER_deathanddecay=852221
constant integer ORDER_deathcoil=852222
constant integer ORDER_deathpact=852223
constant integer ORDER_decouple=852509
constant integer ORDER_defend=852055
constant integer ORDER_detectaoe=852015
constant integer ORDER_detonate=852145
constant integer ORDER_devour=852104
constant integer ORDER_devourmagic=852536
constant integer ORDER_disassociate=852240
constant integer ORDER_disenchant=852495
constant integer ORDER_dismount=852470
constant integer ORDER_dispel=852057
constant integer ORDER_divineshield=852090
constant integer ORDER_doom=852583
constant integer ORDER_drain=852487
constant integer ORDER_dreadlordinferno=852224
constant integer ORDER_dropitem=852001
constant integer ORDER_drunkenhaze=852585
constant integer ORDER_earthquake=852121
constant integer ORDER_eattree=852146
constant integer ORDER_elementalfury=852586
constant integer ORDER_ensnare=852106
constant integer ORDER_ensnareoff=852108
constant integer ORDER_ensnareon=852107
constant integer ORDER_entangle=852147
constant integer ORDER_entangleinstant=852148
constant integer ORDER_entanglingroots=852171
constant integer ORDER_etherealform=852496
constant integer ORDER_evileye=852105
constant integer ORDER_faeriefire=852149
constant integer ORDER_faeriefireoff=852151
constant integer ORDER_faeriefireon=852150
constant integer ORDER_fanofknives=852526
constant integer ORDER_farsight=852122
constant integer ORDER_fingerofdeath=852230
constant integer ORDER_firebolt=852231
constant integer ORDER_flamestrike=852488
constant integer ORDER_flamingarrows=852174
constant integer ORDER_flamingarrowstarg=852173
constant integer ORDER_flamingattack=852540
constant integer ORDER_flamingattacktarg=852539
constant integer ORDER_flare=852060
constant integer ORDER_forceboard=852044
constant integer ORDER_forceofnature=852176
constant integer ORDER_forkedlightning=852586
constant integer ORDER_freezingbreath=852195
constant integer ORDER_frenzy=852561
constant integer ORDER_frenzyoff=852563
constant integer ORDER_frenzyon=852562
constant integer ORDER_frostarmor=852225
constant integer ORDER_frostarmoroff=852459
constant integer ORDER_frostarmoron=852458
constant integer ORDER_frostnova=852226
constant integer ORDER_getitem=851981
constant integer ORDER_gold2lumber=852233
constant integer ORDER_grabtree=852511
constant integer ORDER_harvest=852018
constant integer ORDER_heal=852063
constant integer ORDER_healingspray=852664
constant integer ORDER_healingward=852109
constant integer ORDER_healingwave=852501
constant integer ORDER_healoff=852065
constant integer ORDER_healon=852064
constant integer ORDER_hex=852502
constant integer ORDER_holdposition=851993
constant integer ORDER_holybolt=852092
constant integer ORDER_howlofterror=852588
constant integer ORDER_humanbuild=851995
constant integer ORDER_immolation=852177
constant integer ORDER_impale=852555
constant integer ORDER_incineratearrow=852670
constant integer ORDER_incineratearrowoff=852672
constant integer ORDER_incineratearrowon=852671
constant integer ORDER_inferno=852232
constant integer ORDER_innerfire=852066
constant integer ORDER_innerfireoff=852068
constant integer ORDER_innerfireon=852067
constant integer ORDER_instant=852200
constant integer ORDER_invisibility=852069
constant integer ORDER_lavamonster=852667
constant integer ORDER_lightningshield=852110
constant integer ORDER_load=852046
constant integer ORDER_loadarcher = 852142
constant integer ORDER_loadcorpse=852050
constant integer ORDER_loadcorpseinstant=852053
constant integer ORDER_locustswarm=852556
constant integer ORDER_lumber2gold=852234
constant integer ORDER_magicdefense=852478
constant integer ORDER_magicleash=852480
constant integer ORDER_magicundefense=852479
constant integer ORDER_manaburn=852179
constant integer ORDER_manaflareoff=852513
constant integer ORDER_manaflareon=852512
constant integer ORDER_manashieldoff=852590
constant integer ORDER_manashieldon=852589
constant integer ORDER_massteleport=852093
constant integer ORDER_mechanicalcritter=852564
constant integer ORDER_metamorphosis=852180
constant integer ORDER_militia=852072
constant integer ORDER_militiaconvert=852071
constant integer ORDER_militiaoff=852073
constant integer ORDER_militiaunconvert=852651
constant integer ORDER_mindrot=852565
constant integer ORDER_mirrorimage=852123
constant integer ORDER_monsoon=852591
constant integer ORDER_mount=852469
constant integer ORDER_mounthippogryph=852143
constant integer ORDER_move=851986
constant integer ORDER_nagabuild=852467
constant integer ORDER_neutraldetectaoe=852023
constant integer ORDER_neutralinteract=852566
constant integer ORDER_neutralspell=852630
constant integer ORDER_nightelfbuild=851997
constant integer ORDER_orcbuild=851996
constant integer ORDER_parasite=852601
constant integer ORDER_parasiteoff=852603
constant integer ORDER_parasiteon=852602
constant integer ORDER_patrol=851990
constant integer ORDER_phaseshift=852514
constant integer ORDER_phaseshiftinstant=852517
constant integer ORDER_phaseshiftoff=852516
constant integer ORDER_phaseshifton=852515
constant integer ORDER_phoenixfire=852481
constant integer ORDER_phoenixmorph=852482
constant integer ORDER_poisonarrows=852255
constant integer ORDER_poisonarrowstarg=852254
constant integer ORDER_polymorph=852074
constant integer ORDER_possession=852196
constant integer ORDER_preservation=852568
constant integer ORDER_purge=852111
constant integer ORDER_rainofchaos=852237
constant integer ORDER_rainoffire=852238
constant integer ORDER_raisedead=852197
constant integer ORDER_raisedeadoff=852199
constant integer ORDER_raisedeadon=852198
constant integer ORDER_ravenform=852155
constant integer ORDER_recharge=852157
constant integer ORDER_rechargeoff=852159
constant integer ORDER_rechargeon=852158
constant integer ORDER_rejuvination=852160
constant integer ORDER_renew=852161
constant integer ORDER_renewoff=852163
constant integer ORDER_renewon=852162
constant integer ORDER_repair=852024
constant integer ORDER_repairoff=852026
constant integer ORDER_repairon=852025
constant integer ORDER_replenish=852542
constant integer ORDER_replenishlife=852545
constant integer ORDER_replenishlifeoff=852547
constant integer ORDER_replenishlifeon=852546
constant integer ORDER_replenishmana=852548
constant integer ORDER_replenishmanaoff=852550
constant integer ORDER_replenishmanaon=852549
constant integer ORDER_replenishoff=852544
constant integer ORDER_replenishon=852543
constant integer ORDER_request_hero=852239
constant integer ORDER_requestsacrifice=852201
constant integer ORDER_restoration=852202
constant integer ORDER_restorationoff=852204
constant integer ORDER_restorationon=852203
constant integer ORDER_resumebuild=851999
constant integer ORDER_resumeharvesting=852017
constant integer ORDER_resurrection=852094
constant integer ORDER_returnresources=852020
constant integer ORDER_revenge=852241
constant integer ORDER_revive=852039
constant integer ORDER_roar=852164
constant integer ORDER_robogoblin=852656
constant integer ORDER_root=852165
constant integer ORDER_sacrifice=852205
constant integer ORDER_sanctuary=852569
constant integer ORDER_scout=852181
constant integer ORDER_selfdestruct=852040
constant integer ORDER_selfdestructoff=852042
constant integer ORDER_selfdestructon=852041
constant integer ORDER_sentinel=852182
constant integer ORDER_setrally=851980
constant integer ORDER_shadowsight=852570
constant integer ORDER_shadowstrike=852527
constant integer ORDER_shockwave=852125
constant integer ORDER_silence=852592
constant integer ORDER_sleep=852227
constant integer ORDER_slow=852075
constant integer ORDER_slowoff=852077
constant integer ORDER_slowon=852076
constant integer ORDER_smart=851971
constant integer ORDER_soulburn=852668
constant integer ORDER_soulpreservation=852242
constant integer ORDER_spellshield=852571
constant integer ORDER_spellshieldaoe=852572
constant integer ORDER_spellsteal=852483
constant integer ORDER_spellstealoff=852485
constant integer ORDER_spellstealon=852484
constant integer ORDER_spies=852235
constant integer ORDER_spiritlink=852499
constant integer ORDER_spiritofvengeance=852528
constant integer ORDER_spirittroll=852573
constant integer ORDER_spiritwolf=852126
constant integer ORDER_stampede=852593
constant integer ORDER_standdown=852113
constant integer ORDER_starfall=852183
constant integer ORDER_stasistrap=852114
constant integer ORDER_steal=852574
constant integer ORDER_stomp=852127
constant integer ORDER_stoneform=852206
constant integer ORDER_stop=851972
constant integer ORDER_submerge=852604
constant integer ORDER_summonfactory=852658
constant integer ORDER_summongrizzly=852594
constant integer ORDER_summonphoenix=852489
constant integer ORDER_summonquillbeast=852595
constant integer ORDER_summonwareagle=852596
constant integer ORDER_tankdroppilot=852079
constant integer ORDER_tankloadpilot=852080
constant integer ORDER_tankpilot=852081
constant integer ORDER_taunt=852520
constant integer ORDER_thunderbolt=852095
constant integer ORDER_thunderclap=852096
constant integer ORDER_tornado=852597
constant integer ORDER_townbelloff=852083
constant integer ORDER_townbellon=852082
constant integer ORDER_tranquility=852184
constant integer ORDER_transmute=852665
constant integer ORDER_unavatar=852087
constant integer ORDER_unavengerform=852532
constant integer ORDER_unbearform=852139
constant integer ORDER_unburrow=852534
constant integer ORDER_uncoldarrows=852245
constant integer ORDER_uncorporealform=852494
constant integer ORDER_undeadbuild=851998
constant integer ORDER_undefend=852056
constant integer ORDER_undivineshield=852091
constant integer ORDER_unetherealform=852497
constant integer ORDER_unflamingarrows=852175
constant integer ORDER_unflamingattack=852541
constant integer ORDER_unholyfrenzy=852209
constant integer ORDER_unimmolation=852178
constant integer ORDER_unload=852047
constant integer ORDER_unloadall=852048
constant integer ORDER_unloadallcorpses=852054
constant integer ORDER_unloadallinstant=852049
constant integer ORDER_unpoisonarrows=852256
constant integer ORDER_unravenform=852156
constant integer ORDER_unrobogoblin=852657
constant integer ORDER_unroot=852166
constant integer ORDER_unstableconcoction=852500
constant integer ORDER_unstoneform=852207
constant integer ORDER_unsubmerge=852605
constant integer ORDER_unsummon=852210
constant integer ORDER_unwindwalk=852130
constant integer ORDER_vengeance=852521
constant integer ORDER_vengeanceinstant=852524
constant integer ORDER_vengeanceoff=852523
constant integer ORDER_vengeanceon=852522
constant integer ORDER_volcano=852669
constant integer ORDER_voodoo=852503
constant integer ORDER_ward=852504
constant integer ORDER_waterelemental=852097
constant integer ORDER_wateryminion=852598
constant integer ORDER_web=852211
constant integer ORDER_weboff=852213
constant integer ORDER_webon=852212
constant integer ORDER_whirlwind=852128
constant integer ORDER_windwalk=852129
constant integer ORDER_wispharvest=852214
constant integer ORDER_scrollofspeed=852285
constant integer ORDER_cancel=851976
constant integer ORDER_moveslot1=852002
constant integer ORDER_moveslot2=852003
constant integer ORDER_moveslot3=852004
constant integer ORDER_moveslot4=852005
constant integer ORDER_moveslot5=852006
constant integer ORDER_moveslot6=852007
constant integer ORDER_useslot1=852008
constant integer ORDER_useslot2=852009
constant integer ORDER_useslot3=852010
constant integer ORDER_useslot4=852011
constant integer ORDER_useslot5=852012
constant integer ORDER_useslot6=852013
constant integer ORDER_skillmenu=852000
constant integer ORDER_stunned=851973
constant integer ORDER_instant1=851991 //?
constant integer ORDER_instant2=851987 //?
constant integer ORDER_instant3=851975 //?
constant integer ORDER_instant4=852019 //?
endglobals
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library_once Event /* v2.0.0.1
************************************************************************************
*
* Functions
*
* function CreateEvent takes nothing returns integer
* function TriggerRegisterEvent takes trigger t, integer ev returns nothing
*
************************************************************************************
*
* struct Event extends array
*
* static method create takes nothing returns thistype
* method registerTrigger takes trigger t returns nothing
* method register takes boolexpr c returns nothing
* method fire takes nothing returns nothing
*
************************************************************************************/
globals
private real q=0
endglobals
struct Event extends array
private static integer w=0
private static trigger array e
static method create takes nothing returns thistype
set w=w+1
set e[w]=CreateTrigger()
return w
endmethod
method registerTrigger takes trigger t returns nothing
call TriggerRegisterVariableEvent(t,SCOPE_PRIVATE+"q",EQUAL,this)
endmethod
method register takes boolexpr c returns nothing
call TriggerAddCondition(e[this],c)
endmethod
method fire takes nothing returns nothing
set q=0
set q=this
call TriggerEvaluate(e[this])
endmethod
endstruct
function CreateEvent takes nothing returns Event
return Event.create()
endfunction
function TriggerRegisterEvent takes trigger t,Event ev returns nothing
call ev.registerTrigger(t)
endfunction
function RegisterEvent takes boolexpr c,Event ev returns nothing
call ev.register(c)
endfunction
function FireEvent takes Event ev returns nothing
call ev.fire()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library_once WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
* readonly static integer centerX
* readonly static integer centerY
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX=R2I(GetRectMaxX(world))
set maxY=R2I(GetRectMaxY(world))
set minX=R2I(GetRectMinX(world))
set minY=R2I(GetRectMinY(world))
set centerX=R2I((maxX+minX)/2)
set centerY=R2I((minY+maxY)/2)
set worldRegion=CreateRegion()
call RegionAddRect(worldRegion,world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
* Read Me
* ---------
*
* In order to use Dummy you have to setup 3 things
*
* 1. Import the dummy model into your map (F12) - Import Editor
* 2. Copy the unit particle into your map (F6) - Object Editor
* 3. Set private constant integer DUMMY_ID inside the Dummy library
* to the correct path of particle (CTRL + D) - Object Editor and Trigger Editor
*/
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Dummy /* v1.0.0.5
*************************************************************************************
*
* Allows one to create dummy units that are either at or are close
* to the angle specified.
*
* Dummy recycling minimizes the number of dummy units on the map while supporting near
* instant SetUnitFacing.
*
* Assigned dummy indexes are not unit indexes.
*
* Errors
* ----------------------------
*
* Any error will result in the system disabling itself and an error message
*
* -> May not kill dummies
* -> May not remove dummies
* -> May not attempt to recycle non dummies
*
*************************************************************************************
*
* Credits
*
* Vexorian for dummy.mdx
*
* Bribe
*
* Delayed recycling implemetation
* ----------------------------
*
* Bribe's delayed recycling implementation uses timestamps rather than timers, which
* helps improve performance.
*
* Stamps for queue node movement
* ----------------------------
*
* Convinced me that this was worth it
*
* Time it takes to rotate 180 degrees
* ----------------------------
*
* Supplied me with the number .73
*
*************************************************************************************
*
* */ uses /*
*
* /* Any Unit Indexer */
* */ UnitIndexer /* can be any, but one must be chosen
*
************************************************************************************
*
* SETTINGS
*
*/
globals
/*
* The unit id of dummy.mdx
*/
private constant integer DUMMY_ID = 'h000'
/*
* The space between angles for the recycler
*
* Angles used are angles from 0 to 359 in intervals of ANGLE_SPACING
*
* Higher spacing means less units but lower accuracy when creating the facing
*
*/
private constant integer ANGLE_SPACING = 15
/*
* How many projectiles to preload per angle
*
* Preloaded projectile count is 360/ANGLE_SPACING*MAX_PROJECTILES
*
*/
private constant integer PRELOAD_PROJECTILES_PER_ANGLE = 1//50
/*
* How much to delay before recycling dummy
*/
private constant real RECYCLE_DELAY = 2
endglobals
/*
************************************************************************************
*
* library MissileRecycler uses Dummy
* ----------------------------
*
* For compatibility with Bribe's resource
*
* function GetRecycledMissile takes real x, real y, real z, real facing returns unit
* function RecycleMissile takes unit whichUnit returns nothing
*
************************************************************************************
*
* Functions
* ----------------------------
*
* function IsUnitDummy takes unit whichUnit returns boolean
*
************************************************************************************
*
*
* struct Dummy extends array
*
* Creators/Destructors
* ----------------------------
*
* static method create takes real x, real y, real facing returns Dummy
* - For those of you who really want this to return a unit, getting
* - the unit from this is very easy, so don't whine
*
* - Dummy.create().unit -> unit
*
* method destroy takes nothing returns nothing
* - For those of you who really want this to take a unit, getting
* - the dummy index is very easy.
*
* - Dummy[whichUnit].destroy()
*
* Fields
* ----------------------------
*
* readonly unit unit
*
* Operators
* ----------------------------
*
* static method operator [] takes unit dummyUnit returns Dummy
*
************************************************************************************/
private keyword Queue
globals
/*
* Used for dummy instancing
* Dummy indexes are never destroyed, so there is no need for a recycler
*/
private Queue dummyCount = 0
/*
* Used to retrieve unit handle via dummy index
*/
private unit array dummies
private integer array indexPointer
private integer array dummyPointer
/*
* The owner of all dummy units. This shouldn't be changed.
*/
private constant player DUMMY_OWNER = Player(15)
/*
* Used to apply time stamps to dummies for recycling
* purposes. A dummy is only considered recycled if its
* stamp is less than the elapsed time of stamp timer.
*/
private timer stampTimer
endglobals
function IsUnitDummy takes unit whichUnit returns boolean
return dummies[GetUnitUserData(whichUnit)] == whichUnit
endfunction
/*
* min == max - 1
* max == min + 1
*
* variance of counts must be 1
*/
private struct ArrayStack extends array
/*
* The minimum and maximum counts
*/
static thistype max = 0
static thistype min = 0
/*
* list[count].first
*/
thistype first
/*
* queue.size
*/
thistype count_p
/*
* list[count].next
*/
thistype next
/*
* list[count].prev
*/
thistype prev
/*
* list[count].first -> queue of dummies
*/
static method operator [] takes thistype index returns thistype
return index.first
endmethod
/*
* list[count].add(queue of dummies)
*/
private method add takes thistype node returns nothing
/*
* Update min/max
*/
if (integer(this) > integer(max)) then
set max = this
elseif (integer(this) < integer(min)) then
set min = this
endif
/*
* Push on to front of list like a stack
*/
set node.next = first
set node.next.prev = node
set node.prev = 0
set first = node
set node.count_p = this
endmethod
/*
* list[count].remove(list of dummies)
*/
private method remove takes thistype node returns nothing
/*
* If node is the first, update the first
*/
if (node == first) then
set first = node.next
/*
* If list is empty, update min/max
*/
if (0 == first) then
if (this == min) then
set min = max
else
set max = min
endif
endif
else
/*
* Simple removal
*/
set node.prev.next = node.next
set node.next.prev = node.prev
endif
endmethod
method operator count takes nothing returns integer
return count_p
endmethod
method operator count= takes thistype value returns nothing
/*
* Remove from list node was on
*/
call count_p.remove(this)
/*
* Add to new list
*/
call value.add(this)
endmethod
endstruct
/*
* queue = angle + 1
*/
private struct Queue extends array
private real stamp
thistype next
thistype last
/*
* Update dummy count for queue
*/
private method operator count takes nothing returns integer
return ArrayStack(this).count
endmethod
private method operator count= takes integer value returns nothing
set ArrayStack(this).count = value
endmethod
/*
* Queue with smallest number of dummies
*/
private static method operator min takes nothing returns thistype
return ArrayStack.min.first
endmethod
/*
* Queue with largest number of dummies
*/
private static method operator max takes nothing returns thistype
return ArrayStack.max.first
endmethod
static method add takes thistype dummy returns nothing
/*
* Always add to the queue with the least amount of dummies
*/
local thistype this = min
/*
* Add to end of queue
*/
set last.next = dummy
set last = dummy
set dummy.next = 0
/*
* Update queue count
*/
set count = count + 1
/*
* Match unit angle with queue
*/
call SetUnitFacing(dummies[indexPointer[dummy]], this - 1)
/*
* Apply stamp so that dummy isn't used until the stamp is expired
*/
set dummy.stamp = TimerGetElapsed(stampTimer) + RECYCLE_DELAY - .01
endmethod
static method pop takes thistype this, real x, real y, real facing returns integer
/*
* Retrieve queue and first dummy on queue given angle
*/
local unit dummyUnit //dummy unit
local thistype dummyIndex = next //dummy index
local integer unitIndex //unit idex
local thistype this2
local thistype node
local real stamp
/*
* If the queue is empty, return new dummy
*/
if (0 == dummyIndex or dummyIndex.stamp > TimerGetElapsed(stampTimer)) then
/*
* Allocate new dummy
*/
debug if (dummyCount == 8191) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"DUMMY RECYCLER FATAL ERROR: DUMMY OVERLOAD")
debug set Dummy.enabled = false
debug set this = 1/0
debug endif
set dummyIndex = dummyCount + 1
set dummyCount = dummyIndex
/*
* Create and initialize new unit handle
*/
set dummyUnit = CreateUnit(DUMMY_OWNER, DUMMY_ID, x, y, facing)
set unitIndex = GetUnitUserData(dummyUnit)
set indexPointer[dummyIndex] = unitIndex
set dummyPointer[unitIndex] = dummyIndex
set dummies[unitIndex] = dummyUnit
call UnitAddAbility(dummyUnit, 'Amrf')
call UnitRemoveAbility(dummyUnit, 'Amrf')
call PauseUnit(dummyUnit, true)
return dummyIndex
endif
/*
* Remove the dummy from the queue
*/
set next = dummyIndex.next
if (0 == next) then
set last = this
endif
/*
* Only remove from the count if the queue has most dummies in it
*
* If queue doesn't have most dummies in it, take a dummy from the queue
* with most dummies in it and keep count the same
*/
if (count == ArrayStack.max) then
set count = count - 1
else
/*
* Retrieve the queue with most dummies in it as well as the
* first dummy in that queue
*/
set this2 = max
set node = this2.next
/*
* Remove first dummy from largest queue
*/
if (0 == node.next) then
set this2.last = this2
else
set this2.next = node.next
endif
set this2.count = this2.count - 1
/*
* Add first dummy to current queue
*/
set last.next = node
set last = node
set node.next = 0
/*
* Match unit angle with queue
*/
call SetUnitFacing(dummies[indexPointer[node]], this - 1)
/*
* .73 seconds is how long it takes for a dummy to rotate 180 degrees
*
* Credits to Bribe for these 4 lines of code and the .73 value
*/
set stamp = TimerGetElapsed(stampTimer) + .73
if (stamp > node.stamp) then
set node.stamp = stamp
endif
endif
/*
* Move dummy to target position
*/
set dummyUnit = dummies[indexPointer[dummyIndex]]
call SetUnitX(dummyUnit, x)
call SetUnitY(dummyUnit, y)
call SetUnitFacing(dummyUnit, facing)
set dummyUnit = null
/*
* Return first dummy from current queue
*/
return dummyIndex
endmethod
endstruct
struct Dummy extends array
debug static boolean enabled = false
debug private boolean allocated
/*
* Retrieve index given unit handle
*/
static method operator [] takes unit dummyUnit returns thistype
debug if (not enabled) then
debug return 1/0
debug endif
return GetUnitUserData(dummyUnit)
endmethod
/*
* Retrieve unit handle given index
*/
method operator unit takes nothing returns unit
debug if (not enabled) then
debug set this = 1/0
debug endif
return dummies[this]
endmethod
/*
* Slightly faster than ModuloInteger due to less args + constants
*/
private static method getClosestAngle takes integer angle returns integer
set angle = angle - angle/360*360
if (0 > angle) then
set angle = angle + 360
endif
return angle/ANGLE_SPACING*ANGLE_SPACING
endmethod
/*
* Returns either a new or a recycled dummy index
*/
static method create takes real x, real y, real facing returns Dummy
static if DEBUG_MODE then
local thistype this
if (not enabled) then
set x = 1/0
endif
set this = indexPointer[Queue.pop(getClosestAngle(R2I(facing)) + 1, x, y, facing)]
debug set allocated = true
return this
else
return indexPointer[Queue.pop(getClosestAngle(R2I(facing)) + 1, x, y, facing)]
endif
endmethod
/*
* Recycles dummy index
*/
method destroy takes nothing returns nothing
debug if (not enabled) then
debug set this = 1/0
debug endif
/*
* If the recycled dummy was invalid, issue critical error
*/
debug if (0 == GetUnitTypeId(unit) or 0 == GetWidgetLife(unit) or not allocated) then
debug if (not allocated) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 10, "DUMMY RECYCLER FATAL ERROR: DOUBLE FREE")
debug elseif (null == unit) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 10, "DUMMY RECYCLER FATAL ERROR: REMOVED A DUMMY")
debug elseif (0 == GetWidgetLife(unit)) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 10, "DUMMY RECYCLER FATAL ERROR: KILLED A DUMMY")
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 10, "DUMMY RECYCLER FATAL ERROR: ATTEMPTED TO RECYCLE NON DUMMY UNIT")
debug endif
debug set enabled = false
debug set this = 1/0
debug endif
debug if (indexPointer[dummyPointer[this]] != this) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ERROR")
debug endif
debug set allocated = false
call SetUnitPosition(dummies[this], 2147483647, 2147483647)
call Queue.add(dummyPointer[this])
endmethod
endstruct
/*
* Initialization
*/
private function Initialize takes nothing returns nothing
local unit dummy
local integer last
local integer angle
local ArrayStack queue
local integer count
/*
* This timer
*/
set stampTimer = CreateTimer()
call TimerStart(stampTimer, 604800, false, null)
/*
* The highest possible angle
*/
set last = 360/ANGLE_SPACING*ANGLE_SPACING
if (360 == last) then
set last = last - ANGLE_SPACING
if (last < ANGLE_SPACING) then
set last = 0
endif
endif
/*
* The lowest possible angle
*/
set angle = 0
/*
* Start dummy count at the last possible angle so that
* angles don't overlap with dummy indexes. This is done
* to simplify queue algorithm and improve overall performance.
* At most 360 possible dummy unit indexes will be lost due to this.
*/
set dummyCount = last + 1
/*
* Initialize ArrayStack
*/
set ArrayStack.min = PRELOAD_PROJECTILES_PER_ANGLE
set ArrayStack.max = PRELOAD_PROJECTILES_PER_ANGLE
set ArrayStack(PRELOAD_PROJECTILES_PER_ANGLE).first = 1
loop
/*
* queue pointer is angle + 1
*/
set queue = angle + 1
/*
* Only add projectiles to queue if MAX_PROJECTILES < 0
*/
if (0 < PRELOAD_PROJECTILES_PER_ANGLE) then
set count = PRELOAD_PROJECTILES_PER_ANGLE
set queue.count_p = PRELOAD_PROJECTILES_PER_ANGLE
set dummyCount = dummyCount + 1
set Queue(queue).next = dummyCount
/*
* Create and add all dummies to queue
*/
loop
/*
* Create and initialize unit handle
*/
set dummy = CreateUnit(DUMMY_OWNER, DUMMY_ID, 0, 0, angle)
set indexPointer[dummyCount] = GetUnitUserData(dummy)
set dummyPointer[GetUnitUserData(dummy)] = dummyCount
set dummies[indexPointer[dummyCount]] = dummy
call UnitAddAbility(dummy, 'Amrf')
call UnitRemoveAbility(dummy, 'Amrf')
call PauseUnit(dummy, true)
set count = count - 1
exitwhen 0 == count
/*
* Point to next
*/
set dummyCount.next = dummyCount + 1
set dummyCount = dummyCount + 1
endloop
set Queue(queue).last = dummyCount
else
set Queue(queue).last = queue
endif
exitwhen last == angle
/*
* Go to next angle
*/
set angle = angle + ANGLE_SPACING
/*
* Link queues together
*/
set queue.next = angle + 1
set ArrayStack(angle + 1).prev = queue
/*
* Go to next queue
*/
set queue = angle + 1
endloop
set dummy = null
debug set Dummy.enabled = true
endfunction
private module Init
private static method onInit takes nothing returns nothing
static if DEBUG_MODE then
call ExecuteFunc(SCOPE_PRIVATE + "Initialize")
if (not Dummy.enabled) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"DUMMY RECYCLER FATAL ERROR: INITIALIZATION CRASHED, LOWER PRELOAD DUMMY COUNT")
endif
else
call Initialize()
endif
endmethod
endmodule
private struct Inits extends array
implement Init
endstruct
endlibrary
library MissileRecycler uses Dummy
function GetRecycledMissile takes real x, real y, real z, real facing returns unit
local Dummy dummy = Dummy.create(x, y, facing)
call SetUnitFlyHeight(dummy.unit, z, 0)
return dummy.unit
endfunction
function RecycleMissile takes unit u returns nothing
call Dummy[u].destroy()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
* Read Me
* ---------
*
* In order to use UnitIndexer you have to setup 2 things
*
* 1. Copy the Unit indexing ability into your map (F6) - Object Editor
* 2. Set constant integer ABILITIES_UNIT_INDEXER inside the UnitIndexer library
* to the correct path of the Unit Indexing ability (CTRL + D) - Object Editor and Trigger Editor
*/
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitIndexer /* v4.0.2.7
*************************************************************************************
*
* Assigns unique indexes to units via unit user data.
*
*************************************************************************************
*
* */uses/*
*
* */ WorldBounds /* hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
* */ Event /* hiveworkshop.com/forums/submissions-414/snippet-event-186555/
*
************************************************************************************
*
* SETTINGS
*/
globals
constant integer ABILITIES_UNIT_INDEXER = 'A003'
endglobals
/*
************************************************************************************
*
* Functions
*
* function RegisterUnitIndexEvent takes boolexpr codeToRegister, Event unitIndexEvent returns nothing
* function TriggerRegisterUnitIndexEvent takes trigger triggerToRegister, Event unitIndexEvent returns nothing
*
* function GetUnitById takes integer index returns unit
* - Returns unit given a unit index
* function GetUnitId takes unit u returns integer
* - Returns unit index given a unit
*
* function IsUnitIndexed takes unit u returns boolean
* function IsUnitDeindexing takes unit u returns boolean
*
* function GetIndexedUnitId takes nothing returns integer
* function GetIndexedUnit takes nothing returns unit
*
************************************************************************************
*
* module UnitIndexStructMethods
* static method operator [] takes unit u returns thistype
* - Return GetUnitUserData(u)
*
* readonly unit unit
* - The indexed unit of the struct
*
************************************************************************************
*
* module UnitIndexStruct extends UnitIndexStructMethods
*
* - A pseudo module interface that runs a set of methods if they exist and provides
* - a few fields and operators. Runs on static ifs to minimize code.
*
* readonly boolean allocated
* - Is unit allocated for the struct
*
* Interface:
*
* - These methods don't have to exist. If they don't exist, the code
* - that calls them won't even be in the module.
*
* private method index takes nothing returns nothing
* - called when a unit is indexed and passes the filter.
* -
* - thistype this: Unit's index
* private method deindex takes nothing returns nothing
* - called when a unit is deindexed and is allocated for struct
* -
* - thistype this: Unit's index
* private static method filter takes unit unitToIndex returns boolean
* - Determines whether or not to allocate struct for unit
* -
* - unit unitToIndex: Unit being filtered
*
************************************************************************************
*
* struct UnitIndexer extends array
*
* - Controls the unit indexer system.
*
* static constant Event UnitIndexer.INDEX
* static constant Event UnitIndexer.DEINDEX
* - Don't register functions and triggers directly to the events. Register them via
* - RegisterUnitIndexEvent and TriggerRegisterUnitIndexEvent.
*
* static boolean enabled
* - Enables and disables unit indexing. Useful for filtering out dummy units.
*
************************************************************************************
*
* struct UnitIndex extends UnitIndexStructMethods
*
* - Constrols specific unit indexes.
*
* method lock takes nothing returns nothing
* - Locks an index. When an index is locked, it will not be recycled
* - when the unit is deindexed until all locks are removed. Deindex
* - events still fire at the appropriate times, the index just doesn't
* - get thrown into the recycler.
* method unlock takes nothing returns nothing
* - Unlocks an index.
*
************************************************************************************/
globals
private trigger q=CreateTrigger()
private trigger l=CreateTrigger()
private unit array e
private integer r=0
private integer y=0
private integer o=0
private boolean a=false
private integer array n
private integer array p
private integer array lc
endglobals
function GetIndexedUnitId takes nothing returns integer
return o
endfunction
function GetIndexedUnit takes nothing returns unit
return e[o]
endfunction
//! runtextmacro optional UNIT_LIST_LIB()
private struct PreLoader extends array
public static method run takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
set a=true
endmethod
public static method eval takes trigger t returns nothing
local integer f=n[0]
local integer d=o
loop
exitwhen 0==f
if (IsTriggerEnabled(t)) then
set o=f
if (TriggerEvaluate(t)) then
call TriggerExecute(t)
endif
else
exitwhen true
endif
set f=n[f]
endloop
set o=d
endmethod
public static method evalb takes boolexpr c returns nothing
local trigger t=CreateTrigger()
local thistype f=n[0]
local integer d=o
call TriggerAddCondition(t,c)
loop
exitwhen 0==f
set o=f
call TriggerEvaluate(t)
set f=n[f]
endloop
call DestroyTrigger(t)
set t=null
set o=d
endmethod
endstruct
//! runtextmacro optional UNIT_EVENT_MACRO()
private module UnitIndexerInit
private static method onInit takes nothing returns nothing
local integer i=15
local boolexpr bc=Condition(function thistype.onLeave)
local boolexpr bc2=Condition(function thistype.onEnter)
local group g=CreateGroup()
local player p
set INDEX=CreateEvent()
set DEINDEX=CreateEvent()
call TriggerRegisterEnterRegion(q,WorldBounds.worldRegion,bc2)
loop
set p=Player(i)
call TriggerRegisterPlayerUnitEvent(l,p,EVENT_PLAYER_UNIT_ISSUED_ORDER,bc)
call SetPlayerAbilityAvailable(p,ABILITIES_UNIT_INDEXER,false)
call GroupEnumUnitsOfPlayer(g,p,bc2)
exitwhen 0==i
set i=i-1
endloop
call DestroyGroup(g)
set bc=null
set g=null
set bc2=null
set p=null
call TimerStart(CreateTimer(),0,false,function PreLoader.run)
endmethod
endmodule
struct UnitIndex extends array
method lock takes nothing returns nothing
debug if (null!=e[this]) then
set lc[this]=lc[this]+1
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO LOCK NULL INDEX")
debug endif
endmethod
method unlock takes nothing returns nothing
debug if (0<lc[this]) then
set lc[this]=lc[this]-1
if (0==lc[this] and null==e[this]) then
set n[this]=y
set y=this
endif
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO UNLOCK UNLOCKED INDEX")
debug endif
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
static method operator [] takes unit whichUnit returns thistype
return GetUnitUserData(whichUnit)
endmethod
endstruct
struct UnitIndexer extends array
readonly static Event INDEX
readonly static Event DEINDEX
static boolean enabled=true
private static method onEnter takes nothing returns boolean
local unit Q=GetFilterUnit()
local integer i
local integer d=o
if (enabled and Q!=e[GetUnitUserData(Q)] and 0==GetUnitUserData(Q)) then
if (0==y) then
set r=r+1
set i=r
else
set i=y
set y=n[y]
endif
call UnitAddAbility(Q,ABILITIES_UNIT_INDEXER)
call UnitMakeAbilityPermanent(Q,true,ABILITIES_UNIT_INDEXER)
call SetUnitUserData(Q,i)
set e[i]=Q
static if not LIBRARY_UnitList then
if (not a)then
set p[i]=p[0]
set n[p[0]]=i
set n[i]=0
set p[0]=i
endif
else
set p[i]=p[0]
set n[p[0]]=i
set n[i]=0
set p[0]=i
call GroupAddUnit(g,e[i])
endif
set o=i
call FireEvent(INDEX)
set o=d
endif
set Q=null
return false
endmethod
private static method onLeave takes nothing returns boolean
static if LIBRARY_UnitEvent then
implement optional UnitEventModule
else
local unit u=GetFilterUnit()
local integer i=GetUnitUserData(u)
local integer d=o
if (0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER) and u==e[i]) then
static if not LIBRARY_UnitList then
if (not a)then
set n[p[i]]=n[i]
set p[n[i]]=p[i]
endif
else
set n[p[i]]=n[i]
set p[n[i]]=p[i]
call GroupRemoveUnit(g,e[i])
endif
set o=i
call FireEvent(DEINDEX)
set o=d
if (0==lc[i]) then
set n[i]=y
set y=i
endif
set e[i]=null
endif
set u=null
endif
return false
endmethod
implement UnitIndexerInit
endstruct
//! runtextmacro optional UNIT_EVENT_MACRO_2()
function RegisterUnitIndexEvent takes boolexpr c,integer ev returns nothing
call RegisterEvent(c, ev)
if (not a and ev==UnitIndexer.INDEX and 0!=n[0]) then
call PreLoader.evalb(c)
endif
endfunction
function TriggerRegisterUnitIndexEvent takes trigger t,integer ev returns nothing
call TriggerRegisterEvent(t,ev)
if (not a and ev == UnitIndexer.INDEX and 0!=n[0]) then
call PreLoader.eval(t)
endif
endfunction
function GetUnitById takes integer W returns unit
return e[W]
endfunction
function GetUnitId takes unit u returns integer
return GetUnitUserData(u)
endfunction
function IsUnitIndexed takes unit u returns boolean
return u==e[GetUnitUserData(u)]
endfunction
function IsUnitDeindexing takes unit u returns boolean
return IsUnitIndexed(u) and 0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER)
endfunction
module UnitIndexStructMethods
static method operator [] takes unit u returns thistype
return GetUnitUserData(u)
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
endmodule
module UnitIndexStruct
implement UnitIndexStructMethods
static if thistype.filter.exists then
static if thistype.index.exists then
static if thistype.deindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return filter(e[this])
endmethod
endif
else
method operator allocated takes nothing returns boolean
return filter(e[this])
endmethod
endif
elseif (thistype.index.exists) then
static if thistype.deindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return this==GetUnitUserData(e[this])
endmethod
endif
else
method operator allocated takes nothing returns boolean
return this==GetUnitUserData(e[this])
endmethod
endif
static if thistype.index.exists then
private static method onIndexEvent takes nothing returns boolean
static if thistype.filter.exists then
if (filter(e[o])) then
static if thistype.deindex.exists then
set thistype(o).allocated=true
endif
call thistype(o).index()
endif
else
static if thistype.deindex.exists then
set thistype(o).allocated=true
endif
call thistype(o).index()
endif
return false
endmethod
endif
static if thistype.deindex.exists then
private static method onDeindexEvent takes nothing returns boolean
static if thistype.filter.exists then
static if thistype.index.exists then
if (thistype(o).allocated) then
set thistype(o).allocated=false
call thistype(o).deindex()
endif
else
if (filter(e[o])) then
call thistype(o).deindex()
endif
endif
else
static if thistype.index.exists then
set thistype(o).allocated=false
endif
call thistype(o).deindex()
endif
return false
endmethod
endif
static if thistype.index.exists then
static if thistype.deindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
endmethod
else
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
endmethod
endif
elseif thistype.deindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
endmethod
endif
endmodule
endlibrary
//TESH.scrollpos=104
//TESH.alwaysfold=0
library_once IsPointInRectangle
//determins if point P is in rectangle ABCD
function IsPointInRectangle takes real ax, real ay, real bx, real by, real cx, real cy, real dx, real dy, real px, real py returns boolean
local real cross0 = (py-ay)*(bx-ax)-(px-ax)*(by-ay)
local real cross1 = (py-cy)*(ax-cx)-(px-cx)*(ay-cy)
local real cross4 = (py-dy)*(ax-dx)-(px-dx)*(ay-dy)
return ((cross0*cross1 >= 0) and (((py-by)*(cx-bx)-(px-bx)*(cy-by))*cross1 >= 0)) or ((cross0*cross4 >= 0) and (((py-by)*(dx-bx)-(px-bx)*(dy-by))*cross4 >= 0))
endfunction
endlibrary
library ArcaneTrap /* v1.0.0.0
*************************************************************************************
*
* Creates a trap which creates a lighting moving in a circle.
* Units hit by the lightning will be damaged each interval.
*
*************************************************************************************
*
* Credits
*
* To Nestharus
* -----------------------
*
* For Alloc
*
* To Vexorian
* -----------------------
*
* For TimerUtils
*
*
*************************************************************************************
*
* */ uses /*
*
* */ Dummy /*
* */ optional TimerUtils /* http://www.wc3c.net/showthread.php?t=101322
* */ optional Alloc /* -
*
************************************************************************************
*
* 2. API
* ¯¯¯¯¯¯
* struct ArcaneTrap extends array
*
* static method create takes player who, real createX, real createY, real degree, integer level returns thistype
* method destroy takes nothing returns nothing
*
* method operator owner= takes player who returns nothing
* Not really changes the controller, but the player for the player struct member "own"
*
* SETTINGS
*
*/
globals
/*
* Trap models may be curved, which can look weird. A symmetrical model probably will fit best.
*/
private constant integer TRAP_ID = 'o001'
private constant real RED = 0.2
private constant real GREEN = 1.0
private constant real BLUE = 0.2
/*
* Define the variance in which units are damaged.
*/
private constant real VARIANCE = 20.
/*
* The trap can only be invulnerable
* if it's selectable. Otherwise the code
* below will ignore IS_TRAP_INVULNERABLE.
*/
private constant boolean IS_TRAP_SELECTABLE = false
private constant boolean IS_TRAP_INVULNERABLE = false
/*
* Fly height of dummy representing the head of the lightning.
*/
private constant real DUMMY_FLY_HEIGHT = 50.
/*
* Fly height of the origin of the lighting.
*/
private constant real TRAP_HEIGHT = 125.00
private constant real ANGLE_PER_TICK = 0.5
private constant real TIMER_TIMEOUT = 0.031250000
private constant string LIGHTNING = "LEAS"
private constant string EFFECT_ON_DUMMY = "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl"
private constant real SCALE = 1.8
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
endglobals
//native UnitAlive takes unit id returns boolean
private function TargetFilter takes unit target, player who returns boolean
return UnitAlive(target) and IsUnitEnemy(target, who) and not IsUnitType(target, UNIT_TYPE_STRUCTURE)
endfunction
//The duration the trap lasts.
private constant function GetDuration takes integer level returns real
return 40. + (2.*level)
endfunction
private constant function GetRange takes integer level returns real
return 450 + 0.*level
endfunction
private constant function GetDamage takes integer level returns real
return 10.*level
endfunction
struct ArcaneTrap extends array
implement optional Alloc
static if not LIBRARY_Alloc then
private static integer array recycler
static method allocate takes nothing returns thistype
local thistype this = recycler[0]
debug if (0 == this) then
debug call BJDebugMsg("this == 0, Arcane Trap, allocate Overflow")
debug endif
set recycler[0] = recycler[this]
debug set recycler[this] = -1
return this
endmethod
method deallocate takes nothing returns nothing
debug if (recycler[this] != -1) then
debug call BJDebugMsg("this == 0, Arcane Trap, deallocate, Attempted To Deallocate Null Instance.")
debug endif
set recycler[this] = recycler[0]
set recycler[0] = this
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
set recycler[8191] = 0
loop
set recycler[i] = i + 1
exitwhen i == 8190
set i = i + 1
endloop
endmethod
endif
readonly static constant integer TIMED_LIFE = 'BTLF'
readonly unit trap
readonly Dummy dum
private static constant real v = bj_PI/2
private static constant real radians = ANGLE_PER_TICK*bj_DEGTORAD
private static location loc = Location(0,0)
private lightning light
private effect sfx
private player own
private real damage
private real range
private real angle
private real x
private real y
private real x0
private real y0
private static group enu = CreateGroup()
static if not LIBRARY_TimerUtils then
private static timer clock = CreateTimer()
endif
private static integer array n
private static integer array p
method operator owner= takes player p returns nothing
set own = p
endmethod
method destroy takes nothing returns nothing
set n[p[this]] = n[this]
set p[n[this]] = p[this]
call deallocate()
call DestroyEffect(sfx)
call dum.destroy()
call DestroyLightning(light)
call UnitApplyTimedLife(trap, TIMED_LIFE, 0.01)
set trap = null
set light = null
set sfx = null
endmethod
private static method callback takes nothing returns nothing
local thistype this = n[0]
local unit u
local real z
local real z2
local real s//sinus
local real c//cosinus
loop
if UnitAlive(trap) then
set angle = angle + radians
set x = GetUnitX(trap)
set y = GetUnitY(trap)
call SetUnitFacing(trap, angle*bj_RADTODEG)
set x0 = x + range*Cos(angle)
set y0 = y + range*Sin(angle)
set s = VARIANCE*Sin(angle + v)
set c = VARIANCE*Cos(angle + v)
call GroupEnumUnitsInRange(enu, x, y, range, null)
loop
set u = FirstOfGroup(enu)
exitwhen u == null
call GroupRemoveUnit(enu, u)
if TargetFilter(u, own) then
//Requires library IsPointInRectangle
//Detects if a point p is within ABCD.
if (IsPointInRectangle(x + c, y + s, x - c, y - s, x0 - c, y0 - s, x0 + c , y0 + s, GetUnitX(u), GetUnitY(u))) then
call UnitDamageTarget(trap, u, damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
//Add a special effect on hit here.
endif
endif
endloop
call SetUnitX(dum.unit, x0)
call SetUnitY(dum.unit, y0)
call MoveLocation(thistype.loc, x0, y0)
set z = GetLocationZ(thistype.loc)
call MoveLocation(thistype.loc, x, y)
set z2 = GetLocationZ(thistype.loc)
call MoveLightningEx(light, true, x, y, z2 + TRAP_HEIGHT, x0, y0, z + GetUnitFlyHeight(dum.unit))
else
call destroy()
if (0 == n[0]) then
static if LIBRARY_TimerUtils then
call ReleaseTimer(GetExpiredTimer())
else
call PauseTimer(clock)
endif
endif
endif
set this = n[this]
exitwhen 0 == this
endloop
endmethod
static method create takes player who, real createX, real createY, real degree, integer level returns thistype
local thistype this = allocate()
//Linked List
set n[this] = 0
set p[this] = p[0]
set n[p[0]] = this
set p[0] = this
set trap = CreateUnit(who, TRAP_ID, createX, createY, degree)
call UnitApplyTimedLife(trap, TIMED_LIFE, GetDuration(level))
set x = GetUnitX(trap)
set y = GetUnitY(trap)
set own = who
set range = GetRange(level)
set damage = GetDamage(level)
set angle = degree*bj_DEGTORAD
set x0 = x + range*Cos(angle)
set y0 = y + range*Sin(angle)
set dum = Dummy.create(x0, y0 , degree)
call SetUnitFlyHeight(dum.unit, DUMMY_FLY_HEIGHT, 0.)
set sfx = AddSpecialEffectTarget(EFFECT_ON_DUMMY, dum.unit, "origin")
call SetUnitScale(dum.unit, SCALE, 0., 0.)
set light = AddLightningEx(LIGHTNING, true, x, y , TRAP_HEIGHT, x0, y0, GetUnitFlyHeight(dum.unit))
call SetLightningColor(light, RED, GREEN, BLUE, 1)
static if IS_TRAP_SELECTABLE then
static if IS_TRAP_INVULNERABLE then
call UnitAddAbility(trap, 'Avul')
endif
else
call UnitAddAbility(trap, 'Aloc')
endif
if (0 == p[this]) then
static if LIBRARY_TimerUtils then
call TimerStart(NewTimer(), TIMER_TIMEOUT, true, function thistype.callback)
else
call TimerStart(clock, TIMER_TIMEOUT, true, function thistype.callback)
endif
endif
return this
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DemoArcaneTrap initializer onInit
globals
private constant integer AID = 'A007'
endglobals
private function run takes nothing returns boolean
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real angle = GetRandomReal(0., 359.)
local integer level = GetUnitAbilityLevel(GetTriggerUnit(), AID)
call ArcaneTrap.create(GetTriggerPlayer(), x, y, angle, level)
return false
endfunction
private function check takes nothing returns boolean
if GetSpellAbilityId() == AID then
call run()
endif
return false
endfunction
private function onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function check))
//call RegisterSpellEffectEvent(AID, function run)
endfunction
endscope
//TESH.scrollpos=2
//TESH.alwaysfold=0
library LightningTrap/* v1.0.0.0
*************************************************************************************
*
* Creates a trap which focuses enemies within 500 range.
* Nearby corpses will explode and deal damage relative to their maximum life.
*
*************************************************************************************
*
* Credits
*
* To Nestharus
* -----------------------
*
* For Alloc
*
* To Vexorian
* -----------------------
*
* For TimerUtils
*
*
*************************************************************************************
*
* */ uses /*
*
* */ optional TimerUtils /* http://www.wc3c.net/showthread.php?t=101322
* */ optional Alloc /* -
*
************************************************************************************
*
* SETTINGS
*
*/
globals
/*
* It is not required to set the timer timeout to a really small
* value for this spell. 0.1 is a recommended value here.
*/
private constant real TIMEOUT = 0.1
/*
* The trap can only be invulnerable
* if it is selectable. Otherwise the code
* below will ignore IS_TRAP_INVULNERABLE.
*/
private constant boolean IS_TRAP_SELECTABLE = true
private constant boolean IS_TRAP_INVULNERABLE = false
/*
* Explosions fire with a cooldown in between.
*/
private constant real COOLDOWN_BETWEEN_EXPLOSIONS = 1.7
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
/*
* The effect on the trap each time a explosion takes place.
*/
private constant string EXPLOSION_ON_TRAP = "Abilities\\Weapons\\ChimaeraLightningMissile\\ChimaeraLightningMissile.mdl"
private constant string ATTACH_ON_TRAP = "origin"
/*
* The effect on living affected units.
*/
private constant string EXPLOSION_ON_UNIT = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
private constant string ATTACH_ON_UNIT = "chest"
/*
* The effect displayed on the corpse.
*/
private constant string EXPLOSION_ON_CORPSE = "Objects\\Spawnmodels\\Undead\\UndeadLargeDeathExplode\\UndeadLargeDeathExplode.mdl"
endglobals
native UnitAlive takes unit id returns boolean
//Place in the corresponding raw-code, based on the passed integer level
private function GetTrapByLevel takes integer level returns integer
if level == 1 then
return 'o000'
elseif level == 2 then
return 'o000'
else
return 'o000'
endif
endfunction
//The duration the trap lasts.
private constant function GetDuration takes integer level returns real
return 8. + (2.*level)
endfunction
//The aoe the trap searches for corpses
private constant function GetDetectionRange takes integer level returns real
return 400. + (50.*level)
endfunction
//The explosion aoe. Within this aoe units take damage.
private constant function GetExplosionRange takes integer level returns real
return 200. + (50.*level)
endfunction
//Each trap can fire a maximum number of explosions.
private constant function GetExplosions takes integer level returns integer
return 4 + (1*level)
endfunction
//Filter which corpses should be considered. Heroes are filtered out by default.
private constant function ExplosionFilter takes unit target returns boolean
return not IsUnitType(target, UNIT_TYPE_MECHANICAL)
endfunction
//The percent of maximum damage, which will be dealt as damage
//i.e: Footman has 100 maximum life --> 100*0.2 = 20.
private constant function GetDamageFactor takes integer level returns real
return 0.2 + (0.2*level)
endfunction
//Which units around the corpse should take damage
private function DamageFilter takes unit target, player who returns boolean
return UnitAlive(target) and IsUnitEnemy(target, who)
endfunction
struct LightningTrap extends array
implement optional Alloc
static if not LIBRARY_Alloc then
private static integer array recycler
endif
static if not LIBRARY_TimerUtils then
private static timer tmr = CreateTimer()
endif
private unit trap
private player owner
private real range
private real factor
private real radius
private real x
private real y
private integer counter
private real cooldown
private static group pick = CreateGroup()
private static group expl = CreateGroup()
private static integer array next
private static integer array prev
/*
* Heroes aren't considered as corpses,
* because they shouldn't be removed from the game.
*/
private static method basicFilter takes unit u returns boolean
return not UnitAlive(u) and (not IsUnitType(u, UNIT_TYPE_HERO))
endmethod
method destroy takes nothing returns nothing
static if LIBRARY_Alloc then
call this.deallocate()
else
set recycler[this] = recycler[0]
set recycler[0] = this
endif
call UnitApplyTimedLife(.trap, 'BTLF', 0.01)
set this.trap = null
set this.owner = null
endmethod
private static method callback takes nothing returns nothing
local thistype this = next[0]
local unit u
local unit c
local real x
local real y
local real damage
local boolean b = false
loop
/*
* Each trap can fire a maximum of
* corpse explosions.
*/
if UnitAlive(.trap) and (0 < .counter) then
/*
* There is a cooldown between two
* corpse explosions.
*/
if (0 >= .cooldown) then
call GroupEnumUnitsInRange(pick, .x, .y , .range, null)
loop
set u = FirstOfGroup(pick)
exitwhen u == null
call GroupRemoveUnit(pick, u)
if ExplosionFilter(u) and thistype.basicFilter(u) then
call GroupAddUnit(expl, u)
endif
endloop
call ForGroup(expl, function GroupPickRandomUnitEnum)
set c = FirstOfGroup(expl)
call GroupClear(expl)
if (c != null) then
set x = GetUnitX(c)
set y = GetUnitY(c)
set damage = GetUnitState(c, UNIT_STATE_MAX_LIFE)*factor
call GroupEnumUnitsInRange(pick, x, y, .radius, null)
loop
set u = FirstOfGroup(pick)
exitwhen u == null
call GroupRemoveUnit(pick, u)
if (DamageFilter(u, .owner)) then
call UnitDamageTarget(.trap, u, damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
call DestroyEffect(AddSpecialEffectTarget(EXPLOSION_ON_UNIT, u, ATTACH_ON_UNIT))
set b = true
endif
endloop
/*
* b confirms if the trap has hit any enemies.
* if not neither the corpse is removed nor the cooldown goes off.
*/
if b then
call RemoveUnit(c)
call DestroyEffect(AddSpecialEffect(EXPLOSION_ON_CORPSE, x, y))
call DestroyEffect(AddSpecialEffectTarget(EXPLOSION_ON_TRAP, .trap, ATTACH_ON_TRAP))
/*
* Decrease the maximum explosion counter
* and set the cooldown.
*/
set .counter = .counter - 1
set .cooldown = COOLDOWN_BETWEEN_EXPLOSIONS
set b = not b
endif
set c = null
endif
else
set .cooldown = .cooldown - TIMEOUT
endif
else
call this.destroy()
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
if (0 == next[0]) then
static if LIBRARY_TimerUtils then
call ReleaseTimer(GetExpiredTimer())
else
call PauseTimer(tmr)
endif
endif
endif
set this = next[this]
exitwhen 0 == this
endloop
endmethod
static method create takes player who, real x, real y, real angle, integer level returns thistype
static if LIBRARY_Alloc then
local thistype this = allocate()
else
local thistype this = recycler[0]
set recycler[0] = recycler[this]
endif
set next[this] = 0
set prev[this] = prev[0]
set next[prev[0]] = this
set prev[0] = this
set .owner = who
set .trap = CreateUnit(who, GetTrapByLevel(level), x, y, angle)
call UnitApplyTimedLife(.trap, 'BTLF', GetDuration(level))
set .range = GetDetectionRange(level)
set .radius = GetExplosionRange(level)
set .factor = GetDamageFactor(level)
set .counter = GetExplosions(level)
set .cooldown = COOLDOWN_BETWEEN_EXPLOSIONS
/*
* May not be passed in x and y due to pathing.
*/
set .x = GetUnitX(this.trap)
set .y = GetUnitY(this.trap)
static if IS_TRAP_SELECTABLE then
static if IS_TRAP_INVULNERABLE then
call UnitAddAbility(this.trap, 'Avul')
endif
else
call UnitAddAbility(this.trap, 'Aloc')
endif
if (0 == prev[this]) then
static if LIBRARY_TimerUtils then
call TimerStart(NewTimer(), TIMEOUT, true, function thistype.callback)
else
call TimerStart(tmr, TIMEOUT, true, function thistype.callback)
endif
endif
return this
endmethod
//Full credits to Nestharus
static if not LIBRARY_Alloc then
private static method onInit takes nothing returns nothing
local integer i = 0
set recycler[8191] = 0
loop
set recycler[i] = i + 1
exitwhen i == 8190
set i = i + 1
endloop
endmethod
endif
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DemoLightningTrap initializer onInit
globals
private constant integer AID = 'A008'
endglobals
private function run takes nothing returns boolean
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real angle = GetRandomReal(0., 359.)
local integer level = GetUnitAbilityLevel(GetTriggerUnit(), AID)
call LightningTrap.create(GetTriggerPlayer(), x, y, angle, level)
return false
endfunction
private function check takes nothing returns boolean
if GetSpellAbilityId() == AID then
call run()
endif
return false
endfunction
private function onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function check))
//call RegisterSpellEffectEvent(AID, function run)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
* Read Me
* ---------
*
* The Demo map is rather simple and boring, if you have interest and want to spice it up
* then create a nice demo map and send it to me.
* -- Please to not overdo it --
* 1. The map should not influence fps in any way ( doodads, destructables, etc)
* 2. The map size should be small
* 3. The map needs two camps, so i can code a small creep system similar to an aos
*
*/
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope map
globals
private real X = -1500
private real Y = -2280
private real X0 = 1177
private real Y0 = 1370
private unit HERO
endglobals
private struct preload extends array
static method sfx takes nothing returns nothing
call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\ChimaeraLightningMissile\\ChimaeraLightningMissile.mdl", 2300,-2900))
call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl", 2300,-2900))
call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\UndeadLargeDeathExplode\\UndeadLargeDeathExplode.mdl", 2300,-2900))
endmethod
endstruct
private struct xxx extends array
private static method spawn takes nothing returns nothing
local integer i = 0
local unit u
loop
exitwhen i == 4
set u = CreateUnit(Player(1), 'ugho', X, Y, 0)
call IssuePointOrder(u, "attack", X0, Y0)
set u = CreateUnit(Player(2), 'ugho', X0, Y0, 0)
call IssuePointOrder(u, "attack", X, Y)
set i = i + 1
endloop
set u = null
endmethod
private static method revive takes nothing returns boolean
local player p = GetTriggerPlayer()
local unit u
if p == Player(1) then
set u = CreateUnit(p, 'ugho', X, Y, 0)
call IssuePointOrder(u, "attack", X0, Y0)
elseif p == Player(2) then
set u = CreateUnit(p, 'ugho', X0, Y0, 0)
call IssuePointOrder(u, "attack", X, Y)
elseif GetTriggerUnit() == HERO then
call ReviveHero(HERO, 0,0, true)
endif
set u = null
set p = null
return false
endmethod
private static method reset takes nothing returns boolean
call ClearTextMessages()
call UnitResetCooldown(HERO)
call SetUnitState(HERO, UNIT_STATE_MANA, GetUnitState(HERO, UNIT_STATE_MAX_MANA))
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.revive)
call thistype.spawn()
set HERO = CreateUnit(Player(0), 'Uktl', 0,0,0)
call SetHeroLevel(HERO, 12, true)
call FogModifierStart(CreateFogModifierRect(Player(0), FOG_OF_WAR_VISIBLE, WorldBounds.world, false, false))
call TriggerRegisterPlayerEventEndCinematic(t, Player(0))
call TriggerAddCondition(t, Condition(function thistype.reset))
call BJDebugMsg("Press |cffdaa520ESC|r to reset cooldowns and refresh mana")
set t = null
call preload.sfx()
call AddSpecialEffectTarget("UI\\Feedback\\SelectionCircleEnemy\\SelectionCircleEnemy.mdx", HERO, "origin")
endmethod
endstruct
endscope
//TESH.scrollpos=11
//TESH.alwaysfold=0
/**************************************************************
*
* RegisterPlayerUnitEvent
* v5.1.0.1
* By Magtheridon96
*
* I would like to give a special thanks to Bribe, azlier
* and BBQ for improving this library. For modularity, it only
* supports player unit events.
*
* Functions passed to RegisterPlayerUnitEvent must either
* return a boolean (false) or nothing. (Which is a Pro)
*
* Warning:
* --------
*
* - Don't use TriggerSleepAction inside registered code.
* - Don't destroy a trigger unless you really know what you're doing.
*
* API:
* ----
*
* - function RegisterPlayerUnitEvent takes playerunitevent whichEvent, code whichFunction returns nothing
* - Registers code that will execute when an event fires.
* - function RegisterPlayerUnitEventForPlayer takes playerunitevent whichEvent, code whichFunction, player whichPlayer returns nothing
* - Registers code that will execute when an event fires for a certain player.
* - function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* - Returns the trigger corresponding to ALL functions of a playerunitevent.
*
**************************************************************/
library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
globals
private trigger array t
endglobals
function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
local integer i = GetHandleId(p)
local integer k = 15
if t[i] == null then
set t[i] = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
exitwhen k == 0
set k = k - 1
endloop
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing
local integer i = 16 * GetHandleId(p) + GetPlayerId(pl)
if t[i] == null then
set t[i] = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(t[i], pl, p, null)
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function GetPlayerUnitEventTrigger takes playerunitevent p returns trigger
return t[GetHandleId(p)]
endfunction
endlibrary