Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
library VorpalExtermination /* v1.0.0.8 by Doomlord
*************************************************************************************
*
* The Hero throws a magical shuriken that deals damage to all enemies it comes in contact with.
* If the shuriken comes in contact with an enemy hero or reaches its maximum range,
* a spinning glaive will be released for 5 seconds to deal damage in an AoE and slow enemies.
* Once the duration is up, the glaive will split into slicing blades that explode
* in a caustic finale after a short period.
*
*************************************************************************************
*
* Credits
*
* Dirac
* -----------------------
*
* Missile library
*
* Maker
* -----------------------
*
* TimedLightnings, FloatingTextArc library
*
* Garfield1337
* -----------------------
*
* UnitZ library
*
* Nestharus
* -----------------------
*
* Alloc, DummyCaster library
*
* PurgeandFire
* -----------------------
*
* SpecialEffectZ library
*
* Bribe
* -----------------------
*
* SpellEffectEvent library
*
* Infrisios
* -----------------------
*
* ArcaneGlaive_2.mdx
*
* WILL THE ALMIGHTY
* -----------------------
*
* EMPBomb.mdx
*
* Suselishe
* -----------------------
*
* Cyclon Explosion.mdx
*
*************************************************************************************
*
* */ uses /*
*
* */ Missile /* hiveworkshop.com/forums/jass-resources-412/system-missile-207854/
* */ SpecialEffectZ /* wc3jass.com/5007/snippet-addspecialeffectz/
* */ UnitZ /* hiveworkshop.com/forums/jass-resources-412/snippet-getterrainz-unitz-236942/
* */ Alloc /* hiveworkshop.com/forums/jass-resources-412/snippet-alloc-alternative-221493/
* */ TimedLightnings /* hiveworkshop.com/forums/spells-569/system-timed-lightnings-v1-0-1-1-a-205105/
* */ DummyCaster /* hiveworkshop.com/forums/jass-resources-412/snippet-dummy-caster-197087/
* */ DelayedDummyRecycler /* hiveworkshop.com/forums/submissions-414/snippet-delayeddummyrecycler-239327/
* */ optional FloatingTextArc /* hiveworkshop.com/forums/spells-569/arcing-floating-text-1-0-0-3-a-228710/
* */ optional SpellEffectEvent /* hiveworkshop.com/forums/jass-resources-412/snippet-spelleffectevent-187193/
*
************************************************************************************
*
* SETTINGS
*
*/
globals
// Ability raw code
private constant integer ABI_ID = 'A001'
// Slow ability raw code
private constant integer SLOW_ID = 'A002'
// Slow order id
private constant integer SLOW_ORDER_ID = 852075
// Height difference for missiles
private constant real HEIGHT_DIFFERENCE = 100.
// FIRST PHASE
// Primary missile model (throw phase)
private constant string PRIMARY_MISSILEFX = "Abilities\\Weapons\\GlaiveMissile\\GlaiveMissile.mdl"
// On collide model for main missile
private constant string PRIMARY_COLLIDEFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
// Primary attachment point
private constant string PRIMARY_ATTACHPOINT = "chest"
// Primary missile scaling
private constant real PRIMARY_MISSILE_SCALE = 1.5
// Area of Effect for throw phase
private constant real PRIMARY_AOE = 200.
// SECOND PHASE
// Secondary missile model (spin phase)
private constant string SECONDARY_MISSILEFX = "war3mapImported\\ArcaneGlaive_2.mdx"
// On collide model for spin phase
private constant string SECONDARY_COLLIDEFX = "Objects\\Spawnmodels\\Human\\HumanBlood\\HeroBloodElfBlood.mdl"
// Secondary attachment point
private constant string SECONDARY_ATTACHPOINT = "chest"
// Glaive expiration effect
private constant string SECONDARY_EXPFX = "war3mapImported\\Cyclon Explosion.mdx"
// Secondary missile scaling
private constant real SECONDARY_MISSILE_SCALE = 3.
// Glaive expiration time
private constant real EXPIRATION_TIME = 5.
/* Damage fraction for spin phase. The unit will be
damaged by main spell damage multiplied by SECONDARY_FRACTION */
private constant real SECONDARY_FRACTION = 0.25
// Damage fidelity for spin phase. Units will be damaged every DAMAGE_FIDELITY(s)
private constant real DAMAGE_FIDELITY = 0.5
// Area of Effect for spin phase
private constant real SECONDARY_AOE = 300.
// THIRD PHASE
// Tertiary missile model (spread phase)
private constant string TERTIARY_MISSILEFX = "Abilities\\Weapons\\SentinelMissile\\SentinelMissile.mdl"
// On collide model for spread phase
private constant string TERTIARY_COLLIDEFX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
// Tertiary attachment point
private constant string TERTIARY_ATTACHPOINT = "chest"
// Final explosion model
private constant string EXPLOSIONFX = "war3mapImported\\EMPBomb.mdx"
// Explosion hit model
private constant string EXPLOSION_HITFX = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
// Explosion hit attachment point
private constant string EXPLOSION_ATTACHPOINT = "origin"
// Bonus effect
private constant string BONUSFX = "Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl"
// Tertiary missile scaling
private constant real TERTIARY_MISSILE_SCALE = 1.5
// Glaive spread count
private constant integer SPREAD_COUNT = 12
/* Damage fraction for spread phase. The unit will be
damaged by main spell damage multiplied by TERTIARY_FRACTION */
private constant real TERTIARY_FRACTION = 0.2
// Glaive spread max range
private constant real SPREAD_MAX_RANGE = 400.
// Inactive time for spread glaives
private constant real INACTIVE_PERIOD = 1.5
// Area of Effect for spread phase slicing
private constant real TERTIARY_AOE = 200.
// Explosion AoE for spread phase
private constant real EXPLOSION_AOE = 300.
/* Some explosion effect needs scaling and
thus we need a special technique for it */
private constant boolean SPECIAL_EXPLOSION_FX_USAGE = true
// Explosion effect scaling. Only use this if the above boolean is true.
private constant real EXPLOSION_SCALE = 5.
// ENERGY GATHER EFFECT
// Effect model
private constant string ENERGY_GATHER_FX = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl"
// Effect model variant
private constant string ENERGY_GATHER_FX_VAR = "Abilities\\Weapons\\VengeanceMissile\\VengeanceMissile.mdl"
// Effect when lightning orbs reach the glaive
private constant string ENERGY_GATHER_FX_FINISH = "Abilities\\Spells\\Orc\\Purge\\PurgeBuffTarget.mdl"
/* Effect orbs spawn rate per second. There must be a remainder
of 0 from the division 60/ENERGY_GATHER_SPAWN_OFFSET */
private constant integer ENERGY_GATHER_SPAWN_RATE = 12
// Effect spawn offset
private constant real ENERGY_GATHER_SPAWN_OFFSET = 400.
// Effect orbs move speed
private constant real ENERGY_GATHER_SPEED = 900.
// DAMAGE CONFIGURATION
// SLICE DAMAGE
// Attack type
private constant attacktype SLICE_ATT = ATTACK_TYPE_HERO
// Damage type
private constant damagetype SLICE_DAM = DAMAGE_TYPE_NORMAL
// Weapon type
private constant weapontype SLICE_WEA = WEAPON_TYPE_METAL_HEAVY_SLICE
// EXPLOSION DAMAGE
// Attack type
private constant attacktype EXP_ATT = ATTACK_TYPE_NORMAL
// Damage type
private constant damagetype EXP_DAM = DAMAGE_TYPE_MAGIC
// Weapon type
private constant weapontype EXP_WEA = null
endglobals
/************************************************************************************
*
* END SETTINGS
*
*/
globals
private group g = CreateGroup()
private string array s
endglobals
// Primary missile speed
private constant function GetPrimarySpeed takes integer lvl returns real
return 1440.
endfunction
// Tertiary missile speed
private constant function GetTertiarySpeed takes integer lvl returns real
return 1120.
endfunction
// Main spell damage
private constant function GetDamage takes integer level returns real
return 50. + level*100.
endfunction
// Explosion damage
private constant function GetExplosionDamage takes integer level returns real
return 100. + level*50
endfunction
// Filter out some targets
private function FilterUnit takes unit u, player casterOwner returns boolean
return /*
*/ IsUnitEnemy(u, casterOwner) and /* Target is an enemy of caster
*/ not IsUnitType(u, UNIT_TYPE_DEAD) and /* Target is not dead
*/ not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and /* Target is not immune to magic
*/ not IsUnitType(u, UNIT_TYPE_STRUCTURE) /* Target is not a structure
*/
endfunction
// Filter target for glaive release
private function FilterActivationUnit takes unit u returns boolean
return /*
*/ IsUnitType(u, UNIT_TYPE_HERO) /* Target is a Hero
*/
endfunction
// Lightning settings - set lightning types for randomizer
private function LightningSettings takes nothing returns nothing
set s[0] = "AFOD"
set s[1] = "FORK"
set s[2] = "MBUR"
set s[3] = "SPLK"
set s[4] = "DRAL"
set s[5] = "DRAM"
endfunction
// Lightning type randomizer
private function LightningRandomizer takes nothing returns string
return s[GetRandomInt(0, 5)]
endfunction
// As usual, skip this part
private struct GlaiveSpread extends array
implement Alloc
private boolean b
private real timeCounter
private real x
private real y
private real z
private Missile m
static method onPeriod takes Missile m returns boolean
local thistype this = thistype(m.data)
local unit u
local unit v
if this.b then
// Is inactive period over?
if this.timeCounter >= INACTIVE_PERIOD then
call DestroyEffect(AddSpecialEffectZ(TERTIARY_MISSILEFX, m.impact.x, m.impact.y, m.impact.z))
static if SPECIAL_EXPLOSION_FX_USAGE then
set v = Dummy.create(m.impact.x, m.impact.y, 270).unit
call SetUnitScale(v, EXPLOSION_SCALE, 0, 0)
call SetUnitZ(v, m.impact.z)
call RecycleDummyDelayedEx(v, 3, AddSpecialEffectTarget(EXPLOSIONFX, v, "origin"), false)
set v = null
call DestroyEffect(AddSpecialEffectZ(ENERGY_GATHER_FX, m.impact.x, m.impact.y, m.impact.z))
else
call DestroyEffect(AddSpecialEffectZ(EXPLOSIONFX, m.impact.x, m.impact.y, m.impact.z))
endif
call GroupEnumUnitsInRange(g, m.x, m.y, EXPLOSION_AOE, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if FilterUnit(u, GetOwningPlayer(m.source)) then
call DestroyEffect(AddSpecialEffectTarget(EXPLOSION_HITFX, u, EXPLOSION_ATTACHPOINT))
call UnitDamageTarget(m.source, u, GetDamage(GetUnitAbilityLevel(m.source, ABI_ID)), false, false, EXP_ATT, EXP_DAM, EXP_WEA)
endif
call GroupRemoveUnit(g, u)
endloop
call this.deallocate()
return true
else
// Create lightning links to center
if this.timeCounter == 0 then
set bj_lastCreatedLightning = AddLightningEx(LightningRandomizer(), true, this.x, this.y, this.z, m.impact.x, m.impact.y, m.impact.z)
call TimedL.P2P(bj_lastCreatedLightning, INACTIVE_PERIOD, 1, 0)
call DestroyEffect(AddSpecialEffectZ(BONUSFX, m.impact.x, m.impact.y, m.impact.z))
endif
set this.timeCounter = this.timeCounter + .031250000
endif
endif
return false
endmethod
static method onFinish takes Missile m returns boolean
set thistype(m.data).b = true
// Stop the slicing blades
set m.speed = 0
return false
endmethod
static method onCollide takes Missile m, unit justHit returns boolean
if FilterUnit(justHit, GetOwningPlayer(m.source)) then
// Damage enemies and play some extra blood effects
call UnitDamageTarget(m.source, justHit, GetDamage(GetUnitAbilityLevel(m.source, ABI_ID))*TERTIARY_FRACTION, false, false, SLICE_ATT, SLICE_DAM, SLICE_WEA)
call DestroyEffect(AddSpecialEffectTarget(TERTIARY_COLLIDEFX, justHit, TERTIARY_ATTACHPOINT))
endif
return false
endmethod
implement MissileStruct
static method onActivate takes unit caster, real x, real y, real x1, real y1 returns thistype
local thistype this = thistype.allocate()
local real r = GetTerrainZ(x, y)
local integer i = GetUnitAbilityLevel(caster, ABI_ID)
set this.timeCounter = 0
set this.b = false
set this.x = x
set this.y = y
set this.z = GetTerrainZ(x, y) + HEIGHT_DIFFERENCE
set this.m = Missile.create(x, y, this.z, Atan2(y1 - y, x1 - x), SPREAD_MAX_RANGE, GetTerrainZ(x1, y1) + HEIGHT_DIFFERENCE)
set m.source = caster
set m.model = TERTIARY_MISSILEFX
set m.scale = TERTIARY_MISSILE_SCALE
set m.collision = TERTIARY_AOE
set m.speed = GetTertiarySpeed(i)/32
set m.data = this
call launch(m)
return this
endmethod
endstruct
private struct EnergyGatherFxInstance extends array
implement Alloc
private Missile m
private integer i
private real alphaStep
static method onFinish takes Missile m returns boolean
local unit v
if thistype(m.data).i == 0 then
call DestroyEffect(AddSpecialEffectZ(ENERGY_GATHER_FX, m.impact.x, m.impact.y, m.impact.z))
else
call DestroyEffect(AddSpecialEffectZ(ENERGY_GATHER_FX_VAR, m.impact.x, m.impact.y, m.impact.z))
endif
set v = Dummy.create(m.impact.x, m.impact.y, 270).unit
call SetUnitZ(v, m.impact.z)
call SetUnitScale(v, 1.25, 0, 0)
call RecycleDummyDelayedEx(v, 2, AddSpecialEffectTarget(ENERGY_GATHER_FX_FINISH, v, "origin"), false)
set v = null
call SetUnitVertexColor(m.dummy, 255, 255, 255, 255)
call thistype(m.data).deallocate()
return true
endmethod
static method onPeriod takes Missile m returns boolean
set thistype(m.data).alphaStep = thistype(m.data).alphaStep + 255/(ENERGY_GATHER_SPAWN_OFFSET/(ENERGY_GATHER_SPEED/32))
call SetUnitVertexColor(m.dummy, 255, 255, 255, R2I(thistype(m.data).alphaStep))
return false
endmethod
implement MissileStruct
static method onActivate takes real x, real y returns thistype
local thistype this = thistype.allocate()
local real r = GetTerrainZ(x, y) + HEIGHT_DIFFERENCE
local real s = GetRandomReal(0, 2*bj_PI)
local real x1 = x + ENERGY_GATHER_SPAWN_OFFSET*Cos(s)
local real y1 = y + ENERGY_GATHER_SPAWN_OFFSET*Sin(s)
set this.m = Missile.create(x1, y1, r, Atan2(y - y1, x - x1), ENERGY_GATHER_SPAWN_OFFSET, r)
set this.i = GetRandomInt(0, 1)
set this.alphaStep = 0
if this.i == 0 then
set m.model = ENERGY_GATHER_FX
set m.scale = 1
else
set m.model = ENERGY_GATHER_FX_VAR
set m.scale = 1.5
endif
set m.speed = ENERGY_GATHER_SPEED/32
set m.data = this
call launch(m)
return this
endmethod
endstruct
private struct EnergyGatherFx extends array
private integer counter
private real dur
private real x
private real y
implement CTL
implement CTLExpire
if this.dur <= 0 then
call this.destroy()
else
if this.counter == 0 or ModuloInteger(this.counter, 60/ENERGY_GATHER_SPAWN_RATE) == 0 and this.dur >= 0.5 then
call EnergyGatherFxInstance.onActivate(this.x, this.y)
endif
set this.counter = this.counter + 1
set this.dur = this.dur - .031250000
endif
implement CTLNull
implement CTLEnd
static method onStart takes real x, real y, real duration returns thistype
local thistype this = create()
set this.counter = 0
set this.dur = duration
set this.x = x
set this.y = y
return this
endmethod
endstruct
private struct GlaiveSpin extends array
implement Alloc
private real baseDamage
private real smallDamage
private real timeCounter
private Missile m
static method onPeriod takes Missile m returns boolean
local unit u
local thistype this = thistype(m.data)
local real i = 0
// Is the duration up yet?
if this.timeCounter >= EXPIRATION_TIME then
call DestroyEffect(AddSpecialEffectZ(SECONDARY_MISSILEFX, m.impact.x, m.impact.y, m.impact.z))
call DestroyEffect(AddSpecialEffectZ(SECONDARY_EXPFX, m.impact.x, m.impact.y, m.impact.z))
// Splits the glaive into slicing blades
loop
exitwhen i >= 2*bj_PI
call GlaiveSpread.onActivate(m.source, m.impact.x, m.impact.y, m.impact.x + SPREAD_MAX_RANGE*Cos(i), m.impact.y + SPREAD_MAX_RANGE*Sin(i))
set i = i + 2*bj_PI/SPREAD_COUNT
endloop
call this.deallocate()
return true
else
// Accumulate damage for the next damage instance
set this.smallDamage = this.smallDamage + this.baseDamage*.031250000
// Do we acquire enough damage yet?
if this.smallDamage >= this.baseDamage*DAMAGE_FIDELITY then
call GroupEnumUnitsInRange(g, m.x, m.y, SECONDARY_AOE, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if FilterUnit(u, GetOwningPlayer(m.source)) then
call DestroyEffect(AddSpecialEffectTarget(SECONDARY_COLLIDEFX, u, SECONDARY_ATTACHPOINT))
call UnitDamageTarget(m.source, u, this.smallDamage, false, false, SLICE_ATT, SLICE_DAM, SLICE_WEA)
call DummyCaster[SLOW_ID].castTarget(GetOwningPlayer(m.source), 10 - R2I((GetWidgetLife(u)/GetUnitState(u, UNIT_STATE_MAX_LIFE))*10), SLOW_ORDER_ID, u)
endif
call GroupRemoveUnit(g, u)
endloop
set this.smallDamage = 0
endif
set this.timeCounter = this.timeCounter + .031250000
endif
return false
endmethod
implement MissileStruct
static method onActivate takes unit caster, real x, real y returns thistype
local thistype this = thistype.allocate()
local real r = GetTerrainZ(x, y)
local integer i = GetUnitAbilityLevel(caster, ABI_ID)
set this.baseDamage = GetDamage(i)*SECONDARY_FRACTION
set this.timeCounter = 0
set this.smallDamage = 0
set this.m = Missile.create(x, y, r + HEIGHT_DIFFERENCE, 0, 1, r + HEIGHT_DIFFERENCE)
set m.source = caster
set m.model = SECONDARY_MISSILEFX
set m.scale = SECONDARY_MISSILE_SCALE
set m.speed = 0
set m.data = this
call EnergyGatherFx.onStart(x, y, EXPIRATION_TIME)
call launch(m)
return this
endmethod
endstruct
private struct GlaiveThrow extends array
implement Alloc
private unit caster
private Missile m
// Shuriken at max range, activate buzzsaw
static method onFinish takes Missile m returns boolean
call DestroyEffect(AddSpecialEffectZ(PRIMARY_MISSILEFX, m.impact.x, m.impact.y, m.impact.z))
call GlaiveSpin.onActivate(m.source, m.impact.x, m.impact.y)
call thistype(m.data).deallocate()
set thistype(m.data).caster = null
return true
endmethod
static method onCollide takes Missile m, unit justHit returns boolean
if FilterUnit(justHit, GetOwningPlayer(m.source)) then
call UnitDamageTarget(m.source, justHit, GetDamage(GetUnitAbilityLevel(m.source, ABI_ID)), false, false, SLICE_ATT, SLICE_DAM, SLICE_WEA)
call DestroyEffect(AddSpecialEffectTarget(PRIMARY_COLLIDEFX, justHit, PRIMARY_ATTACHPOINT))
// Hero collision. Release buzzsaw
if FilterActivationUnit(justHit) then
call DestroyEffect(AddSpecialEffectZ(PRIMARY_MISSILEFX, m.x, m.y, m.z))
call GlaiveSpin.onActivate(m.source, m.x, m.y)
call thistype(m.data).deallocate()
set thistype(m.data).caster = null
return true
endif
endif
return false
endmethod
implement MissileStruct
private static method create takes nothing returns thistype
local thistype this = thistype.allocate()
local integer i
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real x1
local real y1
local real a
set this.caster = GetTriggerUnit()
set i = GetUnitAbilityLevel(this.caster, ABI_ID)
set x1 = GetUnitX(this.caster)
set y1 = GetUnitY(this.caster)
set a = Atan2(y - y1, x - x1)
set this.m = Missile.create(x1 + 100*Cos(a), y1 + 100*Sin(a), GetUnitZ(this.caster) + HEIGHT_DIFFERENCE, a, SquareRoot((x - x1)*(x - x1) + (y - y1)*(y - y1)) - 100, GetTerrainZ(x, y) + HEIGHT_DIFFERENCE)
set m.source = this.caster
set m.speed = GetPrimarySpeed(i)/32
set m.model = PRIMARY_MISSILEFX
set m.collision = PRIMARY_AOE
set m.scale = PRIMARY_MISSILE_SCALE
set m.data = this
static if LIBRARY_FloatingTextArc then
call ArcingTextTag.create("|c00ECEC00 VORPAL EXTERMINATION!|r", this.caster)
endif
call launch(m)
return this
endmethod
static if not LIBRARY_SpellEffectEvent then
private static method onCast takes nothing returns boolean
if GetSpellAbilityId() == ABI_ID then
call thistype.create()
endif
return false
endmethod
endif
private static method onInit takes nothing returns nothing
local trigger t
static if LIBRARY_SpellEffectEvent then
call RegisterSpellEffectEvent(ABI_ID, function thistype.create)
else
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.onCast))
set t = null
endif
call LightningSettings()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Alloc /* v1.0.0.1
*************************************************************************************
*
* */uses/*
*
* */ ErrorMessage /* hiveworkshop.com/forums/submissions-414/snippet-error-message-239210/
*
************************************************************************************
*
* module Alloc
*
* static method allocate takes nothing returns thistype
* method deallocate takes nothing returns nothing
*
************************************************************************************/
module Alloc
private static integer array recycler
private static integer instanceCount = 0
static method allocate takes nothing returns thistype
local thistype this = recycler[0]
if (this == 0) then
debug call ThrowError(instanceCount == 8191, "Alloc", "allocate", "thistype", 0, "Overflow.")
set this = instanceCount + 1
set instanceCount = this
else
set recycler[0] = recycler[this]
endif
debug set recycler[this] = -1
return this
endmethod
method deallocate takes nothing returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "deallocate", "thistype", this, "Attempted To Deallocate Null Instance.")
set recycler[this] = recycler[0]
set recycler[0] = this
endmethod
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ErrorMessage /* v1.0.1.4
*************************************************************************************
*
* Issue THW Compliant Error Messages
*
************************************************************************************
*
* debug function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
* - In the event of an error the game will be permanently paused
*
* debug function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
*
************************************************************************************/
static if DEBUG_MODE then
private struct Fields extends array
static constant string COLOR_RED = "|cffff0000"
static constant string COLOR_YELLOW = "|cffffff00"
static string lastError = null
endstruct
private function Pause takes nothing returns nothing
call PauseGame(true)
endfunction
private function ThrowMessage takes string libraryName, string functionName, string objectName, integer objectInstance, string description, string errorType, string color returns nothing
local string str
local string color_braces = "|cff66FF99"
local string orange = "|cffff6600"
set str = "->\n-> " + color_braces + "{|r " + "Library" + color_braces + "(" + orange + libraryName + color_braces + ")"
if (objectName != null) then
if (objectInstance > 0) then
set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + " (|rinstance = " + orange + I2S(objectInstance) + color_braces + ") )" + "|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
else
set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + ")|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
endif
else
set str = str + "|r." + "Function" + color_braces + "(" + orange + functionName + color_braces + ")"
endif
set str = str + color_braces + " }|r " + "has thrown an exception of type " + color_braces + "(" + color + errorType + color_braces + ")|r."
set Fields.lastError = str + "\n->\n" + "-> " + color + description + "|r\n->"
endfunction
function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
if (Fields.lastError != null) then
set objectInstance = 1/0
endif
if (expression) then
call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Error", Fields.COLOR_RED)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
call TimerStart(CreateTimer(), 0, true, function Pause)
set objectInstance = 1/0
endif
endfunction
function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
if (Fields.lastError != null) then
set objectInstance = 1/0
endif
if (expression) then
call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Warning", Fields.COLOR_YELLOW)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
set Fields.lastError = null
endif
endfunction
endif
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Missile /* v2.0.1
*/uses/*
*/ CTL /* hiveworkshop.com/forums/jass-resources-412/snippet-constant-timer-loop-32-a-201381/
*/ AdvLoc /* hiveworkshop.com/forums/submissions-414/snippet-lacking-loc-209322/
*/ optional WorldBounds /* hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
*/ optional MissileRecycler /* hiveworkshop.com/forums/jass-resources-412/system-missilerecycler-206086/
Credits:
- emjlr3 for the deflect angle equation
- AceHart for the parabola equation
**********************************************************************/
globals
//***********************************************************************
// This dummy must use Vexorian's dummy model and it's movement type
// should be "Hover" if you want to correctly move over water, otherwise
// use "None". The dummy must also have Crow Form. If you don't have a
// dummy unit in your map then use the one MissileRecycler provides.
private constant integer DUMMY_RAW_CODE = 'n000'
endglobals
/**********************************************************************
*
* struct Missile
*
* static method create takes real originX, real originY, real originZ...
* ...real targetX, real targetY, real targetZ returns Missile
* - Missiles have the following values to be set by you.
* - real speed
* - real turn
* - real open / curve
* - real height / arc
* - real acceleration
* - real collision
* - unit target
* - unit source
* - string model
* - integer data
*
* real x
* real y
* real z
* - The missile's position
*
* real slide
* - The amount of distance it has covered.
* AdvLoc origin
* - The missile's origin Loc
* AdvLoc impact
* - Where the missile will aim to.
*
* method deflect takes real x, real y returns nothing
* - Deflects the missile from the target point, changing
* - its course.
*
* method bounce takes nothing returns nothing
* - Bounces the missile from its current Z position.
* - Useful when assigning targets to missiles that were
* - already active, it fixes the rough Z position change.
*
***********************************************************************
*
* (optional)
* static method onCollide takes Missile this, unit justHit returns boolean
* - Runs every time the missile collides with something.
* - If returns true the missile is destroyed.
*
* (optional)
* static method onPeriod takes Missile this returns boolean
* - Runs every period.
* - If returns true the missile is destroyed.
*
* (optional)
* static method onFinish takes Missile this returns boolean
* - Runs whenever the missile finishes its course.
* - If returns true the missile is destroyed.
*
* (optional)
* static method onMissile takes Missile this, Missile hit, real range returns boolean
* - Runs whenever the missile encounters another missile.
* - If returns true the missile is destroyed.
*
* (optional)
* static method onRemove takes Missile this returns nothing
* - Runs whenever the missile is deallocated.
*
* module MissileStruct
*
* static method launch takes Missile toLaunch returns nothing
*
***********************************************************************
*
* DISCLAIMER:
*
* - Missile's default owner is Player(15) and this is meant to
* - not be modifiable.
*
* - For curved missiles the "x" and "y" coordinates are only
* - correct in the moment of launch or impact, but during it's
* - air time they ignore the curve it has.
*
* - This system can support up to 600 proyectiles with complex
* - mathematics (curve, arc, collision) before it lags.
*
**********************************************************************/
struct MissileList extends array
implement LinkedList
endstruct
struct Missile extends array
//***********************************************************************
// Why LinkedList? In order to reach a high level of dynamism i'm basing
// this system on iterating through multiple linked lists, each struct
// has one and each struct iterates through it.
implement LinkedList
AdvLoc impact
AdvLoc origin
real slide
readonly real x
readonly real y
readonly real z
private real cA //current angle
private effect fx //effect
private string fP //model
private real dS
readonly unit dummy
readonly group unitsHit
boolean recycle
boolean wantDestroy
unit target
unit source
real collision
real height
real turn
real open
real damage
real speed
real acceleration
integer data
method operator model= takes string path returns nothing
call DestroyEffect(fx)
set fP=path
set fx=AddSpecialEffectTarget(path,dummy,"origin")
endmethod
method operator model takes nothing returns string
return fP
endmethod
method operator curve= takes real value returns nothing
set open=Tan(value)*origin.distance
endmethod
method operator curve takes nothing returns real
return Atan(open/origin.distance)
endmethod
method operator arc= takes real value returns nothing
set height=Tan(value)*origin.distance/4
endmethod
method operator arc takes nothing returns real
return Atan(4*height/origin.distance)
endmethod
method operator scale= takes real v returns nothing
call SetUnitScale(dummy,v,v,v)
set dS=v
endmethod
method operator scale takes nothing returns real
return dS
endmethod
static method createEx takes unit whichUnit, AdvLoc o, AdvLoc i returns thistype
local thistype this=allocate()
set source = null
set target = null
set acceleration = 0
set height = 0
set turn = 0
set open = 0
set unitsHit = CreateGroup()
set collision = 0
set recycle = false
set wantDestroy = false
set fP = ""
set x = o.x
set y = o.y
set z = o.z
set origin = o
set impact = i
set cA = origin.angle
set slide=0
set dummy=whichUnit
call MoveLocation(Loc.global,o.x,o.y)
call SetUnitFlyHeight(dummy,o.z-GetLocationZ(Loc.global),0)
call MissileList.base.insertNode(this)
return this
endmethod
static method createLoc takes AdvLoc o, AdvLoc i returns thistype
call AdvLoc.link(o,i)
static if LIBRARY_MissileRecycler then
return createEx(GetRecycledMissile(o.x,o.y,o.z,o.angle*bj_RADTODEG),o,i)
else
return createEx(CreateUnit(Player(15),DUMMY_RAW_CODE,o.x,o.y,o.angle*bj_RADTODEG),o,i)
endif
endmethod
static method create takes real ox, real oy, real oz, real a, real d, real iz returns thistype
local AdvLoc o = AdvLoc.create(ox,oy,oz)
local AdvLoc i = AdvLoc.create(ox+d*Cos(a),oy+d*Sin(a),iz)
call AdvLoc.link(o,i)
static if LIBRARY_MissileRecycler then
return createEx(GetRecycledMissile(o.x,o.y,o.z,o.angle*bj_RADTODEG),o,i)
else
return createEx(CreateUnit(Player(15),DUMMY_RAW_CODE,o.x,o.y,o.angle*bj_RADTODEG),o,i)
endif
endmethod
method bounce takes nothing returns nothing
call origin.move(x,y,z)
set slide=0
endmethod
method deflect takes real tx, real ty returns nothing
local real a = 2*Atan2(ty-y,tx-x)+bj_PI-cA
call impact.move(x+(origin.distance-slide)*Cos(a),y+(origin.distance-slide)*Sin(a),impact.z)
call this.bounce()
endmethod
method destroy takes nothing returns nothing
set wantDestroy=true
endmethod
method terminate takes nothing returns nothing
call DestroyEffect(fx)
call DestroyGroup(unitsHit)
set recycle=false
set fx=null
static if LIBRARY_MissileRecycler then
call RecycleMissile(dummy)
else
call RemoveUnit(dummy)
endif
call impact.unlock()
call origin.unlock()
call MissileList(this).removeNode()
call this.removeNode()
call this.deallocate()
endmethod
method move takes nothing returns nothing
local real a
local real d
local real s
local real h
local real tx
local real ty
local real ox
local real oy
local AdvLoc o
loop
exitwhen head
set o = origin
set ox = o.x
set oy = o.y
set h = height
if target!=null and GetUnitTypeId(target)!=0 then
call impact.move(GetUnitX(target),GetUnitY(target),GetUnitFlyHeight(target))
set a = Atan2(impact.y-y,impact.x-x)
set slide = origin.distance-SquareRoot((impact.x-x)*(impact.x-x)+(impact.y-y)*(impact.y-y))
else
set a = o.angle
set target = null
endif
if turn!=0 and not(Cos(cA-a)>=Cos(turn)) then
if Sin(a-cA)>=0 then
set cA = cA+turn
else
set cA = cA-turn
endif
else
set cA = a
endif
set d = o.distance
set s = slide+speed
set slide = s
call SetUnitFacing(dummy,cA*bj_RADTODEG)
set tx = x+speed*Cos(cA)
set ty = y+speed*Sin(cA)
set speed = speed + acceleration
set x = tx
set y = ty
if h!=0 or o.slope!=0 then
call MoveLocation(Loc.global,tx,ty)
set z = 4*h*s*(d-s)/(d*d)+o.slope*s+o.z
call SetUnitFlyHeight(dummy,z-GetLocationZ(Loc.global),0)
call SetUnitAnimationByIndex(dummy,R2I(Atan(origin.slope)-Atan((8*h*s-4*d*h)/(d*d))*bj_RADTODEG)+90)
endif
if open!=0 then
set a = 4*open*s*(d-s)/(d*d)
set tx = tx+a*Cos(cA+1.57)
set ty = ty+a*Sin(cA+1.57)
call SetUnitFacing(dummy,(cA+Atan(-(8*open*s-4*d*open)/(d*d)))*bj_RADTODEG)
endif
static if LIBRARY_WorldBounds then
if tx>WorldBounds.maxX or tx<WorldBounds.minX or ty>WorldBounds.maxY or ty<WorldBounds.minY then
call destroy()
else
call SetUnitX(dummy,tx)
call SetUnitY(dummy,ty)
endif
else
call SetUnitX(dummy,tx)
call SetUnitY(dummy,ty)
endif
if s>=d then
set recycle = true
endif
set this = next
endloop
endmethod
endstruct
globals
private integer ACTIVE = 0
private integer SIZE = 0
private trigger FIRE = CreateTrigger()
private integer array STACK
private integer array INSTANCES
private TimerGroup32 array TIMER
private Missile array NODE
endglobals
//***********************************************************************
// This function runs periodically. Can you see the trigger evaluation
// at the end? If you've read T32 then you know exactly what it does.
// The loop above is for cleaning up, the SIZE variable keeps track of
// how many instances have been deallocated by the user, if higher than
// 0 then some of them need to be removed. STACK[SIZE] stores the value
// of the deallocated instances.
private function Execute takes nothing returns nothing
loop
exitwhen SIZE==0
set ACTIVE=ACTIVE-1
set SIZE=SIZE-1
set INSTANCES[STACK[SIZE]]=INSTANCES[STACK[SIZE]]-1
if INSTANCES[STACK[SIZE]]==0 then
call TIMER[STACK[SIZE]].stop()
if ACTIVE==0 then
return
endif
endif
endloop
call TriggerEvaluate(FIRE)
endfunction
//***********************************************************************
// Adds a new instance to the given struct index (This system attaches
// indexes to every struct you implement MissileStruct to) If the amount
// of INSTANCES[index] was 0 then it adds the struct's iterate method to
// the FIRE trigger for it's evaluation. ACTIVE keeps track of all
// allocated instances, if it was 0 that means the timer isn't even
// running yet, it needs to be started.
private function StartPeriodic takes integer index returns nothing
if INSTANCES[index]==0 then
call TIMER[index].start()
endif
set ACTIVE=ACTIVE+1
set INSTANCES[index]=INSTANCES[index]+1
endfunction
//***********************************************************************
// Adds the struct's index to the stack to clear it in the Execute
// function above.
private function StopPeriodic takes integer index returns nothing
set STACK[SIZE]=index
set SIZE=SIZE+1
endfunction
module MissileStruct
private static method missileTerminate takes Missile this returns nothing
static if thistype.onRemove.exists then
call onRemove(this)
endif
call this.terminate()
call StopPeriodic(thistype.typeid)
endmethod
static method unpin takes Missile this returns nothing
call this.removeNode()
call StopPeriodic(thistype.typeid)
endmethod
static if thistype.onMissile.exists then
private static method onMissileLoop takes Missile this returns nothing
local Missile node = MissileList.base
local real ox = this.x
local real oy = this.y
loop
set node = node.next
exitwhen MissileList(node).head
loop
exitwhen node.head
if node!=this and onMissile(this,node,SquareRoot((ox-node.x)*(ox-node.x)+(oy-node.y)*(oy-node.y))) then
call missileTerminate(this)
endif
set node = MissileList(node).next
endloop
endloop
endmethod
endif
//***********************************************************************
// First it takes the struct's first instance, which is the next to the
// head (NODE[thistype.typeid].next) and starts iterating through it until it hits
// the head again. Then checks if the missile is marked for recycling,
// if so it runs the methods and destroys the missile.
private static method missileIterate takes nothing returns nothing
local unit u
local Missile this = NODE[thistype.typeid].next
call this.move()
loop
exitwhen this.head
if this.wantDestroy then
static if thistype.onFinish.exists then
call thistype.onFinish(this)
endif
call missileTerminate(this)
else
if this.recycle then
static if thistype.onCollide.exists then
static if thistype.onFinish.exists then
if this.target==null then
if thistype.onFinish(this) then
call missileTerminate(this)
else
set this.recycle = false
endif
elseif thistype.onCollide(this,this.target) then
call missileTerminate(this)
else
set this.recycle = false
endif
else
if this.target==null then
call missileTerminate(this)
elseif thistype.onCollide(this,this.target) then
call missileTerminate(this)
else
set this.recycle = false
endif
endif
else
static if thistype.onFinish.exists then
if thistype.onFinish(this) then
call missileTerminate(this)
else
set this.recycle = false
endif
else
call missileTerminate(this)
endif
endif
else
static if thistype.onCollide.exists then
if this.collision!=0 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup,this.x,this.y,this.collision,null)
loop
set u = FirstOfGroup(bj_lastCreatedGroup)
exitwhen u==null
if not(IsUnitInGroup(u,this.unitsHit)) and u!=this.target and thistype.onCollide(this,u) then
call missileTerminate(this)
endif
call GroupAddUnit(this.unitsHit,u)
call GroupRemoveUnit(bj_lastCreatedGroup,u)
endloop
endif
endif
endif
endif
static if thistype.onMissile.exists then
call onMissileLoop(this)
endif
static if thistype.onPeriod.exists then
if thistype.onPeriod(this) then
call missileTerminate(this)
endif
endif
set this = this.next
endloop
set u=null
endmethod
static method launch takes Missile this returns nothing
call StartPeriodic(thistype.typeid)
call NODE[thistype.typeid].insertNode(this)
endmethod
private static method onInit takes nothing returns nothing
set NODE[thistype.typeid] = Missile.createNode()
set TIMER[thistype.typeid] = TimerGroup32.create(function thistype.missileIterate)
endmethod
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitIndexer /* v4.0.2.8
*************************************************************************************
*
* 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 = 'A000'
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 method operator enabled takes nothing returns boolean
return IsTriggerEnabled(q)
endmethod
static method operator enabled= takes boolean b returns nothing
if (b) then
call DisableTrigger(q)
call DisableTrigger(l)
else
call EnableTrigger(q)
call EnableTrigger(l)
endif
endmethod
private static method onEnter takes nothing returns boolean
local unit Q=GetFilterUnit()
local integer i
local integer d=o
if (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=0
//TESH.alwaysfold=0
library Event
//2.0.0.1
/////////////////////////////////////////////////////////////////////////
//function CreateEvent takes nothing returns integer
//function TriggerRegisterEvent takes trigger t, integer ev returns nothing
//function RegisterEvent takes boolexpr c, integer ev returns nothing
//function FireEvent takes 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 WorldBounds
//struct WorldBounds extends array
//static readonly rect world
// same as GetWorldBounds()
//static readonly region worldRegion
// contains world for triggers
//static readonly real maxX
//static readonly real maxY
//static readonly real minX
//static readonly real minY
//static readonly real centerX
//static readonly real centerY
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX=GetRectMaxX(world)
set maxY=GetRectMaxY(world)
set minX=GetRectMinX(world)
set minY=GetRectMinY(world)
set centerX=(maxX+minX)/2
set centerY=(minY+maxY)/2
set worldRegion=CreateRegion()
call RegionAddRect(worldRegion,world)
endmethod
endmodule
struct WorldBounds extends array
readonly static real maxX
readonly static real maxY
readonly static real minX
readonly static real minY
readonly static real centerX
readonly static real centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library LinkedListModule /* v2.3.1
Easy implementation of linked lists into structs.
***********************************************************************
*
* module LinkedList
*
* - Implement at the top of your struct, must extend array
*
* thistype next
* thistype prev
* boolean head
*
* readonly static thistype base
* - Precreated head, useful for non-dynamic lists.
*
* static method allocate takes nothing returns thistype
* method deallocate takes nothing returns nothing
*
* static method createNode takes nothing returns thistype
* - Allocates a new node pointing towards itself.
* - These nodes are considered "heads" therefore it's head
* - boolean member is set to true.
* method insertNode takes thistype toInsert returns thistype
* - Inserts the instance before the node.
* method removeNode takes nothing returns nothing
* - Removes the node from the list.
* method clearNode takes nothing returns nothing
* - Deallocates all the instances within the node's range.
* method flushNode takes nothing returns nothing
* - Clears and deallocates the node.
*
* module LinkedListLite
* - Only has the members and the allocation methods.
* - To be used with the provided textmacros.
*
* textmacro LINKED_LIST_HEAD takes node
* - Turns the node into a head.
* textmacro LINKED_LIST_INSERT takes node, toInsert
* - Inserts the instance before the node.
* textmacro LINKED_LIST_REMOVE takes node
* - Removes the node from the list.
* textmacro LINKED_LIST_CLEAR takes node
* - Deallocates all the instances within the node's range.
* textmacro LINKED_LIST_FLUSH takes node
* - Clears and deallocates the node.
* textmacro LINKED_LIST_MERGE takes nodeA, nodeB
* - Merges two lists together (Don't merge loose nodes!)
*
**********************************************************************/
module LinkedListLite
private static integer instanceCount = 0
thistype next
thistype prev
boolean head
static method allocate takes nothing returns thistype
local thistype this = thistype(0).prev
if this==0 then
debug if instanceCount==8190 then
debug call BJDebugMsg("[LinkedList] Error: attempted to allocate too many instances.")
debug return 0
debug endif
set instanceCount = instanceCount+1
return instanceCount
endif
set thistype(0).prev = prev
return this
endmethod
method deallocate takes nothing returns nothing
set this.prev=thistype(0).prev
set thistype(0).prev=this
set this.head=false
endmethod
endmodule
module LinkedList
implement LinkedListLite
static method operator base takes nothing returns thistype
return 8190
endmethod
static method createNode takes nothing returns thistype
local thistype this=allocate()
//! runtextmacro LINKED_LIST_HEAD("this")
return this
endmethod
method clearNode takes nothing returns nothing
//! runtextmacro LINKED_LIST_CLEAR("this")
endmethod
method flushNode takes nothing returns nothing
//! runtextmacro LINKED_LIST_FLUSH("this")
endmethod
method insertNode takes thistype toInsert returns nothing
//! runtextmacro LINKED_LIST_INSERT("this","toInsert")
endmethod
method removeNode takes nothing returns nothing
//! runtextmacro LINKED_LIST_REMOVE("this")
endmethod
private static method onInit takes nothing returns nothing
set thistype(8190).next = 8190
set thistype(8190).prev = 8190
set thistype(8190).head = true
endmethod
static if DEBUG_MODE then
method print takes nothing returns nothing
local string s=""
local thistype exit=this
loop
set s=s+I2S(this)
set this = next
exitwhen this==exit
set s = s+" - "
endloop
call BJDebugMsg("[ "+s+" ]")
endmethod
endif
endmodule
//! textmacro LINKED_LIST_HEAD takes node
set $node$.next = this
set $node$.prev = this
set $node$.head = true
//! endtextmacro
//! textmacro LINKED_LIST_CLEAR takes node
if $node$!=$node$.next then
set $node$.next.prev = thistype(0).prev
set thistype(0).prev = $node$.prev
set $node$.next = $node$
set $node$.prev = $node$
endif
//! endtextmacro
//! textmacro LINKED_LIST_FLUSH takes node
set $node$.next.prev = thistype(0).prev
set thistype(0).prev = $node$
set $node$.head = false
//! endtextmacro
//! textmacro LINKED_LIST_INSERT takes node, toInsert
set $node$.prev.next = $toInsert$
set $toInsert$.prev = $node$.prev
set $node$.prev = $toInsert$
set $toInsert$.next = $node$
//! endtextmacro
//! textmacro LINKED_LIST_REMOVE takes node
set $node$.prev.next = $node$.next
set $node$.next.prev = $node$.prev
//! endtextmacro
//! textmacro LINKED_LIST_MERGE takes nodeA, nodeB
set $nodeA$.next.prev = $nodeB$.prev
set $nodeB$.prev.next = $nodeA$.next
set $nodeA$.next = $nodeB$
set $nodeB$.prev = $nodeA$
//! endtextmacro
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Loc /* v2.1.0
Replacement of the Location native.
***********************************************************************
*
* struct Loc
*
* readonly real x
* readonly real y
* - The Loc's position in the XY grid.
* readonly real z
* - The Loc's total height (including ground z)
*
*
* static method create takes real x, real y, real z returns Loc
* - Creates a new Loc with the given coordinates.
* method lock takes nothing returns nothing
* - Locks the instance, preventing it from being
* - deallocating when unlocked
* method unlock takes nothing returns nothing
* - Attempts to deallocate the instance, wont happen if
* - it's still being used.
*
* method move takes real x, real y, real z returns nothing
* - Assigns the Loc new coordinates.
*
**********************************************************************/
struct Loc extends array
private static integer array r
private static integer ic = 0
readonly static location global = Location(0,0)
readonly real x
readonly real y
readonly real z
//*********************************************************************
// Lock counters: a way to keep track of how many times a Loc has been
// locked, starts counting from 1. Unlocking drops the counters by 1,
// if it reaches 0 the instance is deallocated.
private integer lc
method move takes real sx, real sy, real sz returns nothing
call MoveLocation(global,sx,sy)
set x = sx
set y = sy
set z = sz+GetLocationZ(global)
endmethod
static method create takes real sx, real sy, real sz returns thistype
local thistype this = r[0]
if this==0 then
set ic = ic+1
set this = ic
else
set r[0] = r[this]
endif
call this.move(sx,sy,sz)
set lc = 1
return this
endmethod
method lock takes nothing returns nothing
set lc = lc+1
endmethod
/* idea brought by Nestharus */
method unlock takes nothing returns nothing
set lc = lc-1
if lc==0 then
set r[this] = r[0]
set r[0] = this
endif
endmethod
endstruct
endlibrary
//TESH.scrollpos=27
//TESH.alwaysfold=0
library AdvLoc /* v1.0.0
*/uses/*
*/ Loc /* hiveworkshop.com/forums/submissions-414/snippet-lacking-loc-209322/
Advanced Loc handling
***********************************************************************
*
* struct AdvLoc
* - Has the exact same API as Loc with extended functionality
*
* static method link takes Loc a, Loc b returns nothing
* - Creates a link between the two Locs, linked Locs keep
* - data relative to the other Loc's position such as...
*
* readonly real angle
* readonly real distance
* readonly real slope
* - Each Loc knows the angle/distance/slope from itself
* - to it's linked partner. Updates automatically.
*
* method lock takes nothing returns nothing
* - Locks the instance, preventing it from being
* - deallocating when unlocked
* method unlock takes nothing returns nothing
* - Attempts to deallocate the instance, wont happen if
* - it's still being used.
*
**********************************************************************/
struct AdvLoc extends array
readonly thistype ref
readonly real angle
readonly real distance
readonly real slope
//*********************************************************************
// Lock counters: a way to keep track of how many times a Loc has been
// locked, starts counting from 1. Unlocking drops the counters by 1,
// if it reaches 0 the instance is deallocated.
private integer lc
method operator x takes nothing returns real
return Loc(this).x
endmethod
method operator y takes nothing returns real
return Loc(this).y
endmethod
method operator z takes nothing returns real
return Loc(this).z
endmethod
static method create takes real ox, real oy, real oz returns thistype
local thistype this = Loc.create(ox,oy,oz)
set ref = this
return this
endmethod
private static method math takes thistype a, thistype b returns nothing
set a.angle = Atan2(b.y-a.y,b.x-a.x)
set a.distance = SquareRoot((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y))
set a.slope = (b.z-a.z)/a.distance
set b.angle = a.angle+bj_PI
set b.distance = a.distance
set b.slope = -a.slope
endmethod
static method link takes AdvLoc a, AdvLoc b returns nothing
set a.ref = b
set b.ref = a
call math(a,b)
endmethod
method unlink takes nothing returns nothing
if lc==0 then
set ref.ref = ref
set ref = this
endif
endmethod
method lock takes nothing returns nothing
set lc = lc+1
call Loc(this).lock()
endmethod
method unlock takes nothing returns nothing
set lc = lc-1
if lc==0 then
set ref.ref = ref
set ref = this
endif
call Loc(this).unlock()
endmethod
method move takes real nx, real ny, real nz returns nothing
call Loc(this).move(nx,ny,nz)
if this!=ref then
call math(this,ref)
endif
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library CTL /* v1.2.0.1
*************************************************************************************
*
* CTL or Constant Timer Loop provides a loop for constant merged timers of timeout .03125
*
* Similar to T32 but pauses timer when no structs have instances and removes structs
* from timer trigger when those structs have no instances.
*
* This can also create new timers after destroying a previous timer and generates less
* code in the module. It also generates no triggers so long as the module is implemented
* at the top of the struct.
*
************************************************************************************
*
* module CTL
*
* Allows creation/destruction of timers in a struct. Provides instancing of those timers.
*
* - static method create takes nothing returns thistype
* - method destroy takes nothing returns nothing
*
* CTL (optional)
* local variables, code before running any timers
* CTLExpire (not optional)
* timer code
* CTLNull (optional)
* null any locals, runs after all timers
* CTLEnd (not optional)
*
* module CT32
*
* Converts struct into a timer group. Allows the timer group to be started and stopped.
* Instancing and looping through active timers is up to the user.
*
* - static method start takes nothing returns nothing
* - static method stop takes nothing returns nothing
*
* CT32 (not optional)
* timer code
* CT32End (not optional)
*
* struct TimerGroup32 extends array
*
* Allows for the creation of timer groups. Timer instancing and looping is entirely up
* to the user.
*
* - static method create takes code func returns thistype
* - method destroy takes nothing returns nothing
* - method start takes nothing returns nothing
* - method stop takes nothing returns nothing
*
************************************************************************************/
globals
private integer tgc = 0 //timer group count
private integer array tgr //timer group recycler
private integer ic=0 //instance count
private integer tc=0 //timer count
private integer array rf //root first
private integer array n //next
private integer array p //previous
private integer array th //timer head
private integer array ns //next stack
private trigger t=CreateTrigger()
private timer m=CreateTimer()
private triggercondition array ct
private conditionfunc array rc
private boolean array e32 //enabled
private integer array i32r //ct32 recycler
private integer i32cr = 0 //ct32 count recycler
private boolean array ir32 //is recycling
private boolean array id32 //is destroying
endglobals
private function E takes nothing returns nothing
local integer i=ns[0]
set ns[0]=0
loop
exitwhen 0==i
if (0==p[i]) then
if (0==n[i]) then
call TriggerRemoveCondition(t,ct[th[i]])
set ct[th[i]]=null
set tc=tc-1
set rf[th[i]]=0
else
set rf[th[i]]=n[i]
set p[n[i]]=0
endif
else
set p[n[i]]=p[i]
set n[p[i]]=n[i]
endif
set n[i]=n[0]
set n[0]=i
set i=ns[i]
endloop
loop
exitwhen 0 == i32cr
set i32cr = i32cr - 1
set i = i32r[i32cr]
if (not e32[i]) then
call TriggerRemoveCondition(t,ct[i])
set ct[i] = null
if (id32[i]) then
set tgr[i] = tgr[0]
set tgr[0] = i
set id32[i] = false
set e32[i] = false
set ir32[i] = false
endif
endif
endloop
if (0==tc) then
call PauseTimer(m)
else
call TriggerEvaluate(t)
endif
endfunction
private function CT takes integer r returns integer
local integer i
local integer f
if (0==n[0]) then
set i=ic+1
set ic=i
else
set i=n[0]
set n[0]=n[i]
endif
set th[i]=r
set ns[i]=-1
set f=rf[r]
if (0==f) then
set n[i]=0
set p[i]=0
set rf[r]=i
set ct[r]=TriggerAddCondition(t,rc[r])
//set ct[r] = null
if (0==tc) then
call TimerStart(m,.031250000,true,function E)
endif
set tc=tc+1
else
set n[i]=f
set p[i]=0
set p[f]=i
set rf[r]=i
endif
return i
endfunction
private function DT takes integer t returns nothing
debug if (0>ns[t]) then
set ns[t]=ns[0]
set ns[0]=t
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"TIMER LOOP ERROR: ATTEMPT TO DESTROY NULL TIMER")
debug endif
endfunction
private function A takes code c returns integer
local integer i = tgr[0]
if (0 == i) then
set i = tgc + 1
set tgc = i
else
set tgr[0] = tgr[i]
endif
set rc[i]=Condition(c)
return i
endfunction
private function A32 takes integer i returns nothing
if (not e32[i]) then
if (not ir32[i] and not id32[i]) then
set ct[i] = TriggerAddCondition(t, rc[i])
endif
if (0 == tc) then
call TimerStart(m,.031250000,true,function E)
endif
set tc = tc + 1
set e32[i] = true
endif
endfunction
private function SR32 takes integer i returns nothing
if (e32[i]) then
if (not ir32[i] and not id32[i]) then
set i32r[i32cr] = i
set i32cr = i32cr + 1
set ir32[i] = true
endif
set e32[i] = false
set tc = tc - 1
endif
endfunction
private function DT32 takes integer i returns nothing
if (not id32[i]) then
if (not ir32[i]) then
set ir32[i] = true
set tc = tc - 1
set i32r[i32cr] = i
set i32cr = i32cr + 1
set e32[i] = false
endif
set id32[i] = true
endif
endfunction
private keyword r
private keyword e
module CTL
static integer rctl32
static method create takes nothing returns thistype
return CT(rctl32)
endmethod
method destroy takes nothing returns nothing
call DT(this)
endmethod
static method ectl32 takes nothing returns boolean
local thistype this=rf[rctl32]
endmodule
module CTLExpire
implement CTL
loop
exitwhen 0==this
endmodule
module CTLNull
set this=n[this]
endloop
endmodule
module CTLEnd
implement CTLNull
return false
endmethod
private static method onInit takes nothing returns nothing
set rctl32 = A(function thistype.ectl32)
endmethod
endmodule
module CT32
static integer rctl32
static method ectl32 takes nothing returns boolean
endmodule
module CT32End
return false
endmethod
static method start takes nothing returns nothing
call A32(rctl32)
endmethod
static method stop takes nothing returns nothing
call SR32(rctl32)
endmethod
private static method onInit takes nothing returns nothing
set rctl32 = A(function thistype.ectl32)
endmethod
endmodule
struct TimerGroup32 extends array
static method create takes code c returns thistype
return A(c)
endmethod
method destroy takes nothing returns nothing
call DT32(this)
endmethod
method start takes nothing returns nothing
call A32(this)
endmethod
method stop takes nothing returns nothing
call SR32(this)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitZ /* v1.0.0.0
********************************************************************
*
* */uses/*
* */ GetTerrainZ /*
* */optional/*
* */ AutoFly /* hiveworkshop.com/forums/jass-resources-412/snippet-autofly-unitindexer-version-195563/
*
* function GetUnitZ takes unit whichUnit returns real
* function SetUnitZ takes unit whichUnit, real z returns real
*
********************************************************************/
function GetUnitZ takes unit u returns real
return GetTerrainZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
endfunction
function SetUnitZ takes unit u, real z returns nothing
call SetUnitFlyHeight(u, z - GetTerrainZ(GetUnitX(u), GetUnitY(u)), 0)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library GetTerrainZ /* v1.0.0.0
********************************************************************
*
* function GetTerrainZ takes real x, real y returns real
*
********************************************************************/
globals
private constant location L = Location(0, 0)
endglobals
function GetTerrainZ takes real x, real y returns real
call MoveLocation(L, x, y)
return GetLocationZ(L)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library SpecialEffectZ /* v1.0.0.0
*******************************************************************
*
* Allows you to add a special effect with a Z value.
*
*******************************************************************
*
* function AddSpecialEffectZ takes string model, real x, real y, real z returns effect
*
*******************************************************************/
globals
private destructable platform
private effect zEffect
endglobals
function AddSpecialEffectZ takes string model, real x, real y, real z returns effect
set platform = CreateDestructableZ('OTip', x, y, z, 0, 1, 0)
set zEffect = AddSpecialEffect(model, x, y)
call RemoveDestructable(platform)
return zEffect
endfunction
endlibrary
//TESH.scrollpos=51
//TESH.alwaysfold=0
/******************************************************************************
*
* TIMED LIGHTNINGS by Maker v1.0.1.1
*
* Allows the creation of lightnings with expiration timer.
* Supports:
* o Fading lightnings in and out
* o Attaching to units
* o Attaching to points
* o Linear movement in x-, y- and z-axes
*
*
* Methods
*
* P2U
* From a static point attached to a unit
* static method P2U takes lightning l, unit t, real time, real x1, real y1, real z1, real z2, real startAlpha, real endAlpha returns nothing
*
* The lightning, target unit, duration, origin x, origin y, origin z, end z
*
*
* P2UEx
* From a moving point attached to a unit
* static method P2UEx takes lightning l, unit a, real t, real zu, real x1, real y1, real z1, real x2, real y2, real z2, real startAlpha, real endAlpha returns nothing
*
* The lightning, target unit, duration, target z, origin start x, origin start y, origin start z, origin end x, origin end y, origin end z
*
* U2P
* From attached to a unit to a static point
* static method U2P takes lightning l, unit s, real t, real x1, real y1, real x2, real y2, real z1, real z2, real startAlpha, real endAlpha returns nothing
*
* The lightning, source unit, duration, origin x, origin y, point x , point y, source z, point z
*
* U2PEx
* From attached to a unit to a moving point
* static method U2PEx takes lightning l, unit a, real t, real zu, real x1, real y1, real z1, real x2, real y2, real z2, real startAlpha, real endAlpha returns nothing
*
* The lightning, source unit, duration, source z, point start x, point start y, point start z, point end x, point end y, point end z
*
* U2U
* From attached to a unit to attached to a unit
* static method U2U takes lightning l, unit s, unit t, real time, real z1, real z2, real startAlpha, real endAlpha returns nothing
*
* The lightning, source unit, target unit, duration, source z, target z
*
* P2P
* From a static point to a static point
* static method P2P takes lightning l, real t, real startAlpha, real endAlpha returns nothing
*
* The lightning, duration
*
* P2PEx
* From a moving point to a moving point
* static method P2PEx takes lightning l, real t, real x1, real y1, real z1, real x2, real y2, real z2, real x3, real y3, real z3, real x4, real y4, real z4, real startAlpha, real endAlpha returns nothing
*
* The lightning, duration, origin start x, origin start y, origin start z, origin end x, origin end y, origin end z, target start x, target start y, target start z, target end x, target end y, target end z
*
*
* Alpha values are between 1 and 0. 1 is fully visible, 0 is transparent.
*
*******************************************************************************/
library TimedLightnings
globals
private constant real TO = 0.03125000 // Update interval
private integer CT = 0 // Lightning count
private timer TMR = CreateTimer()
private location loc = Location(0,0)
endglobals
struct TimedL extends array
lightning l
real av // aplha value
real da // transparency change rate
real x1
real x2
real y1
real y2
real z1
real z2
real dx1
real dy1
real dz1
real dx2
real dy2
real dz2
unit s // source
unit t // target
integer time // how many ticks, time
integer next // next node
integer prev // previous node
boolean moves
private static integer rlast = 0 // previous created
private static thistype first // first node
private static integer ic = 0
private static integer ir = 0
private thistype rn
private static thistype dat
private static thistype dat2
private static thistype dat3
private static method destroyL takes nothing returns nothing
/*-Link previous node with next one-*/
set dat3 = dat2.prev
set dat3.next = dat2.next
/*-----Set new last created node----*/
if dat2 == rlast then
set rlast = dat3
endif
/*-Link next node with previous one-*/
set dat3 = dat2.next
set dat3.prev = dat2.prev
/*--------Set new first node--------*/
if dat2 == first then
set first = dat3
endif
call DestroyLightning(dat2.l)
set CT = CT - 1
if CT == 0 then
call PauseTimer(TMR)
endif
set dat2.rn=ir
set ir=dat2
endmethod
private static method looping takes nothing returns nothing
local real z1
local real z2
set dat = first
loop
set z1 = 0
set z2 = 0
set dat.time = dat.time - 1
if dat.da != 0 then
set dat.av = dat.av - dat.da
call SetLightningColor(dat.l, 1, 1, 1, dat.av)
endif
if dat.s == null then
if dat.dx1 != 0 then
set dat.x1 = dat.x1 + dat.dx1
endif
if dat.dy1 != 0 then
set dat.y1 = dat.y1 + dat.dy1
endif
if dat.dz1 != 0 then
set dat.z1 = dat.z1 + dat.dz1
endif
else
set dat.x1 = GetUnitX(dat.s)
set dat.y1 = GetUnitY(dat.s)
set z1 = GetUnitFlyHeight(dat.s)
endif
if dat.t == null then
if dat.dx2 != 0 then
set dat.x2 = dat.x2 + dat.dx2
endif
if dat.dy2 != 0 then
set dat.y2 = dat.y2 + dat.dy2
endif
if dat.dz2 != 0 then
set dat.z2 = dat.z2 + dat.dz2
endif
else
set dat.x2 = GetUnitX(dat.t)
set dat.y2 = GetUnitY(dat.t)
set z2 = GetUnitFlyHeight(dat.t)
endif
if dat.moves then
call MoveLocation(loc, dat.x1, dat.y1)
set z1 = GetLocationZ(loc) + dat.z1 + z1
call MoveLocation(loc, dat.x2, dat.y2)
set z2 = GetLocationZ(loc) + dat.z2 + z2
call MoveLightningEx(dat.l, true, dat.x1, dat.y1, z1, dat.x2, dat.y2, z2)
endif
if dat.time == 0 then
set dat2 = dat
set dat = dat.next
call destroyL()
else
set dat = dat.next
endif
exitwhen dat == 0
endloop
endmethod
private static method InitAdd takes nothing returns nothing
/* Add node to list, make this the last on list */
if rlast != 0 then
set dat2 = rlast
set dat2.next = dat
endif
/* Link this with previous node */
set dat.prev = rlast
/* Make this the last created node */
set rlast = dat
set CT = CT + 1
if CT == 1 then
/* Make this the first node */
set first = dat
call TimerStart(TMR, TO, true, function thistype.looping)
endif
endmethod
private static method Recycle takes nothing returns nothing
if 0==ir then
set ic=ic+1
set dat=ic
else
set dat=ir
set ir=dat.rn
endif
endmethod
static method P2U takes lightning l, unit t, real time, real x1, real y1, real z1, real z2, real startAlpha, real endAlpha returns nothing
local thistype this
call Recycle()
set this = dat
set .x1 = x1
set .y1 = y1
set .z1 = z1
set .z2 = z2
set .s = null
set .t = t
set .next = 0 // Nodes are added to the end of the list, there is no next node
set .l = l
set .time = R2I(time/TO) // Calculates how many loops does the lightning lasts
set .av = startAlpha
set .da = (startAlpha-endAlpha)*TO/time // Transparency change speed
set .moves = true
call InitAdd()
endmethod
static method U2P takes lightning l, unit s, real t, real x1, real y1, real x2, real y2, real z1, real z2, real startAlpha, real endAlpha returns nothing
local thistype this
call Recycle()
set this = dat
set .x1 = x1
set .y1 = y1
set .x2 = x2
set .y2 = y2
set .z1 = z1
set .z2 = z2
set .s = s
set .t = null
set .next = 0
set .l = l
set .time = R2I(t/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*TO/t
set .moves = true
call InitAdd()
endmethod
static method U2U takes lightning l, unit s, unit t, real time, real z1, real z2, real startAlpha, real endAlpha returns nothing
local thistype this
call Recycle()
set this = dat
set .z1 = z1
set .z2 = z2
set .s = s
set .t = t
set .next = 0
set .l = l
set .time = R2I(time/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*TO/time
set .moves = true
call InitAdd()
endmethod
static method P2P takes lightning l, real t, real startAlpha, real endAlpha returns nothing
local thistype this
call Recycle()
set this = dat
set .s = null
set .t = null
set .next = 0
set .l = l
set .time = R2I(t/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*TO/t
set .moves = false
call InitAdd()
endmethod
static method P2UEx takes lightning l, unit a, real t, real zu, real x1, real y1, real z1, real x2, real y2, real z2, real startAlpha, real endAlpha returns nothing
local thistype this
local real n = TO/t
call Recycle()
set this = dat
set .x1 = x1
set dx1 = (x2-x1)*n
set .y1 = y1
set dy1 = (y2-y1)*n
set .z1 = z1
set dz1 = (z2-z1)*n
set .z2 = zu
set .s = null
set .t = a
set .next = 0
set .l = l
set .time = R2I(t/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*n
set .moves = true
call InitAdd()
endmethod
static method U2PEx takes lightning l, unit a, real t, real zu, real x1, real y1, real z1, real x2, real y2, real z2, real startAlpha, real endAlpha returns nothing
local thistype this
local real n = TO/t
call Recycle()
set this = dat
set .x2 = x1
set .dx2 = (x2-x1)*n
set .y2 = y1
set .dy2 = (y2-y1)*n
set .z2 = z1
set .dz2 = (z2-z1)*n
set .z1 = zu
set .s = a
set .t = null
set .next = 0
set .l = l
set .time = R2I(t/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*n
set .moves = true
call thistype.InitAdd()
endmethod
static method P2PEx takes lightning l, real t, real x1, real y1, real z1, real x2, real y2, real z2, real x3, real y3, real z3, real x4, real y4, real z4, real startAlpha, real endAlpha returns nothing
local thistype this
local real n = TO/t
call Recycle()
set this = dat
set .x1 = x1
set .x2 = x3
set .y1 = y1
set .y2 = y3
set .z1 = z1
set .z2 = z3
set .dx1 = (x2-x1)*n
set .dy1 = (y2-y1)*n
set .dz1 = (z2-z1)*n
set .dx2 = (x4-x3)*n
set .dy2 = (y4-y3)*n
set .dz2 = (z4-z3)*n
set .s = null
set .t = null
set .next = 0
set .l = l
set .time = R2I(t/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*n
set .moves = true
call InitAdd()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DummyCaster /* v2.0.0.2
*************************************************************************************
*
* Dummy caster for casting spells
*
* Spells must have 0 cooldown, 92083 range, and cost 0 mana. Spells must be instant and
* can't share the same order as other spells on the dummy caster.
*
*************************************************************************************
*
* */uses/*
* */ optional UnitIndexer /* hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
*
************************************************************************************
* SETTINGS
*/
globals
constant integer UNITS_DUMMY_CASTER = 'n001'
/*************************************************************************************
*
* PLAYER_OWNER
*
* Owner of dummy caster
*
*************************************************************************************/
private constant player PLAYER_OWNER = Player(15)
endglobals
/*
************************************************************************************
*
* Dummy at position 32256,32256
*
* struct DummyCaster extends array
*
* method cast takes player castingPlayer, integer abilityLevel, integer order, real x, real y returns boolean
* - call DummyCaster[abilityId].cast(...)
* method castTarget takes player castingPlayer, integer abilityLevel, integer order, widget t returns boolean
* - call DummyCaster[abilityId].castTarget(...)
* method castPoint takes player castingPlayer, integer abilityLevel, integer order, real x, real y returns boolean
* - call DummyCaster[abilityId].castPoint(...)
*
************************************************************************************/
globals
private unit u
endglobals
private module N
private static method onInit takes nothing returns nothing
static if LIBRARY_UnitIndexer then
set UnitIndexer.enabled=false
set u=CreateUnit(PLAYER_OWNER,UNITS_DUMMY_CASTER,0,0,0)
set UnitIndexer.enabled=true
else
set u=CreateUnit(PLAYER_OWNER,UNITS_DUMMY_CASTER,0,0,0)
endif
call SetUnitPosition(u,32256,32256)
endmethod
endmodule
struct DummyCaster extends array
implement N
private static method prep takes integer a, player p, integer l returns nothing
call UnitAddAbility(u, a)
if (1 < l) then
call SetUnitAbilityLevel(u, a, l)
endif
if (null != p) then
call SetUnitOwner(u, p, false)
endif
endmethod
private static method finish takes integer a returns nothing
call SetUnitOwner(u, PLAYER_OWNER, false)
call UnitRemoveAbility(u, a)
endmethod
method cast takes player p, integer level, integer order, real x, real y returns boolean
local boolean b
call SetUnitX(u, x)
call SetUnitY(u, y)
call prep(this, p, level)
set b = IssueImmediateOrderById(u,order)
call finish(this)
call SetUnitPosition(u, 32256, 32256)
return b
endmethod
method castTarget takes player p, integer level, integer order, widget t returns boolean
local boolean b
call prep(this, p, level)
set b = IssueTargetOrderById(u,order,t)
call finish(this)
return b
endmethod
method castPoint takes player p, integer level, integer order, real x, real y returns boolean
local boolean b
call prep(this, p, level)
set b = IssuePointOrderById(u,order,x,y)
call finish(this)
return b
endmethod
endstruct
endlibrary
//TESH.scrollpos=497
//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 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 = 'n000'
/*
* 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=84
//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=99
//TESH.alwaysfold=0
library DelayedDummyRecycler /* v1.0.0.7
*************************************************************************************
*
* Delay dummy recycling for a Dummy. This is created as an extension for Nestharus' Dummy
* library since it does not have a feature that scales special effects' death animation.
*
* All delayed effects will be resolved before the dummy is recycled.
*
*************************************************************************************
*
* Credits
*
* Nestharus
* -----------------------
*
* Dummy, Alloc
*
* Vexorian
* -----------------------
*
* TimerUtils
*
* Jesus4Lyf & PurgeandFire
* -----------------------
*
* Stack Safety
*
*
*************************************************************************************
*
* Function
* -----------------------
*
* function RecycleDummyDelayed takes Dummy dummy, real timeout, effect fx, boolean fxDead returns nothing
*
* Description
* -----------------------
*
* Delay the recycling of a Dummy.
* Use this function instead of Dummy.destroy()
*
* Takes
* -----------------------
*
* Dummy dummy
* - The target Dummy
*
* real timeout
* - The delay time before recycling is executed
*
* effect fx
* - The effect currently attached to the dummy
*
* boolean fxDead
* - Set to true if you want to play the death animation of the effect
*
*************************************************************************************
*
* Function
* -----------------------
*
* function RecycleDummyDelayedEx takes unit dummy, real timeout, effect fx, boolean fxDead returns nothing
*
* Description
* -----------------------
*
* Delay the recycling of a Dummy.
* For those who prefer to work with units.
* Use this function instead of Dummy.destroy()
*
* Takes
* -----------------------
*
* unit dummy
* - The target dummy unit
*
* real timeout
* - The delay time before recycling is executed
*
* effect fx
* - The effect currently attached to the dummy
*
* boolean fxDead
* - Set to true if you want to play the death animation of the effect
*
*************************************************************************************
*
* */ uses /*
*
* */ Alloc /* hiveworkshop.com/forums/jass-resources-412/snippet-alloc-alternative-221493/
* */ Dummy /* hiveworkshop.com/forums/jass-resources-412/system-dummy-213908/
* */ TimerUtils /* wc3c.net/showthread.php?t=101322
*
************************************************************************************/
globals
private integer array stackLevel
endglobals
private struct DelayedDummyRecycler extends array
implement Alloc
private Dummy dum
private effect sfx
private static method onExpire takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
call SetUnitScale(this.dum.unit, 1., 0, 0)
call SetUnitVertexColor(this.dum.unit, 255, 255, 255, 255)
call SetUnitFlyHeight(this.dum.unit, 0., 0.)
call SetUnitTimeScale(this.dum.unit, 1.)
if this.sfx != null then
call DestroyEffect(this.sfx)
set this.sfx = null
endif
set stackLevel[this.dum] = stackLevel[this.dum] - 1
if stackLevel[this.dum] == 0 then
call this.dum.destroy()
endif
call ReleaseTimer(t)
call this.deallocate()
set t = null
endmethod
static method create takes Dummy dummy, real timeout, effect fx, boolean fxDead returns thistype
local thistype this = thistype.allocate()
local timer t = NewTimer()
set this.dum = dummy
set this.sfx = fx
if fxDead then
call DestroyEffect(this.sfx)
set this.sfx = null
endif
set stackLevel[this.dum] = stackLevel[this.dum] + 1
call SetTimerData(t, this)
call TimerStart(t, timeout, false, function thistype.onExpire)
set t = null
return this
endmethod
endstruct
function RecycleDummyDelayed takes Dummy dummy, real timeout, effect fx, boolean fxDead returns nothing
call DelayedDummyRecycler.create(dummy, timeout, fx, fxDead)
endfunction
function RecycleDummyDelayedEx takes unit dummy, real timeout, effect fx, boolean fxDead returns nothing
call DelayedDummyRecycler.create(Dummy[dummy], timeout, fx, fxDead)
endfunction
endlibrary
//TESH.scrollpos=24
//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
//TESH.scrollpos=0
//TESH.alwaysfold=0
//============================================================================
// SpellEffectEvent
// - Version 1.1.0.0
//
// API
// ---
// RegisterSpellEffectEvent(integer abil, code onCast)
//
// Requires
// --------
// RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
// Optional
// --------
// Table: hiveworkshop.com/forums/showthread.php?t=188084
//
library SpellEffectEvent requires RegisterPlayerUnitEvent, optional Table
//============================================================================
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable ht = InitHashtable()
endif
static method onCast takes nothing returns nothing
static if LIBRARY_Table then
call TriggerEvaluate(.tb.trigger[GetSpellAbilityId()])
else
call TriggerEvaluate(LoadTriggerHandle(.ht, 0, GetSpellAbilityId()))
endif
endmethod
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set .tb = Table.create()
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
//============================================================================
private struct S extends array
implement M
endstruct
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
static if LIBRARY_Table then
if not S.tb.handle.has(abil) then
set S.tb.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(S.tb.trigger[abil], Filter(onCast))
else
if not HaveSavedHandle(S.ht, 0, abil) then
call SaveTriggerHandle(S.ht, 0, abil, CreateTrigger())
endif
call TriggerAddCondition(LoadTriggerHandle(S.ht, 0, abil), Filter(onCast))
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
// Arcing Text Tag v1.0.0.3 by Maker
library FloatingTextArc
globals
private constant real SIZE_MIN = 0.014 // Minimum size of text
private constant real SIZE_BONUS = 0.010 // Text size increase
private constant real TIME_LIFE = 1.0 // How long the text lasts
private constant real TIME_FADE = 0.8 // When does the text start to fade
private constant real Z_OFFSET = 30 // Height above unit
private constant real Z_OFFSET_BON = 30 // How much extra height the text gains
private constant real VELOCITY = 1.5 // How fast the text move in x/y plane
private constant real ANGLE = bj_PI/2 // Movement angle of the text. Does not apply if
// ANGLE_RND is true
private constant boolean ANGLE_RND = true // Is the angle random or fixed
private timer TMR = CreateTimer()
endglobals
struct ArcingTextTag extends array
private texttag tt
private real as // angle, sin component
private real ac // angle, cos component
private real ah // arc height
private real t // time
private real x // origin x
private real y // origin y
private string s // text
private static integer array next
private static integer array prev
private static integer array rn
private static integer ic = 0 // Instance count
private static method update takes nothing returns nothing
local thistype this=next[0]
local real p
loop
set p = Sin(bj_PI*.t)
set .t = .t - 0.03125
set .x = .x + .as
set .y = .y + .ac
call SetTextTagPos(.tt, .x, .y, Z_OFFSET + Z_OFFSET_BON * p)
call SetTextTagText(.tt, .s, SIZE_MIN + SIZE_BONUS * p)
if .t <= 0 then
set .tt = null
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
set rn[this] = rn[0]
set rn[0] = this
if next[0]==0 then
call PauseTimer(TMR)
endif
endif
set this = next[this]
exitwhen this == 0
endloop
endmethod
public static method create takes string s, unit u returns thistype
local thistype this = rn[0]
static if ANGLE_RND then
local real a = GetRandomReal(0, 2*bj_PI)
else
local real a = ANGLE
endif
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set next[this] = 0
set prev[this] = prev[0]
set next[prev[0]] = this
set prev[0] = this
set .s = s
set .x = GetUnitX(u)
set .y = GetUnitY(u)
set .t = TIME_LIFE
set .as = Sin(a)*VELOCITY
set .ac = Cos(a)*VELOCITY
set .ah = 0.
if IsUnitVisible(u, GetLocalPlayer()) then
set .tt = CreateTextTag()
call SetTextTagPermanent(.tt, false)
call SetTextTagLifespan(.tt, TIME_LIFE)
call SetTextTagFadepoint(.tt, TIME_FADE)
call SetTextTagText(.tt, s, SIZE_MIN)
call SetTextTagPos(.tt, .x, .y, Z_OFFSET)
endif
if prev[this] == 0 then
call TimerStart(TMR, 0.03125, true, function thistype.update)
endif
return this
endmethod
endstruct
endlibrary