Name | Type | is_array | initial_value |
demInt | integer | No | |
demLoc | location | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope FrozenSpellpack
/*
* BANSGEE QUEEN SPELLPACK
* v2.0
*
* This spellpack consists of 4 active spells
* They are Cold Addict, Frostwave, Frost
* Phase, and Frozen Fate (ultimate).
* Their codes are packed into one library
* means that they are requiring each other.
*
* !This spellpack requires JNGP to work!
*
* External Dependencies:
* (Required)
* - CTL
* - IsTerrainWalkable
* - IsUnitCorpse
* - WorldBounds
* - UnitIndexer
*
* (Optional)
* - SpellEffectEvent
* - AutoFly
*
* How to install:
* - Install and configure all external
* dependecies properly.
* - Copy all abilities (UD), units (UD), and
* buffs at Object Editor into your map.
* - Copy this trigger into your map.
* - Configure the spells correctly.
*
* Credits:
* - Nestharus
* - Bribe
* - Cokemonkey11
* - Anitarf
* - Vexorian
* - Magtheridon96
*
*
* CONFIGURATION
*
* Configuration is separated into several
* parts. Each part is reserved for one spell.
*/
/* A. Global */
globals
/* Dummy unit's rawcode at Object Editor */
private constant integer DUMMY_ID = 'h000'
/* General decay time for all created sfx */
private constant real SFX_DECAY_TIME = 2.0
endglobals
/* B. Slow Effect */
private module SlowData
/* Slow ability's rawcode at Object Editor */
static constant integer SPELL_ID = 'A001'
/* Slow buff's rawcode at Object Editor */
static constant integer BUFF_ID = 'B001'
/* Slow order id */
static constant integer SLOW_ORDER = 852096 /* thunderclap */
/* Attached sfx on slow targets */
static constant string SLOW_SFX = "Abilities\\Spells\\Other\\FrostDamage\\FrostDamage.mdl"
static constant string SLOW_SFX_PT = "chest"
/* Duration is stackable */
static constant boolean STACKABLE = true
/* Will reset the duration if not stacked */
static constant boolean RESETABLE = false
/* The higher, the safer. But just leave it */
static constant real BUFF_SAFETY = 100.0
endmodule
/* C. Freeze Effect */
private module FreezeData
/* Freeze ability's rawcode at Object Editor */
static constant integer SPELL_ID = 'A000'
/* Freeze buff's rawcode at Object Editor */
static constant integer BUFF_ID = 'B000'
/* Freeze order id */
static constant integer FREEZE_ORDER = 852127 /* stomp */
/* Attached sfx on freeze targets */
static constant string FREEZE_SFX = "Abilities\\Spells\\Undead\\FreezingBreath\\FreezingBreathTargetArt.mdl"
static constant string FREEZE_SFX_PT = "origin"
/* Duration is stackable */
static constant boolean STACKABLE = false
/* Will reset the duration if not stacked */
static constant boolean RESETABLE = true
/* The higher, the safer. But just leave it */
static constant real BUFF_SAFETY = 100.0
endmodule
/*
* COLD ADDICT
* Inflicts frost magic at a target, slowing
* it's movement and attack rate, and stopping
* any mana regeneration. All damages taken
* from caster's spell will be amplified.
*/
private module ColdAddictData
/* Main ability's rawcode at Object Editor */
static constant integer SPELL_ID = 'A003'
/* Attached sfx on targets */
static constant string TARGET_SFX = "Abilities\\Spells\\Items\\AIob\\AIobTarget.mdl"
static constant string TARGET_SFX_PT = "overhead"
/* Damage amplification amount is stackable */
static constant boolean STACKABLE_BUFF = true
/* Duration is stackable */
static constant boolean STACKABLE_DUR = false
/* Will reset the duration if not stacked */
static constant boolean RESETABLE = true
/* Damage amplification amount */
static constant method damage takes integer l returns real
return -0.05 + 0.15 * l
endmethod
/* Buff duration on normal units */
static constant method durationNormal takes integer l returns real
return 15.0
endmethod
/* Buff duration on hero units */
static constant method durationHero takes integer l returns real
return 5.0
endmethod
endmodule
/*
* FROSTWAVE
* Sends a lance of ice shards wave to the
* target point, dealing damage to land units
* in a line and slowing them for a short
* duration.
*/
private module FrostwaveData
/* Main ability's rawcode at Object Editor */
static constant integer SPELL_ID = 'A005'
/* Total of created missiles on every cast */
static constant integer SHARD_COUNT = 23
/* Normal height z for every missile */
static constant real LAUNCH_Z = 64.0
/* Initial speed of every missile */
static constant real SPEED_MIN = 20.0
/* Maximum speed of every missile */
static constant real SPEED_MAX = 40.0
/* Acceleration rate of every missile */
static constant real ACCELERATION = 0.25
/* Turning rate of every missile */
static constant real TURN_RATE = 12.5 * bj_DEGTORAD
/* Missile model path */
static constant string MISSILE_PATH = "Abilities\\Weapons\\LichMissile\\LichMissile.mdl"
/* Attached sfx on targets */
static constant string TARGET_SFX = "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl"
static constant string TARGET_SFX_PT = "origin"
/* Dealt damage configuration */
static constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
static constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_COLD
static constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
/* Max distance from missile to hits a target */
static constant method aoe takes integer l returns real
return 128.0
endmethod
/* Dealt damage amount */
static constant method damage takes integer l returns real
return 20.0 + 60.0 * l
endmethod
/* Travel distance of every missile */
static constant method distance takes integer l returns real
return 1000.0
endmethod
/* Slow duration for normal units */
static constant method durationNormal takes integer l returns real
return 4.0
endmethod
/* Slow duration for hero units */
static constant method durationHero takes integer l returns real
return 1.325
endmethod
/* Configure the targets, by default it's unable to hit structures and magic immune */
static constant method filter takes unit u, player p returns boolean
return not(IsUnitAlly(u, p) or IsUnitType(u, UNIT_TYPE_FLYING) or IsUnitType(u, UNIT_TYPE_MECHANICAL))
endmethod
endmodule
/*
* FROST PHASE
* Instantly vanishes to the target point.
* Leaving ice explosion behind and at the
* target point. Freezes nearby enemy units
* for a short duration and deals minor damage
*/
private module FrostPhaseData
/* Main ability's rawcode at Object Editor */
static constant integer SPELL_ID = 'A004'
/* How often the spell will check for terrain's pathability */
static constant real ACCURACY = 20.0
/* Explosion sfx */
static constant real EXPLODE_SIZE = 2.0
static constant string EXPLODE_SFX = "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl"
/* Only damage once for each target */
static constant boolean DAMAGE_ONCE = false
/* Dealt damage configuration */
static constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
static constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_COLD
static constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
/* Dealt damage amount */
static constant method amount takes integer l returns real
return 20.0 + 20.0 * l
endmethod
/* Max range from the center of explosion to hit a target */
static constant method AoE takes integer l returns real
return 300.0
endmethod
/* Max teleport distance */
static constant method range takes integer l returns real
return 200.0 + 200.0 * l
endmethod
/* Freeze duration for normal units */
static constant method durationNormal takes integer l returns real
return 1.7 + 0.65 * l
endmethod
/* Freeze duration for hero units */
static constant method durationHero takes integer l returns real
return 0.9 + 0.5 * l
endmethod
/* Configure the targets, by default it's unable to hit structures and magic immune */
static constant method filter takes unit u, player p returns boolean
return not(IsUnitAlly(u, p) or IsUnitType(u, UNIT_TYPE_MECHANICAL))
endmethod
endmodule
/*
* FROZEN FATE
* Brings nearby corpses back to life as a
* muntant. Mutant has Frost Attack ability
* which will slows their victim down on
* every attack.
* Behind the scene, this ability is not
* actually reviving unit as other unit but
* removing old unit and creating new unit
* So keep warned.
*/
private module FrozenFateData
/* Main ability's rawcode at Object Editor */
static constant integer SPELL_ID = 'A002'
/* Summoned unit's rawcode at Object Editor */
static constant integer SUMMON_ID = 'u001'
/* Timed life buff's rawcode at Object Editor */
static constant integer BUFF_ID = 'BTLF'
/* Created sfx on missile impact */
static constant string IMPACT_SFX = "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl"
/* Missile model's file path */
static constant string MISSILE_SFX = "Abilities\\Spells\\Undead\\Possession\\PossessionMissile.mdl"
static constant real MISSILE_SIZE = 1.0
/* Movement rate of each missile */
static constant real MISSILE_SPEED = 15.0
/* Normal height z of each missile */
static constant real MISSILE_Z = 0.0
/* Vertical arc of missiles */
static constant real V_ARC_MIN = 0.1
static constant real V_ARC_MAX = 0.4
/* Horizontal arc of missiles */
static constant real H_ARC_MIN = 0.1
static constant real H_ARC_MAX = 0.4
/* Maximum distance to the corpse to successfully revive it */
static constant real TOLERATION = 100.0
/* Maximum summoned unit count */
static constant method count takes integer l returns integer
return 12
endmethod
/* Summoned unit lifespan */
static constant method lifespan takes integer l returns real
return 60.0
endmethod
/* Maximum distance from caster for corpses to be revived */
static constant method aoe takes integer l returns real
return 900.0
endmethod
/* Configure the targeted corpse */
static constant method filter takes unit u, player p returns boolean
return not(IsUnitType(u, UNIT_TYPE_STRUCTURE) or IsUnitType(u, UNIT_TYPE_MECHANICAL) or IsUnitType(u, UNIT_TYPE_HERO) or IsUnitType(u, UNIT_TYPE_SUMMONED))
endmethod
endmodule
/*
* END OF CONFIGURATION
* ================================================== */
native UnitAlive takes unit id returns boolean
globals
private player PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
endglobals
/* Function that returns distance between coordinates */
private function getDistance takes real x, real y, real xt, real yt returns real
return SquareRoot((xt - x) * (xt - x) + (yt - y) * (yt - y))
endfunction
/* Function that returns angle between coordinates */
private function getAngle takes real x, real y, real xt, real yt returns real
return Atan2(yt - y, xt - x)
endfunction
/* Function that checks whether given coordinate is in map bound or not */
private constant function isInBound takes real x, real y returns boolean
return x > WorldBounds.minX and x < WorldBounds.maxX and y > WorldBounds.minY and y < WorldBounds.maxY
endfunction
private struct Slow extends array
implement SlowData
unit target
real duration
effect sfx
static unit dummy
static group group = CreateGroup()
static boolean array isAffected
static thistype array index
implement CTLExpire
set .duration = .duration - .03125
if .duration <= 0 or not UnitAlive(.target) then
call DestroyEffect(.sfx)
call UnitRemoveAbility(.target, BUFF_ID)
set isAffected[GetUnitUserData(.target)] = false
call destroy()
set .sfx = null
set .target = null
endif
implement CTLEnd
static method apply takes unit t, real d returns boolean
local thistype this
local integer i = GetUnitUserData(t)
if isAffected[i] then
set this = index[i]
/* Stack */
static if thistype.STACKABLE then
set .duration = .duration + d
else
/* Reset */
static if thistype.RESETABLE then
if .duration < d then
set .duration = d
endif
endif
endif
return true
else
// Basically, the buff doesn't work only for magic immune and structures
if not(IsUnitType(t, UNIT_TYPE_MAGIC_IMMUNE) or IsUnitType(t, UNIT_TYPE_STRUCTURE)) then
set this = create()
set .target = t
set .duration = d
set .sfx = AddSpecialEffectTarget(SLOW_SFX, t, SLOW_SFX_PT)
set isAffected[i] = true
set index[i] = this
// If unit don't have the buff yet
if GetUnitAbilityLevel(t, BUFF_ID) == 0 then
call SetUnitX(dummy, GetUnitX(t))
call SetUnitY(dummy, GetUnitY(t))
call IssueImmediateOrderById(dummy, SLOW_ORDER)
call SetUnitPosition(dummy, WorldBounds.maxX, WorldBounds.maxY)
endif
// Remove unwanted buff
call GroupEnumUnitsInRange(group, GetUnitX(.target), GetUnitY(.target), BUFF_SAFETY, null)
loop
set t = FirstOfGroup(group)
exitwhen t == null
call GroupRemoveUnit(group, t)
if GetUnitAbilityLevel(t, BUFF_ID) > 0 and not isAffected[GetUnitUserData(t)] then
call UnitRemoveAbility(t, BUFF_ID)
endif
endloop
return true
debug else
debug call BJDebugMsg("Error occured: failed to attach buff")
endif
endif
return false
endmethod
static method onInit takes nothing returns nothing
set dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_ID, WorldBounds.maxX, WorldBounds.maxY, 0)
call UnitAddAbility(dummy, SPELL_ID)
endmethod
endstruct
private struct Freeze extends array
implement FreezeData
unit target
real duration
effect sfx
static unit dummy
static group group = CreateGroup()
static boolean array isAffected
static thistype array index
implement CTLExpire
set .duration = .duration - .03125
if .duration <= 0 or not UnitAlive(.target) then
call DestroyEffect(.sfx)
call UnitRemoveAbility(.target, BUFF_ID)
set isAffected[GetUnitUserData(.target)] = false
call destroy()
set .sfx = null
set .target = null
endif
implement CTLEnd
static method apply takes unit t, real d returns boolean
local thistype this
local integer i = GetUnitUserData(t)
if isAffected[i] then
set this = index[i]
/* Stack */
static if thistype.STACKABLE then
set .duration = .duration + d
else
/* Reset */
static if thistype.RESETABLE then
if .duration < d then
set .duration = d
endif
endif
endif
return true
else
/* Basically, the buff doesn't work for magic immune and structures only */
if not(IsUnitType(t, UNIT_TYPE_MAGIC_IMMUNE) or IsUnitType(t, UNIT_TYPE_STRUCTURE)) then
set this = create()
set .target = t
set .duration = d
set .sfx = AddSpecialEffectTarget(FREEZE_SFX, t, FREEZE_SFX_PT)
set isAffected[i] = true
set index[i] = this
/* If unit don't have the buff yet */
if GetUnitAbilityLevel(t, BUFF_ID) == 0 then
call SetUnitX(dummy, GetUnitX(t))
call SetUnitY(dummy, GetUnitY(t))
call IssueImmediateOrderById(dummy, FREEZE_ORDER)
call SetUnitPosition(dummy, WorldBounds.maxX, WorldBounds.maxY)
endif
/* Remove unwanted buff */
call GroupEnumUnitsInRange(group, GetUnitX(.target), GetUnitY(.target), BUFF_SAFETY, null)
loop
set t = FirstOfGroup(group)
exitwhen t == null
call GroupRemoveUnit(group, t)
if GetUnitAbilityLevel(t, BUFF_ID) > 0 and not isAffected[GetUnitUserData(t)] then
call UnitRemoveAbility(t, BUFF_ID)
endif
endloop
return true
debug else
debug call BJDebugMsg("Error occured: failed to attach buff")
endif
endif
return false
endmethod
private static method onInit takes nothing returns nothing
set dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_ID, WorldBounds.maxX, WorldBounds.maxY, 0)
call UnitAddAbility(dummy, SPELL_ID)
endmethod
endstruct
/* Cold Addict spell*/
scope ColdAddict
struct ColdAddict extends array
implement ColdAddictData
unit target
real duration
real mana
effect sfx
static real array amount
static boolean array isAffected
static thistype array index
implement CTL
local integer i
local real m
implement CTLExpire
set .duration = .duration - .03125
/* Stops mana regeneration */
set m = GetUnitState(.target, UNIT_STATE_MANA)
if m > .mana then
call SetUnitState(.target, UNIT_STATE_MANA, .mana)
elseif m < .mana then
set .mana = m
endif
if .duration <= 0 or not UnitAlive(.target) then
set i = GetUnitUserData(.target)
call DestroyEffect(.sfx)
set amount[i] = 0
set isAffected[i] = false
call destroy()
set .target = null
set .sfx = null
endif
implement CTLEnd
static method onCast takes nothing returns nothing
local thistype this = create()
local unit t = GetSpellTargetUnit()
local integer i = GetUnitUserData(t)
local integer l = GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID)
local real d
if isAffected[i] then
set this = index[i]
static if thistype.STACKABLE_DUR then
if IsUnitType(t, UNIT_TYPE_HERO) then
set .duration = .duration + durationHero(l)
else
set .duration = .duration + durationNormal(l)
endif
else
static if thistype.RESETABLE then
if IsUnitType(t, UNIT_TYPE_HERO) then
set .duration = durationHero(l)
else
set .duration = durationNormal(l)
endif
endif
endif
/* Stack damage amplification amount */
static if thistype.STACKABLE_BUFF then
set amount[i] = amount[i] + damage(l)
endif
/*
* Prevent slow buff from being removed before
* cold addict has expired
*/
if Slow.index[i].duration < .duration then
set Slow.index[i].duration = .duration
endif
else
if IsUnitType(t, UNIT_TYPE_HERO) then
set d = durationHero(l)
else
set d = durationNormal(l)
endif
if Slow.apply(t, duration) then
set this = create()
set .target = t
set .duration = d
set .mana = GetUnitState(.target, UNIT_STATE_MANA)
set amount[i] = damage(l)
set isAffected[i] = true
set index[i] = this
set .sfx = AddSpecialEffectTarget(TARGET_SFX, .target, TARGET_SFX_PT)
endif
endif
set t = null
endmethod
static if not LIBRARY_SpellEffectEvent then
private static method check takes nothing returns isAffectedean
if GetSpellAbilityId() == SPELL_ID then
call thistype.onCast()
endif
return false
endmethod
endif
static method onInit takes nothing returns nothing
local trigger t
static if LIBRARY_SpellEffectEvent then
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
else
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.check))
endif
endmethod
endstruct
endscope
/* Frostwave spell*/
scope Frostwave
private struct data extends array
implement FrostwaveData
static constant real ANGLE_ADD = (bj_PI * 2)/data.SHARD_COUNT
endstruct
private keyword Frostwave
private struct IceShard
integer count
real array angle[data.SHARD_COUNT]
real array speed[data.SHARD_COUNT]
real array x[data.SHARD_COUNT]
real array y[data.SHARD_COUNT]
boolean array bool[data.SHARD_COUNT]
effect array sfx[data.SHARD_COUNT]
unit array dummy[data.SHARD_COUNT]
/* For FoG looping */
static group tempGroup = CreateGroup()
/* Function to compare two distances */
static constant method inRadius takes real x, real y, real xt, real yt, real r returns boolean
return (x - xt) * (x - xt) + (y - yt) * (y - yt) <= r * r
endmethod
static method move takes Frostwave i returns boolean
local boolean b = false
local integer j = 0
local real a
local real d
local unit u
loop
exitwhen j > data.SHARD_COUNT - 1
if i.missile.bool[j] then
set i.missile.x[j] = i.missile.x[j] + i.missile.speed[j] * Cos(i.missile.angle[j])
set i.missile.y[j] = i.missile.y[j] + i.missile.speed[j] * Sin(i.missile.angle[j])
/* If has reached the destination */
if isInBound(i.missile.x[j], i.missile.y[j]) and not inRadius(i.missile.x[j], i.missile.y[j], i.tX, i.tY, i.missile.speed[j]) then
set a = getAngle(i.missile.x[j], i.missile.y[j], i.tX, i.tY)
call SetUnitX(i.missile.dummy[j], i.missile.x[j])
call SetUnitY(i.missile.dummy[j], i.missile.y[j])
call SetUnitFacing(i.missile.dummy[j], i.missile.angle[j] * bj_RADTODEG)
call GroupEnumUnitsInRange(tempGroup, i.missile.x[j], i.missile.y[j], i.angle, null)
loop
set u = FirstOfGroup(tempGroup)
exitwhen u == null
if UnitAlive(u) and not IsUnitInGroup(u, i.targets) and data.filter(u, i.owner) then
if IsUnitType(u, UNIT_TYPE_HERO) then
set d = data.durationHero(i.level)
else
set d = data.durationNormal(i.level)
endif
if Slow.apply(u, d) then
call UnitDamageTarget(i.count, u, i.damage + i.damage * ColdAddict.amount[GetUnitUserData(u)], false, false, data.ATTACK_TYPE, data.DAMAGE_TYPE, data.WEAPON_TYPE)
call DestroyEffect(AddSpecialEffectTarget(data.TARGET_SFX, u, data.TARGET_SFX_PT))
endif
call GroupAddUnit(i.targets, u)
endif
call GroupRemoveUnit(tempGroup, u)
endloop
/*
* Turn the missile slowly to face the target
* point based on TURN_RATE
*/
if data.TURN_RATE != 0 and Cos(i.missile.angle[j] - a) < Cos(data.TURN_RATE) then
if Sin(a - i.missile.angle[j]) >= 0 then
set i.missile.angle[j] = i.missile.angle[j] + data.TURN_RATE
else
set i.missile.angle[j] = i.missile.angle[j] - data.TURN_RATE
endif
else
set i.missile.angle[j] = a
/* Accelerate if has faced the target point correctly */
set i.missile.speed[j] = i.missile.speed[j] + data.ACCELERATION
if i.missile.speed[j] > data.SPEED_MAX then
set i.missile.speed[j] = data.SPEED_MAX
endif
endif
else
call SetUnitX(i.missile.dummy[j], i.tX)
call SetUnitY(i.missile.dummy[j], i.tY)
call DestroyEffect(i.missile.sfx[j])
call UnitApplyTimedLife(i.missile.dummy[j], 'BTLF', SFX_DECAY_TIME)
set i.missile.sfx[j] = null
set i.missile.bool[j] = false
set i.missile.count = i.missile.count - 1
if i.missile.count < 0 then
call i.missile.destroy()
set b = true
endif
endif
endif
set j = j + 1
endloop
return b
endmethod
static method create takes real x, real y, real f returns thistype
local thistype this = allocate()
local integer i = 0
/* Determine the lowest angle */
set f = f - data.ANGLE_ADD * (data.SHARD_COUNT/2)
set .count = data.SHARD_COUNT - 1
loop
exitwhen i > .count
set .speed[i] = data.SPEED_MIN
set .angle[i] = f
set .bool[i] = true
set .x[i] = x
set .y[i] = y
set .dummy[i] = CreateUnit(PASSIVE, DUMMY_ID, x, y, f * bj_RADTODEG)
set .sfx[i] = AddSpecialEffectTarget(data.MISSILE_PATH, .dummy[i], "origin")
static if not LIBRARY_AutoFly then
if UnitAddAbility(.dummy[i], 'Amrf') and UnitRemoveAbility(.dummy[i], 'Amrf') then
endif
endif
call SetUnitFlyHeight(.dummy[i], data.LAUNCH_Z, 0)
set f = f + data.ANGLE_ADD
set i = i + 1
endloop
return this
endmethod
endstruct
private struct Frostwave extends array
real tX
real tY
real angle
real damage
unit count
group targets
player owner
integer level
IceShard missile
implement CTLExpire
if IceShard.move(this) then
call DestroyGroup(.targets)
call destroy()
set .count = null
set .targets = null
endif
implement CTLEnd
static method onCast takes nothing returns nothing
local thistype this = create()
local real a
local real x
local real y
set .count = GetTriggerUnit()
set .owner = GetTriggerPlayer()
set .targets = CreateGroup()
set x = GetUnitX(.count)
set y = GetUnitY(.count)
set .tX = GetSpellTargetX()
set .tY = GetSpellTargetY()
set .level = GetUnitAbilityLevel(.count, data.SPELL_ID)
/* If target point is the same as cast point */
if x == .tX and y == .tY then
set a = GetUnitFacing(.count) * bj_DEGTORAD
else
set a = getAngle(x, y, .tX, .tY)
endif
set .missile = IceShard.create(x, y, a)
set .tX = x + data.distance(.level) * Cos(a)
set .tY = y + data.distance(.level) * Sin(a)
set .damage = data.damage(.level)
set .angle = data.aoe(.level)
endmethod
static if not LIBRARY_SpellEffectEvent then
private static method check takes nothing returns boolean
if GetSpellAbilityId() == data.SPELL_ID then
call thistype.onCast()
endif
return false
endmethod
endif
static method onInit takes nothing returns nothing
local trigger t
static if LIBRARY_SpellEffectEvent then
call RegisterSpellEffectEvent(data.SPELL_ID, function thistype.onCast)
else
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.check))
endif
endmethod
endstruct
endscope
/* Frost Phase spell*/
scope FrostPhase
private struct FrostPhase extends array
implement FrostPhaseData
real aoe
real angle
real distance
real damage
real x
real y
unit source
group targets
player owner
integer level
/* For FoG looping */
static group tempGroup = CreateGroup()
implement CTL
local unit u
local unit f
local real d
local real c = 0
implement CTLExpire
/*
* Check terrain pathability between cast and
* target point
*/
set c = 0
loop
exitwhen c >= .distance or not IsTerrainWalkable(.x, .y)
set .x = .x + ACCURACY * Cos(.angle)
set .y = .y + ACCURACY * Sin(.angle)
set c = c + ACCURACY
endloop
call SetUnitPosition(.source, .x, .y)
set .x = GetUnitX(.source)
set .y = GetUnitY(.source)
call GroupEnumUnitsInRange(tempGroup, .x, .y, .aoe, null)
loop
set u = FirstOfGroup(tempGroup)
exitwhen u == null
if UnitAlive(u) and filter(u, .owner) then
if not IsUnitInGroup(u, .targets) then
if IsUnitType(u, UNIT_TYPE_HERO) then
set d = durationHero(.level)
else
set d = durationNormal(.level)
endif
if Freeze.apply(u, d) then
call UnitDamageTarget(.source, u, .damage + .damage * ColdAddict.amount[GetUnitUserData(u)], false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
/* If only deal damage for once per unit*/
static if DAMAGE_ONCE then
call GroupAddUnit(.targets, u)
endif
endif
endif
endif
call GroupRemoveUnit(tempGroup, u)
endloop
/* Create scaled sfx at target point */
set f = CreateUnit(.owner, DUMMY_ID, .x, .y, 0)
call SetUnitScale(f, EXPLODE_SIZE, 1, 1)
call DestroyEffect(AddSpecialEffectTarget(EXPLODE_SFX, f, "origin"))
call UnitApplyTimedLife(f, 'BTLF', SFX_DECAY_TIME)
call DestroyGroup(.targets)
call destroy()
set .source = null
set .targets = null
set f = null
implement CTLEnd
static method onCast takes nothing returns nothing
local thistype this = create()
local real xt
local real yt
local real d
local unit u
set .source = GetTriggerUnit()
set .owner = GetTriggerPlayer()
set .targets = CreateGroup()
set .x = GetUnitX(.source)
set .y = GetUnitY(.source)
set xt = GetSpellTargetX()
set yt = GetSpellTargetY()
set .level = GetUnitAbilityLevel(.source, SPELL_ID)
set .angle = getAngle(.x, .y, xt, yt)
set .distance = getDistance(.x, .y, xt, yt)
/* If surpass max distance */
if .distance > range(.level) then
set .distance = range(.level)
endif
set .damage = amount(.level)
set .aoe = AoE(.level)
call GroupEnumUnitsInRange(tempGroup, .x, .y, .aoe, null)
loop
set u = FirstOfGroup(tempGroup)
exitwhen u == null
if UnitAlive(u) and filter(u, .owner) then
if not IsUnitInGroup(u, .targets) then
if IsUnitType(u, UNIT_TYPE_HERO) then
set d = durationHero(.level)
else
set d = durationNormal(.level)
endif
if Freeze.apply(u, d) then
call UnitDamageTarget(.source, u, .damage + .damage * ColdAddict.amount[GetUnitUserData(u)], false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
/* If only deal damage for once per unit*/
static if DAMAGE_ONCE then
call GroupAddUnit(.targets, u)
endif
endif
endif
endif
call GroupRemoveUnit(tempGroup, u)
endloop
/* Create scaled sfx at cast point */
set u = CreateUnit(.owner, DUMMY_ID, .x, .y, 0)
call SetUnitScale(u, EXPLODE_SIZE, 1, 1)
call DestroyEffect(AddSpecialEffectTarget(EXPLODE_SFX, u, "origin"))
call UnitApplyTimedLife(u, 'BTLF', SFX_DECAY_TIME)
set u = null
endmethod
static if not LIBRARY_SpellEffectEvent then
private static method check takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call thistype.onCast()
endif
return false
endmethod
endif
static method onInit takes nothing returns nothing
local trigger t
static if LIBRARY_SpellEffectEvent then
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
else
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.check))
endif
endmethod
endstruct
endscope
/* Frozen Fate spell*/
scope FrozenFate
private struct FrozenFate extends array
implement FrozenFateData
real x
real y
real cDistance
real tDistance
real vertical
real horizontal
real angle
real side
real duration
unit target
player owner
effect sfx
unit dummy
static group Group = CreateGroup()
static constant real HP = bj_PI/2
implement CTL
local real v
local real h
local real x
local real y
local real xt
local real yt
implement CTLExpire
set .cDistance = .cDistance + MISSILE_SPEED
/* Calculate vertical and horizontal offset */
set h = (4 * .horizontal/.tDistance) * (.tDistance - .cDistance) * (.cDistance/.tDistance)
set v = (4 * .horizontal/.tDistance) * (.tDistance - .cDistance) * (.cDistance/.tDistance) + MISSILE_Z
set .x = .x + MISSILE_SPEED * Cos(.angle)
set .y = .y + MISSILE_SPEED * Sin(.angle)
set x = .x + h * Cos(.angle + HP * .side)
set y = .y + h * Sin(.angle + HP * .side)
if isInBound(x, y) then
set xt = GetUnitX(.target)
set yt = GetUnitY(.target)
call SetUnitX(.dummy, x)
call SetUnitY(.dummy, y)
call SetUnitFlyHeight(.dummy, v, 0)
call SetUnitFacing(.dummy, getAngle(x, y, xt, yt) * bj_RADTODEG)
if .cDistance >= .tDistance then
/* If the targeted corpse is still available and reachable */
if IsUnitIndexed(.target) and getDistance(x, y, xt, yt) <= TOLERATION then
call DestroyEffect(AddSpecialEffect(IMPACT_SFX, xt, yt))
call UnitApplyTimedLife(CreateUnit(.owner, SUMMON_ID, xt, yt, GetUnitFacing(.target)), BUFF_ID, .duration)
call RemoveUnit(.target)
endif
call kill()
call destroy()
endif
else
call kill()
call destroy()
endif
implement CTLEnd
method kill takes nothing returns nothing
call DestroyEffect(.sfx)
call RemoveUnit(.dummy)
set .sfx = null
set .target = null
set .dummy = null
endmethod
static method onCast takes nothing returns nothing
local thistype this
local unit f
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
local integer l = GetUnitAbilityLevel(u, SPELL_ID)
local integer c = count(l)
local real d = lifespan(l)
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real xt
local real yt
call GroupEnumUnitsInRange(Group, x, y, aoe(l), null)
loop
set f = FirstOfGroup(Group)
exitwhen f == null
if c > 0 and IsUnitCorpse(f) and filter(f, p) then
set this = create()
set .target = f
set .duration = d
set .owner = p
set .x = x
set .y = y
set xt = GetUnitX(f)
set yt = GetUnitY(f)
set .cDistance = 0
set .tDistance = getDistance(.x, .y, xt, yt)
set .angle = getAngle(.x, .y, xt, yt)
set .vertical = .tDistance * GetRandomReal(V_ARC_MIN, V_ARC_MAX)
set .horizontal = .tDistance * GetRandomReal(H_ARC_MIN, H_ARC_MAX)
set .dummy = CreateUnit(PASSIVE, DUMMY_ID, .x, .y, .angle * bj_RADTODEG)
set .sfx = AddSpecialEffectTarget(MISSILE_SFX, .dummy, "origin")
static if not LIBRARY_AutoFly then
if UnitAddAbility(.dummy, 'Amrf') and UnitRemoveAbility(.dummy, 'Amrf') then
endif
endif
/* Set the horizontal offset side */
if GetRandomInt(1, 100) <= 50 then
set .side = 1
else
set .side = -1
endif
call SetUnitScale(.dummy, MISSILE_SIZE, 1, 1)
call SetUnitFlyHeight(.dummy, MISSILE_Z, 0)
set c = c - 1
endif
call GroupRemoveUnit(Group, f)
endloop
set u = null
endmethod
static if not LIBRARY_SpellEffectEvent then
private static method check takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call thistype.onCast()
endif
return false
endmethod
endif
static method onInit takes nothing returns nothing
local trigger t
static if LIBRARY_SpellEffectEvent then
call RegisterSpellEffectEvent(SPELL_ID, function thistype.onCast)
else
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.check))
endif
endmethod
endstruct
endscope
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Frostwave
/*
* FROSTWAVE (STANDALONE)
* v2.0
*
* Sends a lance of ice shards wave to the
* target point, dealing damage to land units
* in a line and slowing them for a short
* duration.
*
* External Dependencies:
* (Required)
* - CTL
* - WorldBounds
* - UnitIndexer
*
* (Optional)
* - SpellEffectEvent
* - AutoFly
*
* How to install:
* - Install and configure all external
* dependecies properly.
* - Copy object datas as following:
* - Frostwave main ability (A005)
* - Slow ability (A001)
* - Slow buff (B001)
* - Dummy unit (h000)
* - Copy this trigger into your map.
* - Configure the spell correctly.
*
* Credits:
* - Nestharus
* - Bribe
* - Magtheridon96
*
*
* CONFIGURATION
*/
/* A. Global */
globals
/* Dummy unit's rawcode at Object Editor */
private constant integer DUMMY_ID = 'h000'
/* General decay time for all created sfx */
private constant real SFX_DECAY_TIME = 2.0
endglobals
/* B. Slow Effect */
private module SlowData
/* Slow ability's rawcode at Object Editor */
static constant integer SPELL_ID = 'A001'
/* Slow buff's rawcode at Object Editor */
static constant integer BUFF_ID = 'B001'
/* Slow order id */
static constant integer SLOW_ORDER = 852096 /* thunderclap */
/* Attached sfx on slow targets */
static constant string SLOW_SFX = "Abilities\\Spells\\Other\\FrostDamage\\FrostDamage.mdl"
static constant string SLOW_SFX_PT = "chest"
/* Duration is stackable */
static constant boolean STACKABLE = true
/* Will reset the duration if not stacked */
static constant boolean RESETABLE = false
/* The higher, the safer. But just leave it */
static constant real BUFF_SAFETY = 100.0
endmodule
/* C. Frostwave */
private module FrostwaveData
/* Main ability's rawcode at Object Editor */
static constant integer SPELL_ID = 'A005'
/* Total of created missiles on every cast */
static constant integer SHARD_COUNT = 23
/* Normal height z for every missile */
static constant real LAUNCH_Z = 64.0
/* Initial speed of every missile */
static constant real SPEED_MIN = 20.0
/* Maximum speed of every missile */
static constant real SPEED_MAX = 40.0
/* Acceleration rate of every missile */
static constant real ACCELERATION = 0.25
/* Turning rate of every missile */
static constant real TURN_RATE = 12.5 * bj_DEGTORAD
/* Missile model path */
static constant string MISSILE_PATH = "Abilities\\Weapons\\LichMissile\\LichMissile.mdl"
/* Attached sfx on targets */
static constant string TARGET_SFX = "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl"
static constant string TARGET_SFX_PT = "origin"
/* Dealt damage configuration */
static constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
static constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_COLD
static constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
/* Max distance from missile to hits a target */
static constant method aoe takes integer l returns real
return 128.0
endmethod
/* Dealt damage amount */
static constant method damage takes integer l returns real
return 20.0 + 60.0 * l
endmethod
/* Travel distance of every missile */
static constant method distance takes integer l returns real
return 1000.0
endmethod
/* Slow duration for normal units */
static constant method durationNormal takes integer l returns real
return 4.0
endmethod
/* Slow duration for hero units */
static constant method durationHero takes integer l returns real
return 1.325
endmethod
/* Configure the targets, by default it's unable to hit structures and magic immune */
static constant method filter takes unit u, player p returns boolean
return not(IsUnitAlly(u, p) or IsUnitType(u, UNIT_TYPE_FLYING) or IsUnitType(u, UNIT_TYPE_MECHANICAL))
endmethod
endmodule
/*
* END OF CONFIGURATION
* ================================================== */
native UnitAlive takes unit id returns boolean
globals
private player PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
endglobals
/* Function that returns angle between coordinates */
private function getAngle takes real x, real y, real xt, real yt returns real
return Atan2(yt - y, xt - x)
endfunction
/* Function that checks whether given coordinate is in map bound or not */
private constant function isInBound takes real x, real y returns boolean
return x > WorldBounds.minX and x < WorldBounds.maxX and y > WorldBounds.minY and y < WorldBounds.maxY
endfunction
private struct Slow extends array
implement SlowData
unit target
real duration
effect sfx
static unit dummy
static group group = CreateGroup()
static boolean array isAffected
static thistype array index
implement CTLExpire
set .duration = .duration - .03125
if .duration <= 0 or not UnitAlive(.target) then
call DestroyEffect(.sfx)
call UnitRemoveAbility(.target, BUFF_ID)
set isAffected[GetUnitUserData(.target)] = false
call destroy()
set .sfx = null
set .target = null
endif
implement CTLEnd
static method apply takes unit t, real d returns boolean
local thistype this
local integer i = GetUnitUserData(t)
if isAffected[i] then
set this = index[i]
/* Stack */
static if thistype.STACKABLE then
set .duration = .duration + d
else
/* Reset */
static if thistype.RESETABLE then
if .duration < d then
set .duration = d
endif
endif
endif
return true
else
// Basically, the buff doesn't work only for magic immune and structures
if not(IsUnitType(t, UNIT_TYPE_MAGIC_IMMUNE) or IsUnitType(t, UNIT_TYPE_STRUCTURE)) then
set this = create()
set .target = t
set .duration = d
set .sfx = AddSpecialEffectTarget(SLOW_SFX, t, SLOW_SFX_PT)
set isAffected[i] = true
set index[i] = this
// If unit don't have the buff yet
if GetUnitAbilityLevel(t, BUFF_ID) == 0 then
call SetUnitX(dummy, GetUnitX(t))
call SetUnitY(dummy, GetUnitY(t))
call IssueImmediateOrderById(dummy, SLOW_ORDER)
call SetUnitPosition(dummy, WorldBounds.maxX, WorldBounds.maxY)
endif
// Remove unwanted buff
call GroupEnumUnitsInRange(group, GetUnitX(.target), GetUnitY(.target), BUFF_SAFETY, null)
loop
set t = FirstOfGroup(group)
exitwhen t == null
call GroupRemoveUnit(group, t)
if GetUnitAbilityLevel(t, BUFF_ID) > 0 and not isAffected[GetUnitUserData(t)] then
call UnitRemoveAbility(t, BUFF_ID)
endif
endloop
return true
debug else
debug call BJDebugMsg("Error occured: failed to attach buff")
endif
endif
return false
endmethod
static method onInit takes nothing returns nothing
set dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_ID, WorldBounds.maxX, WorldBounds.maxY, 0)
call UnitAddAbility(dummy, SPELL_ID)
endmethod
endstruct
private struct data extends array
implement FrostwaveData
static constant real ANGLE_ADD = (bj_PI * 2)/data.SHARD_COUNT
endstruct
private keyword Frostwave
private struct IceShard
integer count
real array angle[data.SHARD_COUNT]
real array speed[data.SHARD_COUNT]
real array x[data.SHARD_COUNT]
real array y[data.SHARD_COUNT]
boolean array bool[data.SHARD_COUNT]
effect array sfx[data.SHARD_COUNT]
unit array dummy[data.SHARD_COUNT]
/* For FoG looping */
static group tempGroup = CreateGroup()
/* Function to compare two distances */
static constant method inRadius takes real x, real y, real xt, real yt, real r returns boolean
return (x - xt) * (x - xt) + (y - yt) * (y - yt) <= r * r
endmethod
static method move takes Frostwave i returns boolean
local boolean b = false
local integer j = 0
local real a
local real d
local unit u
loop
exitwhen j > data.SHARD_COUNT - 1
if i.missile.bool[j] then
set i.missile.x[j] = i.missile.x[j] + i.missile.speed[j] * Cos(i.missile.angle[j])
set i.missile.y[j] = i.missile.y[j] + i.missile.speed[j] * Sin(i.missile.angle[j])
/* If has reached the destination */
if isInBound(i.missile.x[j], i.missile.y[j]) and not inRadius(i.missile.x[j], i.missile.y[j], i.tX, i.tY, i.missile.speed[j]) then
set a = getAngle(i.missile.x[j], i.missile.y[j], i.tX, i.tY)
call SetUnitX(i.missile.dummy[j], i.missile.x[j])
call SetUnitY(i.missile.dummy[j], i.missile.y[j])
call SetUnitFacing(i.missile.dummy[j], i.missile.angle[j] * bj_RADTODEG)
call GroupEnumUnitsInRange(tempGroup, i.missile.x[j], i.missile.y[j], i.angle, null)
loop
set u = FirstOfGroup(tempGroup)
exitwhen u == null
if UnitAlive(u) and not IsUnitInGroup(u, i.targets) and data.filter(u, i.owner) then
if IsUnitType(u, UNIT_TYPE_HERO) then
set d = data.durationHero(i.level)
else
set d = data.durationNormal(i.level)
endif
if Slow.apply(u, d) then
call UnitDamageTarget(i.count, u, i.damage + i.damage, false, false, data.ATTACK_TYPE, data.DAMAGE_TYPE, data.WEAPON_TYPE)
call DestroyEffect(AddSpecialEffectTarget(data.TARGET_SFX, u, data.TARGET_SFX_PT))
endif
call GroupAddUnit(i.targets, u)
endif
call GroupRemoveUnit(tempGroup, u)
endloop
/*
* Turn the missile slowly to face the target
* point based on TURN_RATE
*/
if data.TURN_RATE != 0 and Cos(i.missile.angle[j] - a) < Cos(data.TURN_RATE) then
if Sin(a - i.missile.angle[j]) >= 0 then
set i.missile.angle[j] = i.missile.angle[j] + data.TURN_RATE
else
set i.missile.angle[j] = i.missile.angle[j] - data.TURN_RATE
endif
else
set i.missile.angle[j] = a
/* Accelerate if has faced the target point correctly */
set i.missile.speed[j] = i.missile.speed[j] + data.ACCELERATION
if i.missile.speed[j] > data.SPEED_MAX then
set i.missile.speed[j] = data.SPEED_MAX
endif
endif
else
call SetUnitX(i.missile.dummy[j], i.tX)
call SetUnitY(i.missile.dummy[j], i.tY)
call DestroyEffect(i.missile.sfx[j])
call UnitApplyTimedLife(i.missile.dummy[j], 'BTLF', SFX_DECAY_TIME)
set i.missile.sfx[j] = null
set i.missile.bool[j] = false
set i.missile.count = i.missile.count - 1
if i.missile.count < 0 then
call i.missile.destroy()
set b = true
endif
endif
endif
set j = j + 1
endloop
return b
endmethod
static method create takes real x, real y, real f returns thistype
local thistype this = allocate()
local integer i = 0
/* Determine the lowest angle */
set f = f - data.ANGLE_ADD * (data.SHARD_COUNT/2)
set .count = data.SHARD_COUNT - 1
loop
exitwhen i > .count
set .speed[i] = data.SPEED_MIN
set .angle[i] = f
set .bool[i] = true
set .x[i] = x
set .y[i] = y
set .dummy[i] = CreateUnit(PASSIVE, DUMMY_ID, x, y, f * bj_RADTODEG)
set .sfx[i] = AddSpecialEffectTarget(data.MISSILE_PATH, .dummy[i], "origin")
static if not LIBRARY_AutoFly then
if UnitAddAbility(.dummy[i], 'Amrf') and UnitRemoveAbility(.dummy[i], 'Amrf') then
endif
endif
call SetUnitFlyHeight(.dummy[i], data.LAUNCH_Z, 0)
set f = f + data.ANGLE_ADD
set i = i + 1
endloop
return this
endmethod
endstruct
private struct Frostwave extends array
real tX
real tY
real angle
real damage
unit count
group targets
player owner
integer level
IceShard missile
implement CTLExpire
if IceShard.move(this) then
call DestroyGroup(.targets)
call destroy()
set .count = null
set .targets = null
endif
implement CTLEnd
static method onCast takes nothing returns nothing
local thistype this = create()
local real a
local real x
local real y
set .count = GetTriggerUnit()
set .owner = GetTriggerPlayer()
set .targets = CreateGroup()
set x = GetUnitX(.count)
set y = GetUnitY(.count)
set .tX = GetSpellTargetX()
set .tY = GetSpellTargetY()
set .level = GetUnitAbilityLevel(.count, data.SPELL_ID)
/* If target point is the same as cast point */
if x == .tX and y == .tY then
set a = GetUnitFacing(.count) * bj_DEGTORAD
else
set a = getAngle(x, y, .tX, .tY)
endif
set .missile = IceShard.create(x, y, a)
set .tX = x + data.distance(.level) * Cos(a)
set .tY = y + data.distance(.level) * Sin(a)
set .damage = data.damage(.level)
set .angle = data.aoe(.level)
endmethod
static if not LIBRARY_SpellEffectEvent then
private static method check takes nothing returns boolean
if GetSpellAbilityId() == data.SPELL_ID then
call thistype.onCast()
endif
return false
endmethod
endif
static method onInit takes nothing returns nothing
local trigger t
static if LIBRARY_SpellEffectEvent then
call RegisterSpellEffectEvent(data.SPELL_ID, function thistype.onCast)
else
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.check))
endif
endmethod
endstruct
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library CTL /* v1.2.0.3
*************************************************************************************
*
* 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
endif
set ir32[i] = false
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] or id32[i])) then
if (ir32[i]) then
set ir32[i] = false
else
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] or 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 start takes nothing returns nothing
call A32(rctl32)
endmethod
static method stop takes nothing returns nothing
call SR32(rctl32)
endmethod
static method ectl32 takes nothing returns boolean
endmodule
module CT32End
return false
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
/**
* IsTerrainWalkable snippet for estimating the walkability status of a co-ordinate pair, credits
* to Anitarf and Vexorian.
*
* API:
* boolean IsTerrainWalkable(real x, real y) - returns the walkability of (x,y)
*/
library IsTerrainWalkable initializer init
globals
// this value is how far from a point the item may end up for the point to be considered pathable
private constant real MAX_RANGE=10.
// the following two variables are set to the position of the item after each pathing check
// that way, if a point isn't pathable, these will be the coordinates of the nearest point that is
public real X=0.
public real Y=0.
private rect r
private item check
private item array hidden
private integer hiddenMax=0
endglobals
private function init takes nothing returns nothing
set check=CreateItem('ciri',0.,0.)
call SetItemVisible(check,false)
set r=Rect(0.0,0.0,128.0,128.0)
endfunction
private function hideBothersomeItem takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set hidden[hiddenMax]=GetEnumItem()
call SetItemVisible(hidden[hiddenMax],false)
set hiddenMax=hiddenMax+1
endif
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
// first, hide any items in the area so they don't get in the way of our item
call MoveRectTo(r,x,y)
call EnumItemsInRect(r,null,function hideBothersomeItem)
// try to move the check item and get its coordinates
// this unhides the item...
call SetItemPosition(check,x,y)
set X=GetItemX(check)
set Y=GetItemY(check)
//...so we must hide it again
call SetItemVisible(check,false)
// before returning, unhide any items that got hidden at the start
loop
exitwhen hiddenMax==0
set hiddenMax=hiddenMax-1
call SetItemVisible(hidden[hiddenMax],true)
endloop
// return pathability status
return (x-X)*(x-X)+(y-Y)*(y-Y)<MAX_RANGE*MAX_RANGE
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library_once Event /* v2.0.0.1
************************************************************************************
*
* Functions
*
* function CreateEvent takes nothing returns integer
* function TriggerRegisterEvent takes trigger t, integer ev returns nothing
*
************************************************************************************
*
* struct Event extends array
*
* static method create takes nothing returns thistype
* method registerTrigger takes trigger t returns nothing
* method register takes boolexpr c returns nothing
* method fire takes nothing returns nothing
*
************************************************************************************/
globals
private real q=0
endglobals
struct Event extends array
private static integer w=0
private static trigger array e
static method create takes nothing returns thistype
set w=w+1
set e[w]=CreateTrigger()
return w
endmethod
method registerTrigger takes trigger t returns nothing
call TriggerRegisterVariableEvent(t,SCOPE_PRIVATE+"q",EQUAL,this)
endmethod
method register takes boolexpr c returns nothing
call TriggerAddCondition(e[this],c)
endmethod
method fire takes nothing returns nothing
set q=0
set q=this
call TriggerEvaluate(e[this])
endmethod
endstruct
function CreateEvent takes nothing returns Event
return Event.create()
endfunction
function TriggerRegisterEvent takes trigger t,Event ev returns nothing
call ev.registerTrigger(t)
endfunction
function RegisterEvent takes boolexpr c,Event ev returns nothing
call ev.register(c)
endfunction
function FireEvent takes Event ev returns nothing
call ev.fire()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library_once WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
* readonly static integer centerX
* readonly static integer centerY
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX=R2I(GetRectMaxX(world))
set maxY=R2I(GetRectMaxY(world))
set minX=R2I(GetRectMinX(world))
set minY=R2I(GetRectMinY(world))
set centerX=R2I((maxX+minX)/2)
set centerY=R2I((minY+maxY)/2)
set worldRegion=CreateRegion()
call RegionAddRect(worldRegion,world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library UnitIndexer /* v4.0.2.7
*************************************************************************************
*
* Assigns unique indexes to units via unit user data.
*
*************************************************************************************
*
* */uses/*
*
* */ WorldBounds /* hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
* */ Event /* hiveworkshop.com/forums/submissions-414/snippet-event-186555/
*
************************************************************************************
*
* SETTINGS
*/
globals
constant integer ABILITIES_UNIT_INDEXER = 'A007'
endglobals
/*
************************************************************************************
*
* Functions
*
* function RegisterUnitIndexEvent takes boolexpr codeToRegister, Event unitIndexEvent returns nothing
* function TriggerRegisterUnitIndexEvent takes trigger triggerToRegister, Event unitIndexEvent returns nothing
*
* function GetUnitById takes integer index returns unit
* - Returns unit given a unit index
* function GetUnitId takes unit u returns integer
* - Returns unit index given a unit
*
* function IsUnitIndexed takes unit u returns boolean
* function IsUnitDeindexing takes unit u returns boolean
*
* function GetIndexedUnitId takes nothing returns integer
* function GetIndexedUnit takes nothing returns unit
*
************************************************************************************
*
* module UnitIndexStructMethods
* static method operator [] takes unit u returns thistype
* - Return GetUnitUserData(u)
*
* readonly unit unit
* - The indexed unit of the struct
*
************************************************************************************
*
* module UnitIndexStruct extends UnitIndexStructMethods
*
* - A pseudo module interface that runs a set of methods if they exist and provides
* - a few fields and operators. Runs on static ifs to minimize code.
*
* readonly boolean allocated
* - Is unit allocated for the struct
*
* Interface:
*
* - These methods don't have to exist. If they don't exist, the code
* - that calls them won't even be in the module.
*
* private method index takes nothing returns nothing
* - called when a unit is indexed and passes the filter.
* -
* - thistype this: Unit's index
* private method deindex takes nothing returns nothing
* - called when a unit is deindexed and is allocated for struct
* -
* - thistype this: Unit's index
* private static method filter takes unit unitToIndex returns boolean
* - Determines whether or not to allocate struct for unit
* -
* - unit unitToIndex: Unit being filtered
*
************************************************************************************
*
* struct UnitIndexer extends array
*
* - Controls the unit indexer system.
*
* static constant Event UnitIndexer.INDEX
* static constant Event UnitIndexer.DEINDEX
* - Don't register functions and triggers directly to the events. Register them via
* - RegisterUnitIndexEvent and TriggerRegisterUnitIndexEvent.
*
* static boolean enabled
* - Enables and disables unit indexing. Useful for filtering out dummy units.
*
************************************************************************************
*
* struct UnitIndex extends UnitIndexStructMethods
*
* - Constrols specific unit indexes.
*
* method lock takes nothing returns nothing
* - Locks an index. When an index is locked, it will not be recycled
* - when the unit is deindexed until all locks are removed. Deindex
* - events still fire at the appropriate times, the index just doesn't
* - get thrown into the recycler.
* method unlock takes nothing returns nothing
* - Unlocks an index.
*
************************************************************************************/
globals
private trigger q=CreateTrigger()
private trigger l=CreateTrigger()
private unit array e
private integer r=0
private integer y=0
private integer o=0
private boolean a=false
private integer array n
private integer array p
private integer array lc
endglobals
function GetIndexedUnitId takes nothing returns integer
return o
endfunction
function GetIndexedUnit takes nothing returns unit
return e[o]
endfunction
//! runtextmacro optional UNIT_LIST_LIB()
private struct PreLoader extends array
public static method run takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
set a=true
endmethod
public static method eval takes trigger t returns nothing
local integer f=n[0]
local integer d=o
loop
exitwhen 0==f
if (IsTriggerEnabled(t)) then
set o=f
if (TriggerEvaluate(t)) then
call TriggerExecute(t)
endif
else
exitwhen true
endif
set f=n[f]
endloop
set o=d
endmethod
public static method evalb takes boolexpr c returns nothing
local trigger t=CreateTrigger()
local thistype f=n[0]
local integer d=o
call TriggerAddCondition(t,c)
loop
exitwhen 0==f
set o=f
call TriggerEvaluate(t)
set f=n[f]
endloop
call DestroyTrigger(t)
set t=null
set o=d
endmethod
endstruct
//! runtextmacro optional UNIT_EVENT_MACRO()
private module UnitIndexerInit
private static method onInit takes nothing returns nothing
local integer i=15
local boolexpr bc=Condition(function thistype.onLeave)
local boolexpr bc2=Condition(function thistype.onEnter)
local group g=CreateGroup()
local player p
set INDEX=CreateEvent()
set DEINDEX=CreateEvent()
call TriggerRegisterEnterRegion(q,WorldBounds.worldRegion,bc2)
loop
set p=Player(i)
call TriggerRegisterPlayerUnitEvent(l,p,EVENT_PLAYER_UNIT_ISSUED_ORDER,bc)
call SetPlayerAbilityAvailable(p,ABILITIES_UNIT_INDEXER,false)
call GroupEnumUnitsOfPlayer(g,p,bc2)
exitwhen 0==i
set i=i-1
endloop
call DestroyGroup(g)
set bc=null
set g=null
set bc2=null
set p=null
call TimerStart(CreateTimer(),0,false,function PreLoader.run)
endmethod
endmodule
struct UnitIndex extends array
method lock takes nothing returns nothing
debug if (null!=e[this]) then
set lc[this]=lc[this]+1
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO LOCK NULL INDEX")
debug endif
endmethod
method unlock takes nothing returns nothing
debug if (0<lc[this]) then
set lc[this]=lc[this]-1
if (0==lc[this] and null==e[this]) then
set n[this]=y
set y=this
endif
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO UNLOCK UNLOCKED INDEX")
debug endif
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
static method operator [] takes unit whichUnit returns thistype
return GetUnitUserData(whichUnit)
endmethod
endstruct
struct UnitIndexer extends array
readonly static Event INDEX
readonly static Event DEINDEX
static boolean enabled=true
private static method onEnter takes nothing returns boolean
local unit Q=GetFilterUnit()
local integer i
local integer d=o
if (enabled and Q!=e[GetUnitUserData(Q)] and 0==GetUnitUserData(Q)) then
if (0==y) then
set r=r+1
set i=r
else
set i=y
set y=n[y]
endif
call UnitAddAbility(Q,ABILITIES_UNIT_INDEXER)
call UnitMakeAbilityPermanent(Q,true,ABILITIES_UNIT_INDEXER)
call SetUnitUserData(Q,i)
set e[i]=Q
static if not LIBRARY_UnitList then
if (not a)then
set p[i]=p[0]
set n[p[0]]=i
set n[i]=0
set p[0]=i
endif
else
set p[i]=p[0]
set n[p[0]]=i
set n[i]=0
set p[0]=i
call GroupAddUnit(g,e[i])
endif
set o=i
call FireEvent(INDEX)
set o=d
endif
set Q=null
return false
endmethod
private static method onLeave takes nothing returns boolean
static if LIBRARY_UnitEvent then
implement optional UnitEventModule
else
local unit u=GetFilterUnit()
local integer i=GetUnitUserData(u)
local integer d=o
if (0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER) and u==e[i]) then
static if not LIBRARY_UnitList then
if (not a)then
set n[p[i]]=n[i]
set p[n[i]]=p[i]
endif
else
set n[p[i]]=n[i]
set p[n[i]]=p[i]
call GroupRemoveUnit(g,e[i])
endif
set o=i
call FireEvent(DEINDEX)
set o=d
if (0==lc[i]) then
set n[i]=y
set y=i
endif
set e[i]=null
endif
set u=null
endif
return false
endmethod
implement UnitIndexerInit
endstruct
//! runtextmacro optional UNIT_EVENT_MACRO_2()
function RegisterUnitIndexEvent takes boolexpr c,integer ev returns nothing
call RegisterEvent(c, ev)
if (not a and ev==UnitIndexer.INDEX and 0!=n[0]) then
call PreLoader.evalb(c)
endif
endfunction
function TriggerRegisterUnitIndexEvent takes trigger t,integer ev returns nothing
call TriggerRegisterEvent(t,ev)
if (not a and ev == UnitIndexer.INDEX and 0!=n[0]) then
call PreLoader.eval(t)
endif
endfunction
function GetUnitById takes integer W returns unit
return e[W]
endfunction
function GetUnitId takes unit u returns integer
return GetUnitUserData(u)
endfunction
function IsUnitIndexed takes unit u returns boolean
return u==e[GetUnitUserData(u)]
endfunction
function IsUnitDeindexing takes unit u returns boolean
return IsUnitIndexed(u) and 0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER)
endfunction
module UnitIndexStructMethods
static method operator [] takes unit u returns thistype
return GetUnitUserData(u)
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
endmodule
module UnitIndexStruct
implement UnitIndexStructMethods
static if thistype.filter.exists then
static if thistype.index.exists then
static if thistype.deindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return filter(e[this])
endmethod
endif
else
method operator allocated takes nothing returns boolean
return filter(e[this])
endmethod
endif
elseif (thistype.index.exists) then
static if thistype.deindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return this==GetUnitUserData(e[this])
endmethod
endif
else
method operator allocated takes nothing returns boolean
return this==GetUnitUserData(e[this])
endmethod
endif
static if thistype.index.exists then
private static method onIndexEvent takes nothing returns boolean
static if thistype.filter.exists then
if (filter(e[o])) then
static if thistype.deindex.exists then
set thistype(o).allocated=true
endif
call thistype(o).index()
endif
else
static if thistype.deindex.exists then
set thistype(o).allocated=true
endif
call thistype(o).index()
endif
return false
endmethod
endif
static if thistype.deindex.exists then
private static method onDeindexEvent takes nothing returns boolean
static if thistype.filter.exists then
static if thistype.index.exists then
if (thistype(o).allocated) then
set thistype(o).allocated=false
call thistype(o).deindex()
endif
else
if (filter(e[o])) then
call thistype(o).deindex()
endif
endif
else
static if thistype.index.exists then
set thistype(o).allocated=false
endif
call thistype(o).deindex()
endif
return false
endmethod
endif
static if thistype.index.exists then
static if thistype.deindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
endmethod
else
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
endmethod
endif
elseif thistype.deindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
endmethod
endif
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library IsUnitCorpse initializer onInit
/*
Simple library used to check whether a unit has become a corpse or not.
How to use:
- You must have a dummy caster at your OE
- Copy this trigger into your map
- Save your map, then re-open it
*/
///! external ObjectMerger w3a Amel IRAA anam "CORPSE_CHECKER" abpy 0 auby 0 aart "" auar "" arac "other" ahky "" auhk "" aran 1 0 atar 1 "air,dead,ground,player" atp1 1 "" aub1 1 "" aut1 1 "" auu1 1 ""
/*
- Delete or comment out that one line above and save again.
*/
globals
private constant integer DUMMY_ID = 'h000'
private constant integer SPELL_ID = 'IRAA'
private constant integer CONTAINER_ID = 'Sch2'
private constant integer ORDER_ID = 852053
private constant player UNUSED_PLAYER = Player(15)
private unit Dummy
endglobals
native UnitAlive takes unit id returns boolean
function IsUnitCorpse takes unit u returns boolean
local boolean b
local player p
if not UnitAlive(u) then
set p = GetOwningPlayer(u)
call SetUnitOwner(u, UNUSED_PLAYER, false)
call SetUnitX(Dummy, GetUnitX(u) + 100)
call SetUnitY(Dummy, GetUnitY(u) + 100)
call IssueImmediateOrderById(Dummy, ORDER_ID)
set b = GetUnitCurrentOrder(Dummy) == ORDER_ID
call SetUnitPosition(Dummy, 1234567890, 1234567890)
call SetUnitOwner(u, p, false)
else
return false
endif
return b
endfunction
private function onInit takes nothing returns nothing
set Dummy = CreateUnit(UNUSED_PLAYER, DUMMY_ID, 1234567890, 1234567890, 0)
call UnitAddAbility(Dummy, SPELL_ID)
call UnitAddAbility(Dummy, CONTAINER_ID)
endfunction
endlibrary
//TESH.scrollpos=0
//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
library AutoFly /* v1.0.0.1
-Credits to Magtheridon96 and Bribe for code update
-Credits to Azlier for original
-thehelper.net/forums/showthread.php/139729-AutoFly
*************************************************************************************
*
* Makes SetUnitFlyHeight possible
*
*************************************************************************************
*
* */uses/*
*
* */ UnitIndexer /* hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
*
************************************************************************************/
private function i takes nothing returns boolean
return UnitAddAbility(GetIndexedUnit(), 'Amrf') and UnitRemoveAbility(GetIndexedUnit(), 'Amrf')
endfunction
private module Init
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function i), UnitIndexer.INDEX)
endmethod
endmodule
private struct Inits extends array
implement Init
endstruct
endlibrary