Name | Type | is_array | initial_value |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Alloc ~~ By Sevion ~~ Version 1.09 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Alloc?
// - Alloc implements an intuitive allocation method for array structs
//
// =Pros=
// - Efficient.
// - Simple.
// - Less overhead than regular structs.
//
// =Cons=
// - Must use array structs (hardly a con).
// - Must manually call OnDestroy.
// - Must use Delegates for inheritance.
// - No default values for variables (use onInit instead).
// - No array members (use another Alloc struct as a linked list or type declaration).
//
// Methods:
// - struct.allocate()
// - struct.deallocate()
//
// These methods are used just as they should be used in regular structs.
//
// Modules:
// - Alloc
// Implements the most basic form of Alloc. Includes only create and destroy
// methods.
//
// Details:
// - Less overhead than regular structs
//
// - Use array structs when using Alloc. Put the implement at the top of the struct.
//
// - Alloc operates almost exactly the same as default structs in debug mode with the exception of onDestroy.
//
// How to import:
// - Create a trigger named Alloc.
// - Convert it to custom text and replace the whole trigger text with this.
//
// Thanks:
// - Nestharus for the method of allocation and suggestions on further merging.
// - Bribe for suggestions like the static if and method names.
// - PurgeandFire111 for some suggestions like the merging of Alloc and AllocX as well as OnDestroy stuff.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library Alloc
module Alloc
private static integer instanceCount = 0
private thistype recycle
static method allocate takes nothing returns thistype
local thistype this
if (thistype(0).recycle == 0) then
debug if (instanceCount == JASS_MAX_ARRAY_SIZE) then
debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Alloc ERROR: Attempted to allocate too many instances!")
debug return 0
debug endif
set instanceCount = instanceCount + 1
set this = instanceCount
else
set this = thistype(0).recycle
set thistype(0).recycle = thistype(0).recycle.recycle
endif
debug set this.recycle = -1
return this
endmethod
method deallocate takes nothing returns nothing
debug if (this.recycle != -1) then
debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Alloc ERROR: Attempted to deallocate an invalid instance at [" + I2S(this) + "]!")
debug return
debug endif
set this.recycle = thistype(0).recycle
set thistype(0).recycle = this
endmethod
endmodule
endlibrary
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
One map, one hashtable. Welcome to NewTable 4.1.0.1
This newest iteration of Table introduces the new HashTable struct.
You can now instantiate HashTables which enables the use of large
parent and large child keys, just like a standard hashtable. Previously,
the user would have to instantiate a Table to do this on their own which -
while doable - is something the user should not have to do if I can add it
to this resource myself (especially if they are inexperienced).
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
//NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
//than that which was previously possible.
struct HashTable extends array
//Enables myHash[parentKey][childKey] syntax.
//Basically, it creates a Table in the place of the parent key if
//it didn't already get created earlier.
method operator [] takes integer index returns Table
local Table t = Table(this)[index]
if t == 0 then
set t = Table.create()
set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
endif
return t
endmethod
//You need to call this on each parent key that you used if you
//intend to destroy the HashTable or simply no longer need that key.
method remove takes integer index returns nothing
local Table t = Table(this)[index]
if t != 0 then
call t.destroy()
call Table(this).remove(index)
endif
endmethod
//Added in version 4.1
method has takes integer index returns boolean
return Table(this).has(index)
endmethod
//HashTables are just fancy Table indices.
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
//Like I said above...
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
endlibrary
library Utilities requires TimerUtils, Indexer, TimedHandles, RegisterPlayerUnitEvent
/* --------------------------------------- Utilities v1.9 --------------------------------------- */
// How to Import:
// 1 - Copy this library into your map
// 2 - Copy the dummy unit in object editor and match its raw code below
// 3 - Copy the TimerUtils library into your map and follow its install instructions
// 4 - Copy the Indexer library over to your map and follow its install instructions
// 5 - Copy the TimedHandles library over to your map and follow its install instructions
// 6 - Copy the RegisterPlayerUnitEvent library over to your map and follow its install instructions
/* ---------------------------------------- By Chopinski ---------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* Configuration */
/* ---------------------------------------------------------------------------------------------- */
globals
// The dummy caster unit id
public constant integer DUMMY = 'dumi'
// Update period
private constant real PERIOD = 0.031250000
// location z
private location LOCZ = Location(0,0)
// One hashtable to rule them all
private hashtable table = InitHashtable()
// Closest Unit
private unit bj_closestUnitGroup
endglobals
/* ---------------------------------------------------------------------------------------------- */
/* JASS API */
/* ---------------------------------------------------------------------------------------------- */
// Only one declaration per map required
native UnitAlive takes unit id returns boolean
// Returns the terrain Z value (Desync safe)
function GetLocZ takes real x, real y returns real
call MoveLocation(LOCZ, x, y)
return GetLocationZ(LOCZ)
endfunction
// Similar to GetUnitX and GetUnitY but for Z axis
function GetUnitZ takes unit u returns real
return GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
endfunction
// Similar to SetUnitX and SetUnitY but for Z axis
function SetUnitZ takes unit u, real z returns nothing
call SetUnitFlyHeight(u, z - GetLocZ(GetUnitX(u), GetUnitY(u)), 0)
endfunction
// Anlge between 2D points
function AngleBetweenCoordinates takes real x, real y, real x2, real y2 returns real
return Atan2(y2 - y, x2 - x)
endfunction
// Similar to AddSpecialEffect but scales the effect and considers z and return it
function AddSpecialEffectEx takes string model, real x, real y, real z, real scale returns effect
set bj_lastCreatedEffect = AddSpecialEffect(model, x, y)
if z != 0 then
call BlzSetSpecialEffectZ(bj_lastCreatedEffect, z + GetLocZ(x, y))
endif
call BlzSetSpecialEffectScale(bj_lastCreatedEffect, scale)
return bj_lastCreatedEffect
endfunction
// Returns a group of enemy units of the specified player within the specified AOE of x and y
function GetEnemyUnitsInRange takes player enemyOf, real x, real y, real aoe, boolean structures, boolean magicImmune returns group
local group g = CreateGroup()
local group h = CreateGroup()
local unit w
call GroupEnumUnitsInRange(h, x, y, aoe, null)
loop
set w = FirstOfGroup(h)
exitwhen w == null
if IsUnitEnemy(w, enemyOf) and UnitAlive(w) and (structures or (not IsUnitType(w, UNIT_TYPE_STRUCTURE))) and (magicImmune or (not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE))) then
call GroupAddUnit(g, w)
endif
call GroupRemoveUnit(h, w)
endloop
call DestroyGroup(h)
set h = null
return g
endfunction
// Returns the closest unit in a unit group with center at x and y
function GetClosestUnitGroup takes real x, real y, group g returns unit
local unit u
local real dx
local real dy
local real md = 100000
local integer i = 0
local integer size = BlzGroupGetSize(g)
set bj_closestUnitGroup = null
loop
exitwhen i == size
set u = BlzGroupUnitAt(g, i)
if UnitAlive(u) then
set dx = GetUnitX(u) - x
set dy = GetUnitY(u) - y
if (dx*dx + dy*dy)/100000 < md then
set bj_closestUnitGroup = u
set md = (dx*dx + dy*dy)/100000
endif
endif
set i = i + 1
endloop
return bj_closestUnitGroup
endfunction
// Removes a destructable after a period of time
function RemoveDestructableTimed takes destructable dest, real timeout returns nothing
call TimedDestructable.create(dest, timeout)
endfunction
// Link an effect to a unit buff or ability
function LinkEffectToBuff takes unit target, integer buffId, string model, string attach returns nothing
call EffectLink.BuffLink(target, buffId, model, attach)
endfunction
// Link an effect to an unit item.
function LinkEffectToItem takes unit target, item i, string model, string attach returns nothing
call EffectLink.ItemLink(target, i, model, attach)
endfunction
// Pretty obvious.
function R2I2S takes real r returns string
return I2S(R2I(r))
endfunction
// Spams the specified effect model at a location with the given interval for the number of times count
function SpamEffect takes string model, real x, real y, real z, real scale, real interval, integer count returns nothing
call EffectSpam.spam(null, model, "", x, y, z, scale, interval, count)
endfunction
// Spams the specified effect model attached to a unit for the given interval for the number of times count
function SpamEffectUnit takes unit target, string model, string attach, real interval, integer count returns nothing
call EffectSpam.spam(target, model, attach, 0, 0, 0, 0, interval, count)
endfunction
// Add the specified ability to the specified unit for the given duration. Use hide to show or not the ability button.
function UnitAddAbilityTimed takes unit whichUnit, integer abilityId, real duration, integer level, boolean hide returns nothing
call TimedAbility.add(whichUnit, abilityId, duration, level, hide)
endfunction
// Resets the specified unit ability cooldown
function ResetUnitAbilityCooldown takes unit whichUnit, integer abilCode returns nothing
call ResetCooldown.reset(whichUnit, abilCode)
endfunction
// Returns the distance between 2 coordinates in Warcraft III units
function DistanceBetweenCoordinates takes real x1, real y1, real x2, real y2 returns real
local real dx = (x2 - x1)
local real dy = (y2 - y1)
return SquareRoot(dx*dx + dy*dy)
endfunction
// Makes the specified source damage an area respecting some basic unit filters
function UnitDamageArea takes unit source, real x, real y, real aoe, real damage, attacktype atkType, damagetype dmgType, boolean structures, boolean magicImmune, boolean allies returns nothing
local group h = CreateGroup()
local player enemyOf = GetOwningPlayer(source)
local unit w
call GroupEnumUnitsInRange(h, x, y, aoe, null)
call GroupRemoveUnit(h, source)
loop
set w = FirstOfGroup(h)
exitwhen w == null
if UnitAlive(w) and (allies or IsUnitEnemy(w, enemyOf)) and (structures or (not IsUnitType(w, UNIT_TYPE_STRUCTURE))) and (magicImmune or (not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE))) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
call GroupRemoveUnit(h, w)
endloop
call DestroyGroup(h)
set h = null
set enemyOf = null
endfunction
// Makes the specified source damage a group. Creates a special effect if specified
function UnitDamageGroup takes unit u, group g, real damage, attacktype atk_type, damagetype dmg_type, string sfx, string atch_point, boolean destroy returns group
local unit v
local integer i = 0
local integer t = BlzGroupGetSize(g)
loop
exitwhen i == t
set v = BlzGroupUnitAt(g, i)
call UnitDamageTarget(u, v, damage, true, false, atk_type, dmg_type, null)
if sfx != "" and atch_point != "" then
call DestroyEffect(AddSpecialEffectTarget(sfx, v, atch_point))
endif
set i = i + 1
endloop
if destroy then
call DestroyGroup(g)
endif
return g
endfunction
// Returns a random range given a max value
function GetRandomRange takes real radius returns real
local real r = GetRandomReal(0, 1) + GetRandomReal(0, 1)
if r > 1 then
return (2 - r)*radius
endif
return r*radius
endfunction
// Returns a random value in the x/y coordinates depending on the value of boolean x
function GetRandomCoordInRange takes real center, real radius, boolean x returns real
local real theta = 2*bj_PI*GetRandomReal(0, 1)
local real r
if x then
set r = center + radius*Cos(theta)
else
set r = center + radius*Sin(theta)
endif
return r
endfunction
// Clones the items in the source unit inventory to the target unit
function CloneItems takes unit source, unit target, boolean isIllusion returns nothing
local integer i = 0
local integer j
local item k
loop
exitwhen i > bj_MAX_INVENTORY
set k = UnitItemInSlot(source, i)
set j = GetItemCharges(k)
set k = CreateItem(GetItemTypeId(k), GetUnitX(target), GetUnitY(target))
call SetItemCharges(k, j)
call UnitAddItem(target, k)
if isIllusion then
if GetItemTypeId(k) == 'ankh' then
call BlzItemRemoveAbility(k, 'AIrc')
endif
call BlzSetItemBooleanField(k, ITEM_BF_ACTIVELY_USED, false)
endif
set i = i + 1
endloop
set k = null
endfunction
// Add the mount for he unit mana pool
function AddUnitMana takes unit whichUnit, real amount returns nothing
call SetUnitState(whichUnit, UNIT_STATE_MANA, (GetUnitState(whichUnit, UNIT_STATE_MANA) + amount))
endfunction
// Add the specified amounts to a hero str/agi/int base amount
function UnitAddStat takes unit whichUnit, integer strength, integer agility, integer intelligence returns nothing
if strength != 0 then
call SetHeroStr(whichUnit, GetHeroStr(whichUnit, false) + strength, true)
endif
if agility != 0 then
call SetHeroAgi(whichUnit, GetHeroAgi(whichUnit, false) + agility, true)
endif
if intelligence != 0 then
call SetHeroInt(whichUnit, GetHeroInt(whichUnit, false) + intelligence, true)
endif
endfunction
// Returns the closest unit from the x and y coordinates in the map
function GetClosestUnit takes real x, real y, boolexpr e returns unit
local real md = 100000
local group g = CreateGroup()
local unit u
local real dx
local real dy
set bj_closestUnitGroup = null
call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, e)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if UnitAlive(u) then
set dx = GetUnitX(u) - x
set dy = GetUnitY(u) - y
if (dx*dx + dy*dy)/100000 < md then
set bj_closestUnitGroup = u
set md = (dx*dx + dy*dy)/100000
endif
endif
call GroupRemoveUnit(g, u)
endloop
call DestroyGroup(g)
call DestroyBoolExpr(e)
set g = null
return bj_closestUnitGroup
endfunction
// Creates a chain lightning with the specified ligihtning effect with the amount of bounces
function CreateChainLightning takes unit source, unit target, real damage, real aoe, real duration, real interval, integer bounceCount, attacktype attackType, damagetype damageType, string lightningType, string sfx, string attachPoint, boolean canRebounce returns nothing
call ChainLightning.create(source, target, damage, aoe, duration, interval, bounceCount, attackType, damageType, lightningType, sfx, attachPoint, canRebounce)
endfunction
// Add the specified amount to the specified player gold amount
function AddPlayerGold takes player whichPlayer, integer amount returns nothing
call SetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(whichPlayer, PLAYER_STATE_RESOURCE_GOLD) + amount)
endfunction
// Creates a text tag in an unit position for a duration
function CreateTextOnUnit takes unit whichUnit, string text, real duration, integer red, integer green, integer blue, integer alpha returns nothing
local texttag tx = CreateTextTag()
call SetTextTagText(tx, text, 0.015)
call SetTextTagPosUnit(tx, whichUnit, 0)
call SetTextTagColor(tx, red, green, blue, alpha)
call SetTextTagLifespan(tx, duration)
call SetTextTagVelocity(tx, 0.0, 0.0355)
call SetTextTagPermanent(tx, false)
set tx = null
endfunction
// Add health regeneration to the unit base value
function UnitAddHealthRegen takes unit whichUnit, real regen returns nothing
call BlzSetUnitRealField(whichUnit, UNIT_RF_HIT_POINTS_REGENERATION_RATE, BlzGetUnitRealField(whichUnit, UNIT_RF_HIT_POINTS_REGENERATION_RATE) + regen)
endfunction
// Retrieves a dummy from the pool. Facing angle in radians
function DummyRetrieve takes player owner, real x, real y, real z, real face returns unit
return DummyPool.retrieve(owner, x, y, z, face)
endfunction
// Recycles a dummy unit type, putting it back into the pool.
function DummyRecycle takes unit dummy returns nothing
call DummyPool.recycle(dummy)
endfunction
// Recycles a dummy with a delay.
function DummyRecycleTimed takes unit dummy, real delay returns nothing
call DummyPool.recycleTimed(dummy, delay)
endfunction
// Casts an ability in the target unit. Must have no casting time
function CastAbilityTarget takes unit target, integer id, string order, integer level returns nothing
local unit dummy = DummyRetrieve(GetOwningPlayer(target), 0, 0, 0, 0)
call UnitAddAbility(dummy, id)
call SetUnitAbilityLevel(dummy, id, level)
call IssueTargetOrder(dummy, order, target)
call UnitRemoveAbility(dummy, id)
call DummyRecycle(dummy)
set dummy = null
endfunction
// Returns a random unit within a group
function GroupPickRandomUnitEx takes group g returns unit
if BlzGroupGetSize(g) > 0 then
return BlzGroupUnitAt(g, GetRandomInt(0, BlzGroupGetSize(g) - 1))
else
return null
endif
endfunction
// Returns true if a unit is within a cone given a facing and fov angle in degrees (Less precise)
function IsUnitInConeEx takes unit u, real x, real y, real face, real fov returns boolean
return Acos(Cos((Atan2(GetUnitY(u) - y, GetUnitX(u) - x)) - face*bj_DEGTORAD)) < fov*bj_DEGTORAD/2
endfunction
// Returns true if a unit is within a cone given a facing, fov angle and a range in degrees (takes collision into consideration). Credits to AGD.
function IsUnitInCone takes unit u, real x, real y, real range, real face, real fov returns boolean
if IsUnitInRangeXY(u, x, y, range) then
set x = GetUnitX(u) - x
set y = GetUnitY(u) - y
set range = x*x + y*y
if range > 0. then
set face = face*bj_DEGTORAD - Atan2(y, x)
set fov = fov*bj_DEGTORAD/2 + Asin(BlzGetUnitCollisionSize(u)/SquareRoot(range))
return RAbsBJ(face) <= fov or RAbsBJ(face - 2.00*bj_PI) <= fov
endif
return true
endif
return false
endfunction
// Makes the source unit damage enemy unit in a cone given a direction, foy and range
function UnitDamageCone takes unit source, real x, real y, real face, real fov, real aoe, real damage, attacktype atkType, damagetype dmgType, boolean structures, boolean magicImmune, boolean allies returns nothing
local group h = CreateGroup()
local player enemyOf = GetOwningPlayer(source)
local unit w
call GroupEnumUnitsInRange(h, x, y, aoe, null)
call GroupRemoveUnit(h, source)
loop
set w = FirstOfGroup(h)
exitwhen w == null
if (UnitAlive(w) and IsUnitInCone(w, x, y, aoe, face, fov)) then
if (allies or IsUnitEnemy(w, enemyOf)) and (structures or (not IsUnitType(w, UNIT_TYPE_STRUCTURE))) and (magicImmune or (not IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE))) then
call UnitDamageTarget(source, w, damage, true, false, atkType, dmgType, null)
endif
endif
call GroupRemoveUnit(h, w)
endloop
call DestroyGroup(h)
set h = null
set enemyOf = null
endfunction
// Heals all allied units of specified player in an area
function HealArea takes player alliesOf, real x, real y, real aoe, real amount, string fxpath, string attchPoint returns nothing
local group g = CreateGroup()
local unit v
call GroupEnumUnitsInRange(g, x, y, aoe, null)
loop
set v = FirstOfGroup(g)
exitwhen v == null
if IsUnitAlly(v, alliesOf) and UnitAlive(v) and not IsUnitType(v, UNIT_TYPE_STRUCTURE) then
call SetWidgetLife(v, GetWidgetLife(v) + amount)
if fxpath != "" then
if attchPoint != "" then
call DestroyEffect(AddSpecialEffectTarget(fxpath, v, attchPoint))
else
call DestroyEffect(AddSpecialEffect(fxpath, GetUnitX(v), GetUnitY(v)))
endif
endif
endif
call GroupRemoveUnit(g, v)
endloop
call DestroyGroup(g)
set g = null
endfunction
// Returns an ability real level field as a string. Usefull for toolltip manipulation.
function AbilityRealField takes unit u, integer abilityId, abilityreallevelfield field, integer level, integer multiplier, boolean asInteger returns string
if asInteger then
return R2I2S(BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, abilityId), field, level)*multiplier)
else
return R2SW(BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, abilityId), field, level)*multiplier,1,1)
endif
endfunction
// Fix for camera pan desync. credits do Daffa
function SmartCameraPanBJModified takes player whichPlayer, location loc, real duration returns nothing
local real tx = GetLocationX(loc)
local real ty = GetLocationY(loc)
local real dx = tx - GetCameraTargetPositionX()
local real dy = ty - GetCameraTargetPositionY()
local real dist = SquareRoot(dx * dx + dy * dy)
if (GetLocalPlayer() == whichPlayer) then
if (dist >= bj_SMARTPAN_TRESHOLD_SNAP) then
call PanCameraToTimed(tx, ty, duration)
// Far away = snap camera immediately to point
elseif (dist >= bj_SMARTPAN_TRESHOLD_PAN) then
call PanCameraToTimed(tx, ty, duration)
// Moderately close = pan camera over duration
else
// User is close, don't move camera
endif
endif
endfunction
// Fix for camera pan desync. credits do Daffa
function SmartCameraPanBJModifiedXY takes player whichPlayer, real x, real y, real duration returns nothing
local real dx = x - GetCameraTargetPositionX()
local real dy = y - GetCameraTargetPositionY()
local real dist = SquareRoot(dx * dx + dy * dy)
if (GetLocalPlayer() == whichPlayer) then
if (dist >= bj_SMARTPAN_TRESHOLD_SNAP) then
call PanCameraToTimed(x, y, duration)
// Far away = snap camera immediately to point
elseif (dist >= bj_SMARTPAN_TRESHOLD_PAN) then
call PanCameraToTimed(x, y, duration)
// Moderately close = pan camera over duration
else
// User is close, don't move camera
endif
endif
endfunction
// Start the cooldown for the source unit unit the new value
function StartUnitAbilityCooldown takes unit source, integer abilCode, real cooldown returns nothing
call AbilityCooldown.start(source, abilCode, cooldown)
endfunction
// Pauses or Unpauses a unit after a delay. If flag = true than the unit will be paused and unpaused after the duration. If flag = false than the unit will be unpaused and paused after the duration.
function PauseUnitTimed takes unit u, real duration, boolean flag returns nothing
call TimedPause.create(u, duration, flag)
endfunction
/* ---------------------------------------------------------------------------------------------- */
/* Systems */
/* ---------------------------------------------------------------------------------------------- */
/* ----------------------------------- Reset Ability Cooldown ----------------------------------- */
struct ResetCooldown
timer timer
unit unit
integer ability
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call BlzEndUnitAbilityCooldown(unit, ability)
call ReleaseTimer(timer)
call deallocate()
set unit = null
set timer = null
endmethod
static method reset takes unit u, integer id returns nothing
local thistype this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = u
set ability = id
call TimerStart(timer, 0.01, false, function thistype.onExpire)
endmethod
endstruct
/* ---------------------------------------- Timed Ability --------------------------------------- */
struct TimedAbility
static timer timer = CreateTimer()
static integer key = -1
static thistype array array
unit unit
integer ability
real duration
method remove takes integer i returns integer
call UnitRemoveAbility(unit, ability)
call RemoveSavedInteger(table, GetHandleId(unit), ability)
set array[i] = array[key]
set key = key - 1
set unit = null
if key == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > key
set this = array[i]
if duration <= 0 then
set i = remove(i)
endif
set duration = duration - 0.1
set i = i + 1
endloop
endmethod
static method add takes unit u, integer id, real duration, integer level, boolean hide returns nothing
local thistype this = LoadInteger(table, GetHandleId(u), id)
if this == 0 then
set this = thistype.allocate()
set unit = u
set ability = id
set key = key + 1
set array[key] = this
call SaveInteger(table, GetHandleId(unit), ability, this)
if key == 0 then
call TimerStart(timer, 0.1, true, function thistype.onPeriod)
endif
endif
if GetUnitAbilityLevel(unit, ability) != level then
call UnitAddAbility(unit, ability)
call SetUnitAbilityLevel(unit, ability, level)
call UnitMakeAbilityPermanent(unit, true, ability)
call BlzUnitHideAbility(unit, ability, hide)
endif
set .duration = duration
endmethod
endstruct
/* ----------------------------------------- Effect Spam ---------------------------------------- */
struct EffectSpam
timer timer
unit unit
integer i
string effect
string point
real scale
real x
real y
real z
private static method onPeriod takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
if i > 0 then
if unit == null then
call DestroyEffect(AddSpecialEffectEx(effect, x, y, z, scale))
else
call DestroyEffect(AddSpecialEffectTarget(effect, unit, point))
endif
else
call ReleaseTimer(timer)
call deallocate()
set timer = null
set unit = null
endif
set i = i - 1
endmethod
static method spam takes unit target, string model, string attach, real x, real y, real z, real scale, real interval, integer count returns nothing
local thistype this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = target
set i = count
set effect = model
set .x = x
set .y = y
set .z = z
set .scale = scale
set point = attach
call TimerStart(timer, interval, true, function thistype.onPeriod)
endmethod
endstruct
/* --------------------------------------- Chain Lightning -------------------------------------- */
struct ChainLightning
timer timer
unit unit
unit prev
unit self
unit next
group group
group damaged
player player
real damage
real range
real duration
integer bounces
attacktype attacktype
damagetype damagetype
string lightning
string effect
string attach
boolean rebounce
private method destroy takes nothing returns nothing
call DestroyGroup(group)
call ReleaseTimer(timer)
call DestroyGroup(damaged)
set prev = null
set self = null
set next = null
set unit = null
set group = null
set timer = null
set player = null
set damaged = null
set attacktype = null
set damagetype = null
call deallocate()
endmethod
private static method onPeriod takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call DestroyGroup(group)
if bounces > 0 then
set group = GetEnemyUnitsInRange(player, GetUnitX(self), GetUnitY(self), range, false, false)
call GroupRemoveUnit(group, self)
if not rebounce then
call BlzGroupRemoveGroupFast(damaged, group)
endif
if BlzGroupGetSize(group) == 0 then
call destroy()
else
set next = GetClosestUnitGroup(GetUnitX(self), GetUnitY(self), group)
if next == prev and BlzGroupGetSize(group) > 1 then
call GroupRemoveUnit(group, prev)
set next = GetClosestUnitGroup(GetUnitX(self), GetUnitY(self), group)
endif
if next != null then
call DestroyLightningTimed(AddLightningEx(lightning, true, GetUnitX(self), GetUnitY(self), GetUnitZ(self) + 60.0, GetUnitX(next), GetUnitY(next), GetUnitZ(next) + 60.0), duration)
call DestroyEffect(AddSpecialEffectTarget(effect, next, attach))
call GroupAddUnit(damaged, next)
call UnitDamageTarget(unit, next, damage, false, false, attacktype, damagetype, null)
call DestroyGroup(group)
set prev = self
set self = next
set next = null
else
call destroy()
endif
endif
else
call destroy()
endif
set bounces = bounces - 1
endmethod
static method create takes unit source, unit target, real dmg, real aoe, real dur, real interval, integer bounceCount, attacktype attackType, damagetype damageType, string lightningType, string sfx, string attachPoint, boolean canRebounce returns thistype
local group g
local thistype this
set g = GetEnemyUnitsInRange(GetOwningPlayer(source), GetUnitX(target), GetUnitY(target), aoe, false, false)
if BlzGroupGetSize(g) == 1 then
call DestroyLightningTimed(AddLightningEx(lightningType, true, GetUnitX(source), GetUnitY(source), BlzGetUnitZ(source) + 60.0, GetUnitX(target), GetUnitY(target), BlzGetUnitZ(target) + 60.0), dur)
call DestroyEffect(AddSpecialEffectTarget(sfx, target, attachPoint))
call UnitDamageTarget(source, target, dmg, false, false, attackType, damageType, null)
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set prev = null
set self = target
set next = null
set unit = source
set player = GetOwningPlayer(source)
set damage = dmg
set range = aoe
set duration = dur
set bounces = bounceCount
set attacktype = attackType
set damagetype = damageType
set lightning = lightningType
set effect = sfx
set attach = attachPoint
set rebounce = canRebounce
set damaged = CreateGroup()
call GroupRemoveUnit(g, target)
call GroupAddUnit(damaged, target)
call DestroyEffect(AddSpecialEffectTarget(sfx, target, attachPoint))
call UnitDamageTarget(source, target, damage, false, false, attacktype, damagetype, null)
call TimerStart(timer, interval, true, function thistype.onPeriod)
endif
call DestroyGroup(g)
set g = null
return this
endmethod
endstruct
/* ----------------------------------------- Dummy Pool ----------------------------------------- */
struct DummyPool
private static player player = Player(PLAYER_NEUTRAL_PASSIVE)
private static group group = CreateGroup()
timer timer
unit unit
static method recycle takes unit dummy returns nothing
if GetUnitTypeId(dummy) != DUMMY then
debug call BJDebugMsg("[DummyPool] Error: Trying to recycle a non dummy unit")
else
call GroupAddUnit(group, dummy)
call SetUnitX(dummy, WorldBounds.maxX)
call SetUnitY(dummy, WorldBounds.maxY)
call SetUnitOwner(dummy, player, false)
call ShowUnit(dummy, false)
call BlzPauseUnitEx(dummy, true)
endif
endmethod
static method retrieve takes player owner, real x, real y, real z, real face returns unit
if BlzGroupGetSize(group) > 0 then
set bj_lastCreatedUnit = FirstOfGroup(group)
call BlzPauseUnitEx(bj_lastCreatedUnit, false)
call ShowUnit(bj_lastCreatedUnit, true)
call GroupRemoveUnit(group, bj_lastCreatedUnit)
call SetUnitX(bj_lastCreatedUnit, x)
call SetUnitY(bj_lastCreatedUnit, y)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
call BlzSetUnitFacingEx(bj_lastCreatedUnit, face*bj_RADTODEG)
call SetUnitOwner(bj_lastCreatedUnit, owner, false)
else
set bj_lastCreatedUnit = CreateUnit(owner, DUMMY, x, y, face*bj_RADTODEG)
call SetUnitFlyHeight(bj_lastCreatedUnit, z, 0)
endif
return bj_lastCreatedUnit
endmethod
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call recycle(unit)
call ReleaseTimer(timer)
set timer = null
set unit = null
call deallocate()
endmethod
static method recycleTimed takes unit dummy, real delay returns nothing
local thistype this
if GetUnitTypeId(dummy) != DUMMY then
debug call BJDebugMsg("[DummyPool] Error: Trying to recycle a non dummy unit")
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = dummy
call TimerStart(timer, delay, false, function thistype.onExpire)
endif
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local unit u
loop
exitwhen i == 20
set u = CreateUnit(player, DUMMY, WorldBounds.maxX, WorldBounds.maxY, 0)
call BlzPauseUnitEx(u, false)
call GroupAddUnit(group, u)
set i = i + 1
endloop
set u = null
endmethod
endstruct
/* ----------------------------------------- Effect Link ---------------------------------------- */
struct EffectLink
static timer timer = CreateTimer()
//Dynamic Indexing for buff and timed
static integer didx = -1
static thistype array data
//Dynamic Indexing for items
static integer ditem = -1
static thistype array items
unit unit
effect effect
item item
integer buff
method remove takes integer i, boolean isItem returns integer
call DestroyEffect(effect)
if isItem then
set items[i] = items[ditem]
set ditem = ditem - 1
else
set data[i] = data[didx]
set didx = didx - 1
if didx == -1 then
call PauseTimer(timer)
endif
endif
set unit = null
set item = null
set effect = null
call deallocate()
return i - 1
endmethod
static method onDrop takes nothing returns nothing
local item j = GetManipulatedItem()
local integer i = 0
local thistype this
loop
exitwhen i > ditem
set this = items[i]
if item == j then
set i = remove(i, true)
endif
set i = i + 1
endloop
set j = null
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > didx
set this = data[i]
if GetUnitAbilityLevel(unit, buff) == 0 then
set i = remove(i, false)
endif
set i = i + 1
endloop
endmethod
static method BuffLink takes unit target, integer id, string model, string attach returns nothing
local thistype this = thistype.allocate()
set unit = target
set buff = id
set effect = AddSpecialEffectTarget(model, target, attach)
set didx = didx + 1
set data[didx] = this
if didx == 0 then
call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
static method ItemLink takes unit target, item i, string model, string attach returns nothing
local thistype this = thistype.allocate()
set item = i
set effect = AddSpecialEffectTarget(model, target, attach)
set ditem = ditem + 1
set items[ditem] = this
endmethod
static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.onDrop)
endmethod
endstruct
/* ----------------------------------- Start Ability Cooldown ----------------------------------- */
struct AbilityCooldown
timer timer
unit unit
integer ability
real newCd
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call BlzStartUnitAbilityCooldown(unit, ability, newCd)
call ReleaseTimer(timer)
call deallocate()
set timer = null
set unit = null
endmethod
static method start takes unit source, integer abilCode, real cooldown returns nothing
local thistype this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = source
set ability = abilCode
set newCd = cooldown
call TimerStart(timer, 0.01, false, function thistype.onExpire)
endmethod
endstruct
/* ------------------------------------- Destructable Timed ------------------------------------- */
struct TimedDestructable
private static constant real period = 0.03125000
private static timer timer = CreateTimer()
private static integer id = -1
private static thistype array array
destructable destructable
real duration
private method remove takes integer i returns integer
call RemoveDestructable(destructable)
set destructable = null
set array[i] = array[id]
set id = id - 1
if id == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > id
set this = array[i]
if duration <= 0 then
set i = remove(i)
endif
set duration = duration - period
set i = i + 1
endloop
endmethod
static method create takes destructable dest, real timeout returns thistype
local thistype this = thistype.allocate()
set destructable = dest
set duration = timeout
set id = id + 1
set array[id] = this
if id == 0 then
call TimerStart(timer, period, true, function thistype.onPeriod)
endif
return this
endmethod
endstruct
/* ----------------------------------------- Timed Pause ---------------------------------------- */
struct TimedPause
static integer array array
timer timer
unit unit
integer key
boolean flag
static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
set array[key] = array[key] - 1
if array[key] == 0 then
call BlzPauseUnitEx(unit, not flag)
endif
call ReleaseTimer(timer)
call deallocate()
set timer = null
set unit = null
endmethod
static method create takes unit u, real duration, boolean pause returns thistype
local thistype this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = u
set flag = pause
set key = GetUnitUserData(u)
if array[key] == 0 then
call BlzPauseUnitEx(u, pause)
endif
set array[key] = array[key] + 1
call TimerStart(timer, duration, false, function thistype.onExpire)
return this
endmethod
endstruct
endlibrary
library Indexer
/* ------------------------ Indexer v1.1 by Chopinski ----------------------- */
// Simple unit indexer for version 1.31+
// Simply copy and paste to import
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
struct Indexer
private static integer ability = 'Adef'
private static integer array array
private static integer key = -1
private static integer id = -1
readonly static unit unit
readonly static trigger onIndex = CreateTrigger()
readonly static trigger onDeindex = CreateTrigger()
private static method index takes unit source returns nothing
if GetUnitUserData(source) == 0 then
set unit = source
if key > - 1 then
set id = array[key]
set array[key] = 0
set key = key - 1
else
set id = id + 1
endif
if GetUnitAbilityLevel(unit, ability) == 0 then
call UnitAddAbility(unit, ability)
call UnitMakeAbilityPermanent(unit, true, ability)
call BlzUnitDisableAbility(unit, ability, true, true)
endif
call SetUnitUserData(unit, id)
call TriggerEvaluate(onIndex)
set unit = null
endif
endmethod
private static method onOrder takes nothing returns nothing
if GetIssuedOrderId() == 852056 then
if GetUnitAbilityLevel(GetTriggerUnit(), ability) == 0 then
set unit = GetTriggerUnit()
call TriggerEvaluate(onDeindex)
set key = key + 1
set array[key] = GetUnitUserData(unit)
set unit = null
endif
endif
endmethod
private static method onEnter takes nothing returns nothing
call index(GetFilterUnit())
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local region r = CreateRegion()
local rect map = GetWorldBounds()
local integer i = 0
call RegionAddRect(r, map)
call RemoveRect(map)
call TriggerRegisterEnterRegion(CreateTrigger(), r, Filter(function thistype.onEnter))
loop
exitwhen i == bj_MAX_PLAYER_SLOTS
call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), null)
loop
set unit = FirstOfGroup(bj_lastCreatedGroup)
exitwhen unit == null
call index(unit)
call GroupRemoveUnit(bj_lastCreatedGroup, unit)
endloop
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
set i = i + 1
endloop
call TriggerAddCondition(t, Filter(function thistype.onOrder))
set r = null
set map = null
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function RegisterUnitIndexEvent takes code c returns nothing
call TriggerAddCondition(Indexer.onIndex, Filter(c))
endfunction
function RegisterUnitDeindexEvent takes code c returns nothing
call TriggerAddCondition(Indexer.onDeindex, Filter(c))
endfunction
function GetIndexUnit takes nothing returns unit
return Indexer.unit
endfunction
endlibrary
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
library MouseUtils
/*
-------------------
MouseUtils
- MyPad
1.0.2.2
-------------------
----------------------------------------------------------------------------
A simple snippet that allows one to
conveniently use the mouse natives
as they were meant to be...
-------------------
| API |
-------------------
struct UserMouse extends array
static method operator [] (player p) -> thistype
- Returns the player's id + 1
static method getCurEventType() -> integer
- Returns the custom event that got executed.
method operator player -> player
- Returns Player(this - 1)
readonly real mouseX
readonly real mouseY
- Returns the current mouse coordinates.
readonly method operator isMouseClicked -> boolean
- Determines whether any mouse key has been clicked,
and will return true on the first mouse key.
method isMouseButtonClicked(mousebuttontype mouseButton)
- Returns true if the mouse button hasn't been
released yet.
method setMousePos(real x, y) (introduced in 1.0.2.2)
- Sets the mouse position for a given player.
static method registerCode(code c, integer ev) -> triggercondition
- Lets code run upon the execution of a certain event.
- Returns a triggercondition that can be removed later.
static method unregisterCallback(triggercondition trgHndl, integer ev)
- Removes a generated triggercondition from the trigger.
functions:
GetPlayerMouseX(player p) -> real
GetPlayerMouseY(player p) -> real
- Returns the coordinates of the mouse of the player.
OnMouseEvent(code func, integer eventId) -> triggercondition
- See UserMouse.registerCode
GetMouseEventType() -> integer
- See UserMouse.getCurEventType
UnregisterMouseCallback(triggercondition t, integer eventId)
- See UserMouse.unregisterCallback
SetUserMousePos(player p, real x, real y)
- See UserMouse.setMousePos
Unique Global Constants:
IMPL_LOCK (Introduced in v.1.0.2.2)
- Enables or disables the lock option
-------------------
| Credits |
-------------------
- Pyrogasm for pointing out a comparison logic flaw
in operator isMouseClicked.
- Illidan(Evil)X for the useful enum handles that
grant more functionality to this snippet.
- TriggerHappy for the suggestion to include
associated events and callbacks to this snippet.
- Quilnez for pointing out a bug related to the
method isMouseButtonClicked not working as intended
in certain situations.
----------------------------------------------------------------------------
*/
// Arbitrary constants
globals
constant integer EVENT_MOUSE_UP = 1024
constant integer EVENT_MOUSE_DOWN = 2048
constant integer EVENT_MOUSE_MOVE = 3072
private constant boolean IMPL_LOCK = false
endglobals
private module Init
private static method onInit takes nothing returns nothing
call thistype.init()
endmethod
endmodule
struct UserMouse extends array
static if IMPL_LOCK then
// Determines the minimum interval that a mouse move event detector
// will be deactivated. (Globally-based)
// You can configure it to any amount you like.
private static constant real INTERVAL = 0.031250000
// Determines how many times a mouse move event detector can fire
// before being deactivated. (locally-based)
// You can configure this to any integer value. (Preferably positive)
private static constant integer MOUSE_COUNT_MAX = 16
// Determines the amount to be deducted from mouseEventCount
// per INTERVAL. Runs independently of resetTimer
private static constant integer MOUSE_COUNT_LOSS = 8
private static constant boolean IS_INSTANT = INTERVAL <= 0.
endif
private static integer currentEventType = 0
private static integer updateCount = 0
private static trigger stateDetector = null
static if IMPL_LOCK and not IS_INSTANT then
private static timer resetTimer = null
endif
private static trigger array evTrigger
private static integer array mouseButtonStack
static if IMPL_LOCK and not IS_INSTANT then
private integer mouseEventCount
private timer mouseEventReductor
endif
private thistype next
private thistype prev
private thistype resetNext
private thistype resetPrev
private trigger posDetector
private integer mouseClickCount
readonly real mouseX
readonly real mouseY
// Converts the enum type mousebuttontype into an integer
private static method toIndex takes mousebuttontype mouseButton returns integer
return GetHandleId(mouseButton)
endmethod
static method getCurEventType takes nothing returns integer
return currentEventType
endmethod
static method operator [] takes player p returns thistype
if thistype(GetPlayerId(p) + 1).posDetector != null then
return GetPlayerId(p) + 1
endif
return 0
endmethod
method operator player takes nothing returns player
return Player(this - 1)
endmethod
method operator isMouseClicked takes nothing returns boolean
return .mouseClickCount > 0
endmethod
method isMouseButtonClicked takes mousebuttontype mouseButton returns boolean
return UserMouse.mouseButtonStack[(this - 1)*3 + UserMouse.toIndex(mouseButton)] > 0
endmethod
method setMousePos takes integer x, integer y returns nothing
if GetLocalPlayer() == this.player then
call BlzSetMousePos(x, y)
endif
endmethod
static if IMPL_LOCK then
private static method getMouseEventReductor takes timer t returns thistype
local thistype this = thistype(0).next
loop
exitwhen this.mouseEventReductor == t or this == 0
set this = this.next
endloop
return this
endmethod
private static method onMouseUpdateListener takes nothing returns nothing
local thistype this = thistype(0).resetNext
set updateCount = 0
loop
exitwhen this == 0
set updateCount = updateCount + 1
set this.mouseEventCount = 0
call EnableTrigger(this.posDetector)
set this.resetNext.resetPrev = this.resetPrev
set this.resetPrev.resetNext = this.resetNext
set this = this.resetNext
endloop
if updateCount > 0 then
static if not IS_INSTANT then
call TimerStart(resetTimer, INTERVAL, false, function thistype.onMouseUpdateListener)
else
call onMouseUpdateListener()
endif
else
static if not IS_INSTANT then
call TimerStart(resetTimer, 0.00, false, null)
call PauseTimer(resetTimer)
endif
endif
endmethod
private static method onMouseReductListener takes nothing returns nothing
local thistype this = getMouseEventReductor(GetExpiredTimer())
if this.mouseEventCount <= 0 then
call PauseTimer(this.mouseEventReductor)
else
set this.mouseEventCount = IMaxBJ(this.mouseEventCount - MOUSE_COUNT_LOSS, 0)
call TimerStart(this.mouseEventReductor, INTERVAL, false, function thistype.onMouseReductListener)
endif
endmethod
endif
private static method onMouseUpOrDown takes nothing returns nothing
local thistype this = thistype[GetTriggerPlayer()]
local integer index = (this - 1)*3 + UserMouse.toIndex(BlzGetTriggerPlayerMouseButton())
local boolean releaseFlag = false
if GetTriggerEventId() == EVENT_PLAYER_MOUSE_DOWN then
set this.mouseClickCount = IMinBJ(this.mouseClickCount + 1, 3)
set releaseFlag = UserMouse.mouseButtonStack[index] <= 0
set UserMouse.mouseButtonStack[index] = IMinBJ(UserMouse.mouseButtonStack[index] + 1, 1)
if releaseFlag then
set currentEventType = EVENT_MOUSE_DOWN
call TriggerEvaluate(evTrigger[EVENT_MOUSE_DOWN])
endif
else
set this.mouseClickCount = IMaxBJ(this.mouseClickCount - 1, 0)
set releaseFlag = UserMouse.mouseButtonStack[index] > 0
set UserMouse.mouseButtonStack[index] = IMaxBJ(UserMouse.mouseButtonStack[index] - 1, 0)
if releaseFlag then
set currentEventType = EVENT_MOUSE_UP
call TriggerEvaluate(evTrigger[EVENT_MOUSE_UP])
endif
endif
endmethod
private static method onMouseMove takes nothing returns nothing
local thistype this = thistype[GetTriggerPlayer()]
local boolean started = false
set this.mouseX = BlzGetTriggerPlayerMouseX()
set this.mouseY = BlzGetTriggerPlayerMouseY()
static if IMPL_LOCK then
set this.mouseEventCount = this.mouseEventCount + 1
if this.mouseEventCount <= 1 then
call TimerStart(this.mouseEventReductor, INTERVAL, false, function thistype.onMouseReductListener)
endif
endif
set currentEventType = EVENT_MOUSE_MOVE
call TriggerEvaluate(evTrigger[EVENT_MOUSE_MOVE])
static if IMPL_LOCK then
if this.mouseEventCount >= thistype.MOUSE_COUNT_MAX then
call DisableTrigger(this.posDetector)
if thistype(0).resetNext == 0 then
static if not IS_INSTANT then
call TimerStart(resetTimer, INTERVAL, false, function thistype.onMouseUpdateListener)
// Mouse event reductor should be paused
else
set started = true
endif
call PauseTimer(this.mouseEventReductor)
endif
set this.resetNext = 0
set this.resetPrev = this.resetNext.resetPrev
set this.resetPrev.resetNext = this
set this.resetNext.resetPrev = this
if started then
call onMouseUpdateListener()
endif
endif
endif
endmethod
private static method init takes nothing returns nothing
local thistype this = 1
local player p = this.player
static if IMPL_LOCK and not IS_INSTANT then
set resetTimer = CreateTimer()
endif
set stateDetector = CreateTrigger()
set evTrigger[EVENT_MOUSE_UP] = CreateTrigger()
set evTrigger[EVENT_MOUSE_DOWN] = CreateTrigger()
set evTrigger[EVENT_MOUSE_MOVE] = CreateTrigger()
call TriggerAddCondition( stateDetector, Condition(function thistype.onMouseUpOrDown))
loop
exitwhen integer(this) > bj_MAX_PLAYER_SLOTS
if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
set this.next = 0
set this.prev = thistype(0).prev
set thistype(0).prev.next = this
set thistype(0).prev = this
set this.posDetector = CreateTrigger()
static if IMPL_LOCK and not IS_INSTANT then
set this.mouseEventReductor = CreateTimer()
endif
call TriggerRegisterPlayerEvent( this.posDetector, p, EVENT_PLAYER_MOUSE_MOVE )
call TriggerAddCondition( this.posDetector, Condition(function thistype.onMouseMove))
call TriggerRegisterPlayerEvent( stateDetector, p, EVENT_PLAYER_MOUSE_UP )
call TriggerRegisterPlayerEvent( stateDetector, p, EVENT_PLAYER_MOUSE_DOWN )
endif
set this = this + 1
set p = this.player
endloop
endmethod
static method registerCode takes code handlerFunc, integer eventId returns triggercondition
return TriggerAddCondition(evTrigger[eventId], Condition(handlerFunc))
endmethod
static method unregisterCallback takes triggercondition whichHandler, integer eventId returns nothing
call TriggerRemoveCondition(evTrigger[eventId], whichHandler)
endmethod
implement Init
endstruct
function GetPlayerMouseX takes player p returns real
return UserMouse[p].mouseX
endfunction
function GetPlayerMouseY takes player p returns real
return UserMouse[p].mouseY
endfunction
function OnMouseEvent takes code func, integer eventId returns triggercondition
return UserMouse.registerCode(func, eventId)
endfunction
function GetMouseEventType takes nothing returns integer
return UserMouse.getCurEventType()
endfunction
function UnregisterMouseCallback takes triggercondition whichHandler, integer eventId returns nothing
call UserMouse.unregisterCallback(whichHandler, eventId)
endfunction
function SetUserMousePos takes player p, integer x, integer y returns nothing
call UserMouse[p].setMousePos(x, y)
endfunction
endlibrary
library WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
*
* Fields
* -------------------------
*
* 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 playMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set playMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set playMinX = GetRectMinX(bj_mapInitialPlayableArea)
set playMinY = GetRectMinY(bj_mapInitialPlayableArea)
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
readonly static real playMaxX
readonly static real playMaxY
readonly static real playMinX
readonly static real playMinY
implement WorldBoundInit
endstruct
endlibrary
library LineSegmentEnumeration /* v2.2a -- hiveworkshop.com/threads/line-segment-enumeration-v1-1.286552/
Information
¯¯¯¯¯¯¯¯¯¯¯
Allows to enumerate widgets inside a line segment with an offset.
So basicly it will result in a rect, but which is also allowed to be rotated.
Mechanics
¯¯¯¯¯¯¯¯¯
(Issue:)
The problem with normal jass rects is that they aren't defined by 4 points, but only by 4 values: x/y -min/max.
The result is that a jass rect is never rotated, so it's always paralel to the x/y axis.
But when we draw a line from point A to point B we might also create a non-axix-parelel rect, and then
we can't use the normal rect natives from jass anymore to find out if a point is inside the rect.
(Solution:)
To solve this problem the system does following:
jass rect: rectangular defined by 4 values (axis paralel)
custom rect: the real rectangular that is defined by user (not axis parelel)
1. Create a big jass rect that is big enough so we can ensure to enum all widgets that are potentialy inside our custom rect. (Enum_Group)
This Enum_Group will contain all wanted units, but may also contain not wanted units.
2. Construct the custom rect following a form with the same parameters as in this image, but in 2D:
https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Ellipsoide.svg/800px-Ellipsoide.svg.png
3. Loop through Enum_Group and define each widget's coordinates relative to the center of the custom rect as a 2D vector
4. Get the components of the widget's position vector on the local (rotated) x-y axis of the custom rect
5. Check if the projected lengths (absolute value of components) of the widget's position is less than <a> and <b> as described in the
image linked above.
*/
// --- API ---
//! novjass
struct LineSegment
static constant real MAX_UNIT_COLLISION
static method EnumUnitsEx takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolean checkCollision returns nothing
static method EnumUnits takes group whichgroup, real ax, real ay, real bx, real by, real offset returns nothing
static method EnumDestructables takes real ax, real ay, real bx, real by, real offset returns nothing
// after enumerated destructables you have access to:
static integer DestructableCounter // starts with index "0"
static destructable array Destructable
static method EnumItems takes real ax, real ay, real bx, real by, real offset returns nothing
// after enumerated items you have access to:
static integer ItemCounter // starts with index "0"
static destructable array Item
//! endnovjass
// ==== End API ====
struct LineSegment extends array
public static constant real MAX_UNIT_COLLISION = 197.00
private static constant rect RECT = Rect(0, 0, 0, 0)
private static constant group GROUP = CreateGroup()
private static real ox
private static real oy
private static real dx
private static real dy
private static real da
private static real db
private static real ui
private static real uj
private static real wdx
private static real wdy
private static method PrepareRect takes real ax, real ay, real bx, real by, real offset, real offsetCollision returns nothing
local real maxX
local real maxY
local real minX
local real minY
// get center coordinates of rectangle
set ox = 0.5*(ax + bx)
set oy = 0.5*(ay + by)
// get rectangle major axis as vector
set dx = 0.5*(bx - ax)
set dy = 0.5*(by - ay)
// get half of rectangle length (da) and height (db)
set da = SquareRoot(dx*dx + dy*dy)
set db = offset
// get unit vector of the major axis
set ui = dx/da
set uj = dy/da
// Prepare the bounding Jass Rect
set offset = offset + offsetCollision
if ax > bx then
set maxX = ax + offset
set minX = bx - offset
else
set maxX = bx + offset
set minX = ax - offset
endif
if ay > by then
set maxY = ay + offset
set minY = by - offset
else
set maxY = by + offset
set minY = ay - offset
endif
call SetRect(RECT, minX, minY, maxX, maxY)
endmethod
private static method RotateWidgetCoordinates takes widget w returns nothing
// distance of widget from rectangle center in vector form
set wdx = GetWidgetX(w) - ox
set wdy = GetWidgetY(w) - oy
set dx = wdx*ui + wdy*uj // get the component of above vector in the rect's major axis
set dy = wdx*(-uj) + wdy*ui // get the component of above vector in the rect's transverse axis
endmethod
private static method IsWidgetInRect takes widget w returns boolean
call RotateWidgetCoordinates(w)
// Check if the components above are less than half the length and height of the rectangle
// (Square them to compare absolute values)
return dx*dx <= da*da and dy*dy <= db*db
endmethod
private static method IsUnitInRect takes unit u, boolean checkCollision returns boolean
if checkCollision then
call RotateWidgetCoordinates(u)
// Check if the perpendicular distances of the unit from both axes of the rect are less than
// da and db
return IsUnitInRangeXY(u, ox - dy*uj, oy + dy*ui, RAbsBJ(da)) /*
*/ and IsUnitInRangeXY(u, ox + dx*ui, oy + dx*uj, RAbsBJ(db))
endif
return IsWidgetInRect(u)
endmethod
public static method EnumUnitsEx takes group whichgroup, real ax, real ay, real bx, real by, real offset, boolean checkCollision returns nothing
local unit u
if checkCollision then
call PrepareRect(ax, ay, bx, by, offset, MAX_UNIT_COLLISION)
else
call PrepareRect(ax, ay, bx, by, offset, 0.00)
endif
call GroupEnumUnitsInRect(GROUP, RECT, null)
// enum through all tracked units, and check if it's inside bounds
call GroupClear(whichgroup)
loop
set u = FirstOfGroup(GROUP)
exitwhen u == null
if IsUnitInRect(u, checkCollision) then
call GroupAddUnit(whichgroup, u)
endif
call GroupRemoveUnit(GROUP, u)
endloop
endmethod
public static method EnumUnits takes group whichgroup, real ax, real ay, real bx, real by, real offset returns nothing
call EnumUnitsEx(whichgroup, ax, ay, bx, by, offset, false)
endmethod
//! textmacro LSE_WIDGET takes TYPE, NAME
public static integer $NAME$Counter = -1
public static $TYPE$ array $NAME$
private static method on$NAME$Filter takes nothing returns nothing
local $TYPE$ t = GetFilter$NAME$()
if IsWidgetInRect(t) then
set $NAME$Counter = $NAME$Counter + 1
set $NAME$[$NAME$Counter] = t
endif
set t = null
endmethod
public static method Enum$NAME$s takes real ax, real ay, real bx, real by, real offset returns nothing
call PrepareRect(ax, ay, bx, by, offset, 0.00)
set $NAME$Counter = -1
call Enum$NAME$sInRect(RECT, Filter(function thistype.on$NAME$Filter), null)
endmethod
//! endtextmacro
//! runtextmacro LSE_WIDGET("destructable", "Destructable")
//! runtextmacro LSE_WIDGET("item", "Item")
endstruct
endlibrary
library TimedHandles uses optional TimerUtils
/**************************************************************
*
* v1.0.5 by TriggerHappy
* ----------------------
*
* Use this to destroy a handle after X amount seconds.
*
* It's useful for things like effects where you may
* want it to be temporary, but not have to worry
* about the cleaning memory leak. By default it supports
* effects, lightning, weathereffect, items, ubersplats, and units.
*
* If you want to add your own handle types copy a textmacro line
* at the bottom and add whichever handle you want along with it's destructor.
*
* Example: //! runtextmacro TIMEDHANDLES("handle", "DestroyHandle")
*
* Installation
----------------------
* 1. Copy this script and over to your map inside a blank trigger.
* 2. If you want more efficiency copy TimerUtils over as well.
*
* API
* ----------------------
* call DestroyEffectTimed(AddSpecialEffect("effect.mdx", 0, 0), 5)
* call DestroyLightningTimed(AddLightning("CLPB", true, 0, 0, 100, 100), 5)
*
* Credits to Vexorian for TimerUtils and his help on the script.
*
**************************************************************/
globals
// If you don't want a timer to be ran each instance
// set this to true.
private constant boolean SINGLE_TIMER = true
// If you chose a single timer then this will be the speed
// at which the timer will update
private constant real UPDATE_PERIOD = 0.05
endglobals
// here you may add or remove handle types
//! runtextmacro TIMEDHANDLES("effect", "DestroyEffect")
//! runtextmacro TIMEDHANDLES("lightning", "DestroyLightning")
//! runtextmacro TIMEDHANDLES("weathereffect", "RemoveWeatherEffect")
//! runtextmacro TIMEDHANDLES("item", "RemoveItem")
//! runtextmacro TIMEDHANDLES("unit", "RemoveUnit")
//! runtextmacro TIMEDHANDLES("ubersplat", "DestroyUbersplat")
// Do not edit below this line
//! textmacro TIMEDHANDLES takes HANDLE,DESTROY
struct $HANDLE$Timed
$HANDLE$ $HANDLE$_var
static integer index = -1
static thistype array instance
static real REAL=UPDATE_PERIOD
static if SINGLE_TIMER then
static timer timer = CreateTimer()
real duration
real elapsed = 0
else static if not LIBRARY.TimerUtils then
static hashtable table = InitHashtable()
endif
method destroy takes nothing returns nothing
call $DESTROY$(this.$HANDLE$_var)
set this.$HANDLE$_var = null
static if SINGLE_TIMER then
set this.elapsed = 0
endif
call this.deallocate()
endmethod
private static method remove takes nothing returns nothing
static if SINGLE_TIMER then
local integer i = 0
local thistype this
loop
exitwhen i > thistype.index
set this = instance[i]
set this.elapsed = this.elapsed + UPDATE_PERIOD
if (this.elapsed >= this.duration) then
set instance[i] = instance[index]
set i = i - 1
set index = index - 1
call this.destroy()
if (index == -1) then
call PauseTimer(thistype.timer)
endif
endif
set i = i + 1
endloop
else
local timer t = GetExpiredTimer()
static if LIBRARY.TimerUtils then
local $HANDLE$Timed this = GetTimerData(t)
call ReleaseTimer(t)
call this.destroy()
else
local $HANDLE$Timed this = LoadInteger(table, 0, GetHandleId(t))
call DestroyTimer(t)
set t = null
call this.destroy()
endif
endif
endmethod
static method create takes $HANDLE$ h, real timeout returns $HANDLE$Timed
local $HANDLE$Timed this = $HANDLE$Timed.allocate()
static if SINGLE_TIMER then
set index = index + 1
set instance[index] = this
if (index == 0) then
call TimerStart(thistype.timer, UPDATE_PERIOD, true, function thistype.remove)
endif
set this.duration = timeout
else
static if LIBRARY.TimerUtils then
call TimerStart(NewTimerEx(this), timeout, false, function $HANDLE$timed.remove)
else
local timer t = CreateTimer()
call SaveInteger(thistype.table, 0, GetHandleId(t), this)
call TimerStart(t, timeout, false, function $HANDLE$Timed.remove)
set t = null
endif
endif
set this.$HANDLE$_var = h
return this
endmethod
endstruct
function $DESTROY$Timed takes $HANDLE$ h, real duration returns $HANDLE$Timed
return $HANDLE$Timed.create(h, duration)
endfunction
//! endtextmacro
endlibrary
library PluginSpellEffect requires RegisterPlayerUnitEvent
/* ------------------- SpellEffectPlugin v1.2 by Chopinski ------------------ */
// Simple plugin for the SpellEffectEvent library by Bribe to cache some usefull
// values.
// Credits to Bribe and Magtheridon96
/* ----------------------------------- END ---------------------------------- */
private struct SUnit
unit unit
player player
integer handle
boolean isHero
boolean isStructure
integer id
real x
real y
real z
static method create takes nothing returns thistype
return thistype.allocate()
endmethod
endstruct
private module Event
readonly static location location = Location(0, 0)
readonly static SUnit source
readonly static SUnit target
readonly static ability ability
readonly static integer level
readonly static integer id
readonly static real x
readonly static real y
readonly static real z
private static method GetUnitZ takes unit u returns real
call MoveLocation(location, GetUnitX(u), GetUnitY(u))
return GetUnitFlyHeight(u) + GetLocationZ(location)
endmethod
private static method GetSpellTargetZ takes nothing returns real
call MoveLocation(location, x, y)
if target.unit != null then
return GetUnitZ(target.unit)
else
return GetLocationZ(location)
endif
endmethod
private static method onCast takes nothing returns nothing
if GetUnitAbilityLevel(GetTriggerUnit(), 'Aloc') == 0 then
set source.unit = GetTriggerUnit()
set source.player = GetOwningPlayer(source.unit)
set source.handle = GetHandleId(source.unit)
set source.id = GetUnitUserData(source.unit)
set source.x = GetUnitX(source.unit)
set source.y = GetUnitY(source.unit)
set source.z = GetUnitZ(source.unit)
set source.isHero = IsUnitType(source.unit, UNIT_TYPE_HERO)
set source.isStructure = IsUnitType(source.unit, UNIT_TYPE_STRUCTURE)
set target.unit = GetSpellTargetUnit()
set target.player = GetOwningPlayer(target.unit)
set target.handle = GetHandleId(target.unit)
set target.id = GetUnitUserData(target.unit)
set target.x = GetUnitX(target.unit)
set target.y = GetUnitY(target.unit)
set target.z = GetUnitZ(target.unit)
set target.isHero = IsUnitType(target.unit, UNIT_TYPE_HERO)
set target.isStructure = IsUnitType(target.unit, UNIT_TYPE_STRUCTURE)
set x = GetSpellTargetX()
set y = GetSpellTargetY()
set z = GetSpellTargetZ()
set id = GetSpellAbilityId()
set level = GetUnitAbilityLevel(source.unit, id)
set ability = BlzGetUnitAbility(source.unit, id)
endif
endmethod
private static method onInit takes nothing returns nothing
set source = SUnit.create()
set target = SUnit.create()
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
struct Spell extends array
implement Event
endstruct
endlibrary
//============================================================================
// 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
// 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.000 // Text size increase
private constant real TIME_LIFE = 1.0 // How long the text lasts
private constant real TIME_FADE = 0.3 // When does the text start to fade
private constant real Z_OFFSET = 50 // Height above unit
private constant real Z_OFFSET_BON = 50 // How much extra height the text gains
private constant real VELOCITY = 2 // 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 + .ac
set .y = .y + .as
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
/**************************************************************
*
* 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
library MissileEffect requires WorldBounds, Alloc
/* ------------------------------------- Missile Effect v2.8 ------------------------------------ */
// This is a simple helper library for the Relativistic Missiles system.
// Credits:
// Sevion for the Alloc module
// - www.hiveworkshop.com/threads/snippet-alloc.192348/
// Nestharus for World Bounds Library
/* ---------------------------------------- By Chopinski ---------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* System */
/* ---------------------------------------------------------------------------------------------- */
private module LinkedList
readonly thistype next
readonly thistype prev
method init takes nothing returns thistype
set next = this
set prev = this
return this
endmethod
method pushBack takes thistype node returns thistype
set node.prev = prev
set node.next = this
set prev.next = node
set prev = node
return node
endmethod
method pushFront takes thistype node returns thistype
set node.prev = this
set node.next = next
set next.prev = node
set next = node
return node
endmethod
method pop takes nothing returns nothing
set prev.next = next
set next.prev = prev
endmethod
endmodule
private struct Effect extends array
implement LinkedList
implement Alloc
real x
real y
real z
real size
real yaw
real pitch
real roll
string path
effect effect
method remove takes nothing returns nothing
call DestroyEffect(effect)
call pop()
call deallocate()
set effect = null
endmethod
method insert takes string fxpath, real x, real y, real z, real scale returns thistype
local thistype node = pushBack(allocate())
set node.x = x
set node.y = y
set node.z = z
set node.yaw = 0.
set node.pitch = 0.
set node.roll = 0.
set node.path = fxpath
set node.size = scale
set node.effect = AddSpecialEffect(fxpath, x, y)
call BlzSetSpecialEffectZ(node.effect, z)
call BlzSetSpecialEffectScale(node.effect, scale)
return node
endmethod
static method create takes nothing returns thistype
return thistype(allocate()).init()
endmethod
endstruct
struct MissileEffect
real size
real yaw
real pitch
real roll
real time
integer transparency
integer animtype
integer playercolor
string path
effect effect
Effect attachments
/* -------------------------------- Operators ------------------------------- */
method operator timeScale= takes real newTimeScale returns nothing
set time = newTimeScale
call BlzSetSpecialEffectTimeScale(effect, time)
endmethod
method operator timeScale takes nothing returns real
return time
endmethod
method operator alpha= takes integer newAlpha returns nothing
set transparency = newAlpha
call BlzSetSpecialEffectAlpha(effect, transparency)
endmethod
method operator alpha takes nothing returns integer
return transparency
endmethod
method operator playerColor= takes integer playerId returns nothing
set playercolor = playerId
call BlzSetSpecialEffectColorByPlayer(effect, Player(playerId))
endmethod
method operator playerColor takes nothing returns integer
return playercolor
endmethod
method operator animation= takes integer animType returns nothing
set animtype = animType
call BlzPlaySpecialEffect(effect, ConvertAnimType(animtype))
endmethod
method operator animation takes nothing returns integer
return animtype
endmethod
/* --------------------------------- Methods -------------------------------- */
method scale takes effect sfx, real scale returns nothing
set size = scale
call BlzSetSpecialEffectScale(sfx, scale)
endmethod
method orient takes real yaw, real pitch, real roll returns nothing
local Effect node = attachments.next
set .yaw = yaw
set .pitch = pitch
set .roll = roll
call BlzSetSpecialEffectOrientation(effect, yaw, pitch, roll)
loop
exitwhen node == attachments
set node.yaw = yaw
set node.pitch = pitch
set node.roll = roll
call BlzSetSpecialEffectOrientation(node.effect, yaw, pitch, roll)
set node = node.next
endloop
endmethod
method move takes real x, real y, real z returns boolean
local Effect node = attachments.next
if not (x > WorldBounds.maxX or x < WorldBounds.minX or y > WorldBounds.maxY or y < WorldBounds.minY) then
call BlzSetSpecialEffectPosition(effect, x, y, z)
loop
exitwhen node == attachments
call BlzSetSpecialEffectPosition(node.effect, x - node.x, y - node.y, z - node.z)
set node = node.next
endloop
return true
endif
return false
endmethod
method attach takes string fxpath, real dx, real dy, real dz, real scale returns effect
local Effect node = attachments.insert(fxpath, dx, dy, dz, scale)
call BlzSetSpecialEffectPosition(node.effect, BlzGetLocalSpecialEffectX(effect) - dx, BlzGetLocalSpecialEffectY(effect) - dy, BlzGetLocalSpecialEffectZ(effect) - dz)
return node.effect
endmethod
method detach takes effect sfx returns nothing
local Effect node = attachments.next
loop
exitwhen node == attachments
if GetHandleId(node.effect) == GetHandleId(sfx) then
call node.remove()
exitwhen true
endif
set node = node.next
endloop
endmethod
method setColor takes integer red, integer green, integer blue returns nothing
call BlzSetSpecialEffectColor(effect, red, green, blue)
endmethod
/* -------------------------- Contructor/Destructor ------------------------- */
method destroy takes nothing returns nothing
local Effect node = attachments.next
loop
exitwhen node == attachments
call node.remove()
set node = node.next
endloop
call DestroyEffect(effect)
call attachments.deallocate()
set effect = null
set path = null
set size = 1.
call deallocate()
endmethod
static method create takes real x, real y, real z returns thistype
local thistype this = thistype.allocate()
set effect = AddSpecialEffect("", x, y)
set path = ""
set size = 1
set time = 0
set transparency = 0
set animtype = 0
set playercolor = 0
set attachments = Effect.create()
call BlzSetSpecialEffectZ(effect, z)
return this
endmethod
endstruct
endlibrary
library MissileUtils requires Missiles, Alloc
/* ------------------------------------- Missile Utils v2.8 ------------------------------------- */
// This is a simple Utils library for the Relativistic Missiles system.
// Credits:
// Sevion for the Alloc module
// - www.hiveworkshop.com/threads/snippet-alloc.192348/
/* ---------------------------------------- By Chopinski ---------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* JASS API */
/* ---------------------------------------------------------------------------------------------- */
function CreateMissileGroup takes nothing returns MissileGroup
return MissileGroup.create()
endfunction
function DestroyMissileGroup takes MissileGroup missiles returns nothing
if missiles != 0 then
call missiles.clear()
call missiles.destroy()
endif
endfunction
function MissileGroupGetSize takes MissileGroup missiles returns integer
if missiles != 0 then
return missiles.size
else
return 0
endif
endfunction
function GroupMissileAt takes MissileGroup missiles, integer position returns Missiles
if missiles != 0 then
return missiles.missileAt(position)
else
return 0
endif
endfunction
function ClearMissileGroup takes MissileGroup missiles returns nothing
if missiles != 0 then
call missiles.clear()
endif
endfunction
function IsMissileInGroup takes Missiles missile, MissileGroup missiles returns boolean
if missiles != 0 and missile != 0 then
if missiles.size > 0 then
return missiles.contains(missile)
else
return false
endif
else
return false
endif
endfunction
function GroupRemoveMissile takes MissileGroup missiles, Missiles missile returns nothing
if missiles != 0 and missile != 0 then
if missiles.size > 0 then
call missiles.remove(missile)
endif
endif
endfunction
function GroupAddMissile takes MissileGroup missiles, Missiles missile returns nothing
if missiles != 0 and missile != 0 then
if not missiles.contains(missile) then
call missiles.insert(missile)
endif
endif
endfunction
function GroupPickRandomMissile takes MissileGroup missiles returns Missiles
if missiles != 0 then
if missiles.size > 0 then
return missiles.missileAt(GetRandomInt(0, missiles.size - 1))
else
return 0
endif
else
return 0
endif
endfunction
function FirstOfMissileGroup takes MissileGroup missiles returns Missiles
if missiles != 0 then
if missiles.size > 0 then
return missiles.group.next.missile
else
return 0
endif
else
return 0
endif
endfunction
function GroupAddMissileGroup takes MissileGroup source, MissileGroup destiny returns nothing
if source != 0 and destiny != 0 then
if source.size > 0 and source != destiny then
call destiny.addGroup(source)
endif
endif
endfunction
function GroupRemoveMissileGroup takes MissileGroup source, MissileGroup destiny returns nothing
if source != 0 and destiny != 0 then
if source == destiny then
call source.clear()
elseif source.size > 0 then
call destiny.removeGroup(source)
endif
endif
endfunction
function GroupEnumMissilesOfType takes MissileGroup missiles, integer whichType returns nothing
local integer i
local Missiles missile
if missiles != 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count
set missile = Missiles.collection[i]
if missile.type == whichType then
call missiles.insert(missile)
endif
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesOfTypeCounted takes MissileGroup missiles, integer whichType, integer amount returns nothing
local integer i
local integer j = amount
local Missiles missile
if missiles != 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count or j == 0
set missile = Missiles.collection[i]
if missile.type == whichType then
call missiles.insert(missile)
endif
set j = j - 1
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesOfPlayer takes MissileGroup missiles, player p returns nothing
local integer i
local Missiles missile
if missiles != 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count
set missile = Missiles.collection[i]
if missile.owner == p then
call missiles.insert(missile)
endif
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesOfPlayerCounted takes MissileGroup missiles, player p, integer amount returns nothing
local integer i
local integer j = amount
local Missiles missile
if missiles != 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count or j == 0
set missile = Missiles.collection[i]
if missile.owner == p then
call missiles.insert(missile)
endif
set j = j - 1
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRect takes MissileGroup missiles, rect r returns nothing
local integer i
local Missiles missile
if missiles != 0 and r != null then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count
set missile = Missiles.collection[i]
if GetRectMinX(r) <= missile.x and missile.x <= GetRectMaxX(r) and GetRectMinY(r) <= missile.y and missile.y <= GetRectMaxY(r) then
call missiles.insert(missile)
endif
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRectCounted takes MissileGroup missiles, rect r, integer amount returns nothing
local integer i
local integer j = amount
local Missiles missile
if missiles != 0 and r != null then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count or j == 0
set missile = Missiles.collection[i]
if GetRectMinX(r) <= missile.x and missile.x <= GetRectMaxX(r) and GetRectMinY(r) <= missile.y and missile.y <= GetRectMaxY(r) then
call missiles.insert(missile)
endif
set j = j - 1
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRangeOfLoc takes MissileGroup missiles, location loc, real radius returns nothing
local real dx
local real dy
local integer i
local Missiles missile
if missiles != 0 and radius > 0 and loc != null then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count
set missile = Missiles.collection[i]
set dx = missile.x - GetLocationX(loc)
set dy = missile.y - GetLocationY(loc)
if SquareRoot(dx*dx + dy*dy) <= radius then
call missiles.insert(missile)
endif
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRangeOfLocCounted takes MissileGroup missiles, location loc, real radius, integer amount returns nothing
local real dx
local real dy
local integer i
local integer j = amount
local Missiles missile
if missiles != 0 and radius > 0 and loc != null then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count or j == 0
set missile = Missiles.collection[i]
set dx = missile.x - GetLocationX(loc)
set dy = missile.y - GetLocationY(loc)
if SquareRoot(dx*dx + dy*dy) <= radius then
call missiles.insert(missile)
endif
set j = j - 1
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRange takes MissileGroup missiles, real x, real y, real radius returns nothing
local real dx
local real dy
local integer i
local Missiles missile
if missiles != 0 and radius > 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count
set missile = Missiles.collection[i]
set dx = missile.x - x
set dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= radius then
call missiles.insert(missile)
endif
set i = i + 1
endloop
endif
endif
endfunction
function GroupEnumMissilesInRangeCounted takes MissileGroup missiles, real x, real y, real radius, integer amount returns nothing
local real dx
local real dy
local integer i
local integer j = amount
local Missiles missile
if missiles != 0 and radius > 0 then
if Missiles.count > -1 then
set i = 0
if missiles.size > 0 then
call missiles.clear()
endif
loop
exitwhen i > Missiles.count or j == 0
set missile = Missiles.collection[i]
set dx = missile.x - x
set dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= radius then
call missiles.insert(missile)
endif
set j = j - 1
set i = i + 1
endloop
endif
endif
endfunction
/* ---------------------------------------------------------------------------------------------- */
/* System */
/* ---------------------------------------------------------------------------------------------- */
private module LinkedList
readonly thistype next
readonly thistype prev
method init takes nothing returns thistype
set next = this
set prev = this
return this
endmethod
method pushBack takes thistype node returns thistype
set node.prev = prev
set node.next = this
set prev.next = node
set prev = node
return node
endmethod
method pushFront takes thistype node returns thistype
set node.prev = this
set node.next = next
set next.prev = node
set next = node
return node
endmethod
method pop takes nothing returns nothing
set prev.next = next
set next.prev = prev
endmethod
endmodule
private struct MGroup extends array
implement LinkedList
implement Alloc
Missiles missile
method remove takes nothing returns nothing
call pop()
call deallocate()
endmethod
method insert takes Missiles m returns thistype
local thistype node = pushBack(allocate())
set node.missile = m
return node
endmethod
static method create takes nothing returns thistype
return thistype(allocate()).init()
endmethod
endstruct
struct MissileGroup
MGroup group
integer size
method destroy takes nothing returns nothing
call group.deallocate()
call deallocate()
endmethod
method missileAt takes integer i returns Missiles
local MGroup node = group.next
local integer j = 0
if size > 0 and i <= size - 1 then
loop
exitwhen j == i
set node = node.next
set j = j + 1
endloop
return node.missile
else
return 0
endif
endmethod
method remove takes Missiles missile returns nothing
local MGroup node = group.next
loop
exitwhen node == group
if node.missile == missile then
set size = size - 1
call node.remove()
exitwhen true
endif
set node = node.next
endloop
endmethod
method insert takes Missiles missile returns nothing
set size = size + 1
call group.insert(missile)
endmethod
method clear takes nothing returns nothing
local MGroup node = group.next
loop
exitwhen node == group
call node.remove()
set node = node.next
endloop
set size = 0
endmethod
method contains takes Missiles missile returns boolean
local MGroup node = group.next
local boolean found = false
loop
exitwhen node == group
if node.missile == missile then
set found = true
exitwhen true
endif
set node = node.next
endloop
return found
endmethod
method addGroup takes MissileGroup source returns nothing
local MGroup node = source.group.next
loop
exitwhen node == source.group
if not contains(node.missile) then
call insert(node.missile)
endif
set node = node.next
endloop
endmethod
method removeGroup takes MissileGroup source returns nothing
local MGroup node = source.group.next
loop
exitwhen node == source.group
if contains(node.missile) then
call remove(node.missile)
endif
set node = node.next
endloop
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set group = MGroup.create()
set size = 0
return this
endmethod
endstruct
endlibrary
library Missiles requires MissileEffect, TimerUtils, WorldBounds
/* ---------------------------------------- Missiles v2.8 --------------------------------------- */
// Thanks and Credits to BPower, Dirac and Vexorian for the Missile Library's at which i based
// this Missiles library. Credits and thanks to AGD and for the effect orientation ideas.
// This version of Missiles requires patch 1.31+
// How to Import:
// 1 - Copy this, MissileEffect and optionaly the MissileUtils libraries to your map
/* ---------------------------------------- By Chopinski ---------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* System */
/* ---------------------------------------------------------------------------------------------- */
globals
// The update period of the system
public constant real PERIOD = 1./40.
// The max amount of Missiles processed in a PERIOD
// You can play around with both these values to find
// your sweet spot. If equal to 0, the system will
// process all missiles at once every period.
public constant real SWEET_SPOT = 150
// the avarage collision size compensation when detecting collisions
private constant real COLLISION_SIZE = 128.
// item size used in z collision
private constant real ITEM_SIZE = 16.
// Raw code of the dummy unit used for vision
private constant integer DUMMY = 'dumi'
// Needed, don't touch.
private location LOC = Location(0., 0.)
endglobals
private interface MissileEvents
method onHit takes unit hit returns boolean defaults false
method onMissile takes Missiles missile returns boolean defaults false
method onDestructable takes destructable dest returns boolean defaults false
method onItem takes item i returns boolean defaults false
method onCliff takes nothing returns boolean defaults false
method onTerrain takes nothing returns boolean defaults false
method onTileset takes integer tileset returns boolean defaults false
method onPeriod takes nothing returns boolean defaults false
method onFinish takes nothing returns boolean defaults false
method onBoundaries takes nothing returns boolean defaults false
method onPause takes nothing returns boolean defaults false
method onResume takes nothing returns boolean defaults false
method onRemove takes nothing returns nothing defaults nothing
endinterface
private function GetLocZ takes real x, real y returns real
call MoveLocation(LOC, x, y)
return GetLocationZ(LOC)
endfunction
private function GetUnitZ takes unit u returns real
return GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
endfunction
private function SetUnitZ takes unit u, real z returns nothing
call SetUnitFlyHeight(u, z - GetLocZ(GetUnitX(u), GetUnitY(u)), 0)
endfunction
private function GetMapCliffLevel takes nothing returns integer
return GetTerrainCliffLevel(WorldBounds.maxX, WorldBounds.maxY)
endfunction
private struct Pool
private static player player = Player(PLAYER_NEUTRAL_PASSIVE)
private static group group = CreateGroup()
timer timer
unit unit
static method recycle takes unit dummy returns nothing
if GetUnitTypeId(dummy) == DUMMY then
call GroupAddUnit(group, dummy)
call SetUnitX(dummy, WorldBounds.maxX)
call SetUnitY(dummy, WorldBounds.maxY)
call SetUnitOwner(dummy, player, false)
call PauseUnit(dummy, true)
endif
endmethod
static method retrieve takes real x, real y, real z, real face returns unit
if BlzGroupGetSize(group) > 0 then
set bj_lastCreatedUnit = FirstOfGroup(group)
call PauseUnit(bj_lastCreatedUnit, false)
call GroupRemoveUnit(group, bj_lastCreatedUnit)
call SetUnitX(bj_lastCreatedUnit, x)
call SetUnitY(bj_lastCreatedUnit, y)
call SetUnitZ(bj_lastCreatedUnit, z)
call BlzSetUnitFacingEx(bj_lastCreatedUnit, face)
else
set bj_lastCreatedUnit = CreateUnit(player, DUMMY, x, y, face)
call SetUnitZ(bj_lastCreatedUnit, z)
call UnitRemoveAbility(bj_lastCreatedUnit, 'Amrf')
endif
return bj_lastCreatedUnit
endmethod
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call recycle(unit)
call ReleaseTimer(timer)
set timer = null
set unit = null
call deallocate()
endmethod
static method recycleTimed takes unit dummy, real delay returns nothing
local thistype this
if GetUnitTypeId(dummy) != DUMMY then
debug call BJDebugMsg("[DummyPool] Error: Trying to recycle a non dummy unit")
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = dummy
call TimerStart(timer, delay, false, function thistype.onExpire)
endif
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local unit u
loop
exitwhen i == SWEET_SPOT
set u = CreateUnit(player, DUMMY, WorldBounds.maxX, WorldBounds.maxY, 0)
call PauseUnit(u, false)
call GroupAddUnit(group, u)
call UnitRemoveAbility(u, 'Amrf')
set i = i + 1
endloop
set u = null
endmethod
endstruct
private struct Coordinates
readonly real x
readonly real y
readonly real z
readonly real angle
readonly real distance
readonly real square
readonly real slope
readonly real alpha
// Creates an origin - impact link.
private thistype ref
private static method math takes thistype a, thistype b returns nothing
local real dx
local real dy
loop
set dx = b.x - a.x
set dy = b.y - a.y
set dx = dx*dx + dy*dy
set dy = SquareRoot(dx)
exitwhen dx != 0. and dy != 0.
set b.x = b.x + .01
set b.z = b.z - GetLocZ(b.x -.01, b.y) + GetLocZ(b.x, b.y)
endloop
set a.square = dx
set a.distance = dy
set a.angle = Atan2(b.y - a.y, b.x - a.x)
set a.slope = (b.z - a.z)/dy
set a.alpha = Atan(a.slope)
// Set b.
if b.ref == a then
set b.angle = a.angle + bj_PI
set b.distance = dy
set b.slope = -a.slope
set b.alpha = -a.alpha
set b.square = dx
endif
endmethod
static method link takes thistype a, thistype b returns nothing
set a.ref = b
set b.ref = a
call math(a, b)
endmethod
method move takes real toX, real toY, real toZ returns nothing
set x = toX
set y = toY
set z = toZ + GetLocZ(toX, toY)
if ref != this then
call math(this, ref)
endif
endmethod
method destroy takes nothing returns nothing
call .deallocate()
endmethod
static method create takes real x, real y, real z returns Coordinates
local thistype this = thistype.allocate()
set ref = this
call move(x, y, z)
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private module OnHit
set o = origin
set h = height
set c = open
set d = o.distance
if .onHit.exists then
if allocated and collision > 0 then
call GroupEnumUnitsInRange(group, x, y, collision + COLLISION_SIZE, null)
loop
set u = FirstOfGroup(group)
exitwhen u == null
if not HaveSavedBoolean(table, this, GetHandleId(u)) then
if IsUnitInRangeXY(u, x, y, collision) then
if collideZ then
set dx = GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
set dy = BlzGetUnitCollisionSize(u)
if dx + dy >= z - collision and dx <= z + collision then
call SaveBoolean(table, this, GetHandleId(u), true)
if allocated and .onHit(u) then
call terminate()
exitwhen true
endif
endif
else
call SaveBoolean(table, this, GetHandleId(u), true)
if allocated and .onHit(u) then
call terminate()
exitwhen true
endif
endif
endif
endif
call GroupRemoveUnit(group, u)
endloop
endif
endif
endmodule
private module OnMissile
if .onMissile.exists then
if allocated and collision > 0 then
set k = 0
loop
exitwhen k > count
set missile = collection[k]
if missile != this then
if not HaveSavedBoolean(table, this, missile) then
set dx = missile.x - x
set dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= collision then
call SaveBoolean(table, this, missile, true)
if allocated and .onMissile(missile) then
call terminate()
exitwhen true
endif
endif
endif
endif
set k = k + 1
endloop
endif
endif
endmodule
private module OnDestructable
if .onDestructable.exists then
if allocated and collision > 0 then
set dx = collision
call SetRect(rect, x - dx, y - dx, x + dx, y + dx)
call EnumDestructablesInRect(rect, null, function thistype.onDest)
endif
endif
endmodule
private module OnItem
if .onItem.exists then
if allocated and collision > 0 then
set dx = collision
call SetRect(rect, x - dx, y - dx, x + dx, y + dx)
call EnumItemsInRect(rect, null, function thistype.onItems)
endif
endif
endmodule
private module OnCliff
if .onCliff.exists then
set dx = GetTerrainCliffLevel(nextX, nextY)
set dy = GetTerrainCliffLevel(x, y)
if dy < dx and z < (dx - GetMapCliffLevel())*bj_CLIFFHEIGHT then
if allocated and .onCliff() then
call terminate()
endif
endif
endif
endmodule
private module OnTerrain
if .onTerrain.exists then
if GetLocZ(x, y) > z then
if allocated and .onTerrain() then
call terminate()
endif
endif
endif
endmodule
private module OnTileset
if .onTileset.exists then
set k = GetTerrainType(x, y)
if k != tileset then
if allocated and .onTileset(k) then
call terminate()
endif
endif
set tileset = k
endif
endmodule
private module OnPeriod
if .onPeriod.exists then
if allocated and .onPeriod() then
call terminate()
endif
endif
endmodule
private module OnOrient
// Homing or not
set u = target
if u != null and GetUnitTypeId(u) != 0 then
call impact.move(GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u) + toZ)
set dx = impact.x - nextX
set dy = impact.y - nextY
set a = Atan2(dy, dx)
set travel = o.distance - SquareRoot(dx*dx + dy*dy)
else
set a = o.angle
set target = null
endif
// turn rate
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 vel = veloc*dilation
set yaw = cA
set s = travel + vel
set veloc = veloc + acceleration
set travel = s
set pitch = o.alpha
set prevX = x
set prevY = y
set prevZ = z
set x = nextX
set y = nextY
set z = nextZ
set nextX = x + vel*Cos(yaw)
set nextY = y + vel*Sin(yaw)
// arc calculation
if h != 0 or o.slope != 0 then
set nextZ = 4*h*s*(d-s)/(d*d) + o.slope*s + o.z
set pitch = pitch - Atan(((4*h)*(2*s - d))/(d*d))
endif
// curve calculation
if c != 0 then
set dx = 4*c*s*(d-s)/(d*d)
set a = yaw + bj_PI/2
set x = x + dx*Cos(a)
set y = y + dx*Sin(a)
set yaw = yaw + Atan(-((4*c)*(2*s - d))/(d*d))
endif
endmodule
private module OnFinish
if s >= d - 0.0001 then
set finished = true
if .onFinish.exists then
if allocated and .onFinish() then
call terminate()
else
if travel > 0 and not paused then
call terminate()
endif
endif
else
call terminate()
endif
else
if not roll then
call effect.orient(yaw, -pitch, 0)
else
call effect.orient(yaw, -pitch, Atan2(c, h))
endif
endif
endmodule
private module OnBoundaries
if not effect.move(x, y, z) then
if .onBoundaries.exists then
if allocated and .onBoundaries() then
call terminate()
endif
endif
else
if dummy != null then
call SetUnitX(dummy, x)
call SetUnitY(dummy, y)
endif
endif
endmodule
private module OnPause
set pid = pid + 1
set pkey = pid
set frozen[pid] = this
if .onPause.exists then
if allocated and .onPause() then
call terminate()
endif
endif
endmodule
private module OnResume
local thistype aux
set paused = flag
if not paused and pkey != -1 then
set id = id + 1
set missiles[id] = this
set aux = frozen[pid]
set aux.pkey = pkey
set frozen[pkey] = frozen[pid]
set pid = pid - 1
set pkey = -1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1.
endif
if id == 0 then
call TimerStart(timer, PERIOD, true, function thistype.move)
endif
if .onResume.exists then
if allocated and .onResume() then
call terminate()
else
if finished then
call terminate()
endif
endif
else
if finished then
call terminate()
endif
endif
endif
endmodule
private module OnRemove
local thistype aux
if allocated and launched then
set allocated = false
if pkey != -1 then
set aux = frozen[pid]
set aux.pkey = pkey
set frozen[pkey] = frozen[pid]
set pid = pid - 1
set pkey = -1
endif
if .onRemove.exists then
call .onRemove()
endif
if dummy != null then
call Pool.recycle(dummy)
endif
set aux = collection[count]
set aux.index = index
set collection[index] = collection[count]
set count = count - 1
set index = -1
call origin.destroy()
call impact.destroy()
call effect.destroy()
call reset()
call FlushChildHashtable(table, this)
endif
endmodule
private module Operators
/* -------------------------- Model of the missile -------------------------- */
method operator model= takes string fx returns nothing
call DestroyEffect(effect.effect)
set effect.path = fx
set effect.effect = AddSpecialEffect(fx, origin.x, origin.y)
call BlzSetSpecialEffectZ(effect.effect, origin.z)
call BlzSetSpecialEffectYaw(effect.effect, cA)
endmethod
method operator model takes nothing returns string
return effect.path
endmethod
/* ----------------------------- Curved movement ---------------------------- */
method operator curve= takes real value returns nothing
set open = Tan(value*bj_DEGTORAD)*origin.distance
endmethod
method operator curve takes nothing returns real
return Atan(open/origin.distance)*bj_RADTODEG
endmethod
/* ----------------------------- Arced Movement ----------------------------- */
method operator arc= takes real value returns nothing
set height = Tan(value*bj_DEGTORAD)*origin.distance/4
endmethod
method operator arc takes nothing returns real
return Atan(4*height/origin.distance)*bj_RADTODEG
endmethod
/* ------------------------------ Effect scale ------------------------------ */
method operator scale= takes real value returns nothing
set effect.size = value
call effect.scale(effect.effect, value)
endmethod
method operator scale takes nothing returns real
return effect.size
endmethod
/* ------------------------------ Missile Speed ----------------------------- */
method operator speed= takes real newspeed returns nothing
local real d = origin.distance
local real s
local real vel
set veloc = newspeed*PERIOD
set vel = veloc*dilation
set s = travel + vel
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
if height != 0 or origin.slope != 0 then
set nextZ = 4*height*s*(d-s)/(d*d) + origin.slope*s + origin.z
set z = nextZ
endif
endmethod
method operator speed takes nothing returns real
return veloc/PERIOD
endmethod
/* ------------------------------- Flight Time ------------------------------ */
method operator duration= takes real flightTime returns nothing
local real d = origin.distance
local real s
local real vel
set veloc = RMaxBJ(0.00000001, (origin.distance - travel)*PERIOD/RMaxBJ(0.00000001, flightTime))
set time = flightTime
set vel = veloc*dilation
set s = travel + vel
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
if height != 0 or origin.slope != 0 then
set nextZ = 4*height*s*(d-s)/(d*d) + origin.slope*s + origin.z
set z = nextZ
endif
endmethod
method operator duration takes nothing returns real
return time
endmethod
/* ------------------------------- Sight Range ------------------------------ */
method operator vision= takes real sightRange returns nothing
set sight = sightRange
if dummy == null then
if owner == null then
if source != null then
set dummy = Pool.retrieve(x, y, z, 0)
call SetUnitOwner(dummy, GetOwningPlayer(source), false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
else
set dummy = Pool.retrieve(x, y, z, 0)
call SetUnitOwner(dummy, owner, false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
else
call SetUnitOwner(dummy, owner, false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
endmethod
method operator vision takes nothing returns real
return sight
endmethod
/* ------------------------------- Time Scale ------------------------------- */
method operator timeScale= takes real newTimeScale returns nothing
set effect.timeScale = newTimeScale
endmethod
method operator timeScale takes nothing returns real
return effect.timeScale
endmethod
/* ---------------------------------- Alpha --------------------------------- */
method operator alpha= takes integer newAlpha returns nothing
set effect.alpha = newAlpha
endmethod
method operator alpha takes nothing returns integer
return effect.alpha
endmethod
/* ------------------------------ Player Color ------------------------------ */
method operator playerColor= takes integer playerId returns nothing
set effect.playerColor = playerId
endmethod
method operator playerColor takes nothing returns integer
return effect.playerColor
endmethod
/* -------------------------------- Animation ------------------------------- */
method operator animation= takes integer animType returns nothing
set effect.animation = animType
endmethod
method operator animation takes nothing returns integer
return effect.animation
endmethod
endmodule
private module Methods
/* --------------------------- Bounce and Deflect --------------------------- */
method bounce takes nothing returns nothing
call origin.move(x, y, z - GetLocZ(x, y))
set travel = 0
set finished = false
endmethod
method deflect takes real tx, real ty, real tz returns nothing
local real locZ = GetLocZ(x, y)
set target = null
set toZ = tz
if z < locZ and .onTerrain.exists then
set nextX = prevX
set nextY = prevY
set nextZ = prevZ
endif
call impact.move(tx, ty, tz)
call origin.move(x, y, z - locZ)
set travel = 0
set finished = false
endmethod
method deflectTarget takes unit u returns nothing
call deflect(GetUnitX(u), GetUnitY(u), toZ)
set target = u
endmethod
/* ---------------------------- Flush hit targets --------------------------- */
method flushAll takes nothing returns nothing
call FlushChildHashtable(table, this)
endmethod
method flush takes widget w returns nothing
if w != null then
call RemoveSavedBoolean(table, this, GetHandleId(w))
endif
endmethod
method hitted takes widget w returns boolean
return HaveSavedBoolean(table, this, GetHandleId(w))
endmethod
/* ----------------------- Missile attachment methods ----------------------- */
method attach takes string model, real dx, real dy, real dz, real scale returns effect
return effect.attach(model, dx, dy, dz, scale)
endmethod
method detach takes effect attachment returns nothing
if attachment != null then
call effect.detach(attachment)
endif
endmethod
/* ------------------------------ Missile Pause ----------------------------- */
method pause takes boolean flag returns nothing
implement OnResume
endmethod
/* ---------------------------------- Color --------------------------------- */
method color takes integer red, integer green, integer blue returns nothing
call effect.setColor(red, green, blue)
endmethod
/* ---------------------- Destructable collision method --------------------- */
static method onDest takes nothing returns nothing
local thistype this = temp
local destructable d = GetEnumDestructable()
local real dz
local real tz
if not HaveSavedBoolean(table, this, GetHandleId(d)) then
if collideZ then
set dz = GetLocZ(GetWidgetX(d), GetWidgetY(d))
set tz = GetDestructableOccluderHeight(d)
if dz + tz >= z - collision and dz <= z + collision then
call SaveBoolean(table, this, GetHandleId(d), true)
if allocated and .onDestructable(d) then
set d = null
call terminate()
return
endif
endif
else
call SaveBoolean(table, this, GetHandleId(d), true)
if allocated and .onDestructable(d) then
set d = null
call terminate()
return
endif
endif
endif
set d = null
endmethod
/* -------------------------- Item collision method ------------------------- */
static method onItems takes nothing returns nothing
local thistype this = temp
local item i = GetEnumItem()
local real dz
if not HaveSavedBoolean(table, this, GetHandleId(i)) then
if collideZ then
set dz = GetLocZ(GetItemX(i), GetItemY(i))
if dz + ITEM_SIZE >= z - collision and dz <= z + collision then
call SaveBoolean(table, this, GetHandleId(i), true)
if allocated and .onItem(i) then
set i = null
call terminate()
return
endif
endif
else
call SaveBoolean(table, this, GetHandleId(i), true)
if allocated and .onItem(i) then
set i = null
call terminate()
return
endif
endif
endif
set i = null
endmethod
/* -------------------------------- Terminate ------------------------------- */
method terminate takes nothing returns nothing
implement OnRemove
endmethod
endmodule
struct Missiles extends MissileEvents
private static timer timer = CreateTimer()
private static group group = CreateGroup()
private static rect rect = Rect(0., 0., 0., 0.)
private static hashtable table = InitHashtable()
private static integer last = 0
private static thistype temp = 0
private static integer id = -1
private static integer pid = -1
private static thistype array missiles
private static thistype array frozen
private static real dilation = 1
readonly static thistype array collection
readonly static integer count = -1
private real cA
private real height
private real open
private real toZ
private real time
private real sight
private unit dummy
private integer pkey
private integer index
Coordinates impact
Coordinates origin
MissileEffect effect
readonly real x
readonly real y
readonly real z
readonly real prevX
readonly real prevY
readonly real prevZ
readonly real nextX
readonly real nextY
readonly real nextZ
readonly real turn
readonly real veloc
readonly real travel
readonly boolean launched
readonly boolean allocated
readonly boolean finished
readonly boolean paused
readonly integer tileset
unit source
unit target
player owner
boolean collideZ
real collision
real damage
real acceleration
integer data
integer type
boolean roll
implement Operators
implement Methods
/* ------------------------------ Reset members ----------------------------- */
private method reset takes nothing returns nothing
set launched = false
set finished = false
set collideZ = false
set paused = false
set roll = false
set source = null
set target = null
set owner = null
set dummy = null
set open = 0.
set height = 0.
set veloc = 0.
set acceleration = 0.
set collision = 0.
set damage = 0.
set travel = 0.
set turn = 0.
set time = 0.
set sight = 0.
set data = 0
set type = 0
set tileset = 0
set pkey = -1
set index = -1
endmethod
/* -------------------------- Destroys the missile -------------------------- */
private method remove takes integer i returns integer
if paused then
implement OnPause
else
implement OnRemove
endif
set missiles[i] = missiles[id]
set id = id - 1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1
endif
if id == -1 then
call PauseTimer(timer)
endif
if not allocated then
call deallocate()
endif
return i - 1
endmethod
/* ---------------------------- Missiles movement --------------------------- */
private static method move takes nothing returns nothing
local integer j = 0
local integer i
local integer k
local unit u
local real a
local real d
local real s
local real h
local real c
local real dx
local real dy
local real vel
local real yaw
local real pitch
local Missiles missile
local Coordinates o
local thistype this
if SWEET_SPOT > 0 then
set i = last
else
set i = 0
endif
loop
exitwhen ((j >= SWEET_SPOT and SWEET_SPOT > 0) or j > id)
set this = missiles[i]
set temp = this
if allocated and not paused then
implement OnHit
implement OnMissile
implement OnDestructable
implement OnItem
implement OnCliff
implement OnTerrain
implement OnTileset
implement OnPeriod
implement OnOrient
implement OnFinish
implement OnBoundaries
else
set i = remove(i)
set j = j - 1
endif
set i = i + 1
set j = j + 1
if i > id and SWEET_SPOT > 0 then
set i = 0
endif
endloop
set last = i
set u = null
endmethod
/* --------------------------- Launch the Missile --------------------------- */
method launch takes nothing returns nothing
if not launched and allocated then
set launched = true
set id = id + 1
set missiles[id] = this
set count = count + 1
set index = count
set collection[count] = this
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1.
endif
if id == 0 then
call TimerStart(timer, PERIOD, true, function thistype.move)
endif
endif
endmethod
/* --------------------------- Main Creator method -------------------------- */
static method create takes real x, real y, real z, real toX, real toY, real toZ returns thistype
local thistype this = thistype.allocate()
call .reset()
set .origin = Coordinates.create(x, y, z)
set .impact = Coordinates.create(toX, toY, toZ)
set .effect = MissileEffect.create(x, y, origin.z)
call Coordinates.link(origin, impact)
set .allocated = true
set .cA = origin.angle
set .x = x
set .y = y
set .z = impact.z
set .prevX = x
set .prevY = y
set .prevZ = impact.z
set .nextX = x
set .nextY = y
set .nextZ = impact.z
set .toZ = toZ
return this
endmethod
endstruct
endlibrary
library Tenacity requires Indexer, Alloc
/* ---------------------------------------- Tenacity v1.0 --------------------------------------- */
// Intro
// This library intension in to introduce to warcraft an easy way to
// manipulate the duration of crowd control on units.
//
// How it Works?
// Working in conjuction with the Crowd Control Library this library allows you to control the
// duration of disables provided in the Crowd Control library. It work similar to the Tenacity
// status in League of Legends or the Status Resistence in Dota 2.
//
// The are basically 3 types of tenacity: Normal (stacks multiplicatively),
// Flat and Offset (stacks additively).The formula for calculation is:
// newDuration = (duration - Offset) * [(1 - value1)*(1 - value2)*...] * (1 - Flat)
//
// The system also allow negative values for Tenacity, resulting in increased
// crowd control duration. Also note that tenacity will only work on CC applied through
// the Crowd Control API
//
// How to Import
// 1. Copy the Indexer and Alloc libraries into your map
// 2. Copy this library into your map and you are done
/* ---------------------------------------- By Chopinski ---------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* JASS API */
/* ---------------------------------------------------------------------------------------------- */
function GetUnitTenacity takes unit u returns real
return Tenacity.get(u, 0)
endfunction
function GetUnitTenacityFlat takes unit u returns real
return Tenacity.get(u, 1)
endfunction
function GetUnitTenacityOffset takes unit u returns real
return Tenacity.get(u, 2)
endfunction
function SetUnitTenacity takes unit u, real value returns nothing
call Tenacity.Set(u, value, 0)
endfunction
function SetUnitTenacityFlat takes unit u, real value returns nothing
call Tenacity.Set(u, value, 1)
endfunction
function SetUnitTenacityOffset takes unit u, real value returns nothing
call Tenacity.Set(u, value, 2)
endfunction
function UnitAddTenacity takes unit u, real value returns nothing
call Tenacity.add(u, value, 0)
endfunction
function UnitAddTenacityFlat takes unit u, real value returns nothing
call Tenacity.add(u, value, 1)
endfunction
function UnitAddTenacityOffset takes unit u, real value returns nothing
call Tenacity.add(u, value, 2)
endfunction
function UnitRemoveTenacity takes unit u, real value returns nothing
call Tenacity.remove(u, value)
endfunction
function GetTenacityDuration takes unit u, real duration returns real
return Tenacity.calculate(u, duration)
endfunction
function RegisterTenacityUnit takes unit u returns Tenacity
return Tenacity.register(u)
endfunction
function DisplayTenacityStatus takes unit u returns nothing
call Tenacity.print(u)
endfunction
/* ---------------------------------------------------------------------------------------------- */
/* System */
/* ---------------------------------------------------------------------------------------------- */
private module ListModule
readonly thistype next
readonly thistype prev
method init takes nothing returns thistype
set next = this
set prev = this
return this
endmethod
method push takes thistype node returns thistype
set node.prev = prev
set node.next = this
set prev.next = node
set prev = node
return node
endmethod
method pop takes nothing returns nothing
set prev.next = next
set next.prev = prev
endmethod
endmodule
private struct List extends array
implement Alloc
implement ListModule
real tenacity
real value
integer size
method destroy takes nothing returns nothing
local thistype node = this.next
loop
exitwhen node == this
set node.value = 0
call node.pop()
call node.deallocate()
set node = node.next
endloop
call deallocate()
endmethod
method insert takes real value returns thistype
local thistype node = push(allocate())
set node.value = value
set size = size + 1
call update()
return node
endmethod
method remove takes real value returns nothing
local thistype node = this.next
loop
exitwhen node == this
if node.value == value then
set size = size - 1
call node.pop()
call node.deallocate()
exitwhen true
endif
set node = node.next
endloop
call update()
endmethod
method update takes nothing returns nothing
local thistype node = this.next
local integer i = 0
if size > 0 then
loop
exitwhen node == this
if i > 0 then
set tenacity = tenacity * (1 - node.value)
else
set tenacity = 1 - node.value
endif
set i = i + 1
set node = node.next
endloop
endif
endmethod
static method create takes nothing returns thistype
local thistype this = thistype(allocate()).init()
set size = 0
set tenacity = 0
return this
endmethod
endstruct
struct Tenacity
private static thistype array struct
private List list
private real flat
private real offset
static method get takes unit source, integer types returns real
local integer id = GetUnitUserData(source)
local thistype this
if struct[id] != 0 then
set this = struct[id]
if types == 0 then
if list.size > 0 then
return 1 - list.tenacity
else
return 0.
endif
elseif types == 1 then
return flat
else
return offset
endif
endif
return 0.
endmethod
static method Set takes unit source, real value, integer types returns nothing
local integer id = GetUnitUserData(source)
local thistype this
if struct[id] == 0 then
set this = register(source)
else
set this = struct[id]
endif
if types == 0 then
set list.tenacity = value
elseif types == 1 then
set flat = value
else
set offset = value
endif
endmethod
static method add takes unit source, real value, integer types returns nothing
local integer id = GetUnitUserData(source)
local thistype this
if value != 0 then
if struct[id] == 0 then
set this = register(source)
else
set this = struct[id]
endif
if types == 0 then
call list.insert(value)
elseif types == 1 then
set flat = flat + value
else
set offset = offset + value
endif
endif
endmethod
static method remove takes unit source, real value returns nothing
local integer id = GetUnitUserData(source)
local thistype this
if value != 0 and struct[id] != 0 then
set this = struct[id]
call list.remove(value)
endif
endmethod
static method calculate takes unit source, real duration returns real
local integer id = GetUnitUserData(source)
local thistype this
if duration != 0 and struct[id] != 0 then
set this = struct[id]
if list.size > 0 then
set duration = (duration - offset) * list.tenacity * (1 - flat)
else
set duration = (duration - offset) * (1 - flat)
endif
if duration <= 0 then
return 0.
endif
return duration
endif
return duration
endmethod
static method register takes unit source returns thistype
local integer id = GetUnitUserData(source)
local thistype this
if struct[id] == 0 then
set this = thistype.allocate()
set list = List.create()
set flat = 0
set offset = 0
set struct[GetUnitUserData(source)] = this
endif
return this
endmethod
static method print takes unit source returns nothing
local integer id = GetUnitUserData(source)
local thistype this
local List node
local integer i = 0
local real array bonus
if struct[id] != 0 then
set this = struct[id]
if list.size > 0 then
set node = list.next
loop
exitwhen node == list
set bonus[i] = node.value
set i = i + 1
set node = node.next
endloop
endif
call ClearTextMessages()
call BJDebugMsg("Tenacity Status for " + GetUnitName(source))
call BJDebugMsg("Tenacity List [" + R2S(bonus[0]) + " | " + R2S(bonus[1]) + " | " + R2S(bonus[2]) + " | " + R2S(bonus[3]) + " | " + R2S(bonus[4]) + " | " + R2S(bonus[5]) + " | ...] = " + R2S(get(source, 0)))
call BJDebugMsg("Tenacity Flat [" + R2S(get(source, 1)) + "]")
call BJDebugMsg("Tenacity Offset [" + R2S(get(source, 2)) + "]")
endif
endmethod
private static method onDeindex takes nothing returns nothing
local unit source = GetIndexUnit()
local integer id = GetUnitUserData(source)
local thistype this
if struct[id] != 0 then
set this = struct[id]
call list.destroy()
call deallocate()
set struct[id] = 0
endif
endmethod
private static method onInit takes nothing returns nothing
call RegisterUnitDeindexEvent(function thistype.onDeindex)
endmethod
endstruct
endlibrary
library TenacityUtils requires Tenacity
/* ------------------------------------- Tenacity Utils v1.0 ------------------------------------ */
// Utility Library that include a few extra functions to deal with Tenacity
/* ---------------------------------------- By Chopinski ---------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* JASS API */
/* ---------------------------------------------------------------------------------------------- */
function UnitAddTenacityTimed takes unit u, real value, real duration returns nothing
call TenacityUtils.addTimed(u, value, duration, 0)
endfunction
function UnitAddTenacityFlatTimed takes unit u, real value, real duration returns nothing
call TenacityUtils.addTimed(u, value, duration, 1)
endfunction
function UnitAddTenacityOffsetTimed takes unit u, real value, real duration returns nothing
call TenacityUtils.addTimed(u, value, duration, 2)
endfunction
/* ---------------------------------------------------------------------------------------------- */
/* System */
/* ---------------------------------------------------------------------------------------------- */
struct TenacityUtils extends Tenacity
private static timer timer = CreateTimer()
private static thistype array array
private static integer key = -1
private static real period = 0.03125000
private unit unit
private real value
private integer type
private real duration
private method destroy takes nothing returns nothing
if key == -1 then
call PauseTimer(timer)
endif
set unit = null
call deallocate()
endmethod
private static method onPeriod takes nothing returns nothing
local thistype this
local integer i = 0
loop
exitwhen i > key
set this = array[i]
if duration <= 0 then
if type == 0 then
call remove(unit, value)
else
call add(unit, -value, type)
endif
set array[i] = array[key]
set key = key - 1
set i = i - 1
call destroy()
endif
set duration = duration - period
set i = i + 1
endloop
endmethod
static method addTimed takes unit u, real amount, real duration, integer types returns nothing
local thistype this = thistype.allocate()
set unit = u
set value = amount
set type = types
set .duration = duration
set key = key + 1
set array[key] = this
call add(unit, value, type)
if key == 0 then
call TimerStart(timer, period, true, function thistype.onPeriod)
endif
endmethod
endstruct
endlibrary
library GetMainSelectedUnit initializer init_function
globals
private framehandle containerFrame
private framehandle array frames
private group Group = CreateGroup()
private unit array units
private integer unitsCount = 0
private filterfunc filter
endglobals
function GetUnitOrderValue takes unit u returns integer
//heroes use the handleId
if IsUnitType(u, UNIT_TYPE_HERO) then
return GetHandleId(u)
else
//units use unitCode
return GetUnitTypeId(u)
endif
endfunction
private function FilterFunction takes nothing returns boolean
local unit u = GetFilterUnit()
local real prio = BlzGetUnitRealField(u, UNIT_RF_PRIORITY)
local boolean found = false
local integer loopA = 1
local integer loopB = 0
// compare the current u with allready found, to place it in the right slot
loop
exitwhen loopA > unitsCount
if BlzGetUnitRealField(units[loopA], UNIT_RF_PRIORITY) < prio then
set unitsCount = unitsCount + 1
set loopB = unitsCount
loop
exitwhen loopB <= loopA
set units[loopB] = units[loopB - 1]
set loopB = loopB - 1
endloop
set units[loopA] = u
set found = true
exitwhen true
// equal prio and better colisions Value
elseif BlzGetUnitRealField(units[loopA], UNIT_RF_PRIORITY) == prio and GetUnitOrderValue(units[loopA]) > GetUnitOrderValue(u) then
set unitsCount = unitsCount + 1
set loopB = unitsCount
loop
exitwhen loopB <= loopA
set units[loopB] = units[loopB - 1]
set loopB = loopB - 1
endloop
set units[loopA] = u
set found = true
exitwhen true
endif
set loopA = loopA + 1
endloop
// not found add it at the end
if not found then
set unitsCount = unitsCount + 1
set units[unitsCount] = u
endif
set u = null
return false
endfunction
function GetSelectedUnitIndex takes nothing returns integer
local integer i = 0
// local player is in group selection?
if BlzFrameIsVisible(containerFrame) then
// find the first visible yellow Background Frame
loop
exitwhen i > 11
if BlzFrameIsVisible(frames[i]) then
return i
endif
set i = i + 1
endloop
endif
return -1
endfunction
function GetMainSelectedUnit takes integer index returns unit
if index >= 0 then
call GroupEnumUnitsSelected(Group, GetLocalPlayer(), filter)
set bj_groupRandomCurrentPick = units[index + 1]
//clear table
loop
exitwhen unitsCount <= 0
set units[unitsCount] = null
set unitsCount = unitsCount - 1
endloop
return bj_groupRandomCurrentPick
else
call GroupEnumUnitsSelected(Group, GetLocalPlayer(), null)
return FirstOfGroup(Group)
endif
endfunction
// returns the local current main selected unit, using it in a sync gamestate relevant manner breaks the game.
function GetMainSelectedUnitEx takes nothing returns unit
return GetMainSelectedUnit(GetSelectedUnitIndex())
endfunction
private function init_functionAt0s takes nothing returns nothing
local integer i = 0
local framehandle console = BlzGetFrameByName("ConsoleUI", 0)
local framehandle bottomUI = BlzFrameGetChild(console, 1)
local framehandle groupframe = BlzFrameGetChild(bottomUI, 5)
local framehandle buttonContainer
//globals
set containerFrame = BlzFrameGetChild(groupframe, 0)
set Group = CreateGroup()
// give this frames a handleId
loop
exitwhen i >= BlzFrameGetChildrenCount(containerFrame) - 1
set buttonContainer = BlzFrameGetChild(containerFrame, i)
set frames[i] = BlzFrameGetChild(buttonContainer, 0)
set i = i + 1
endloop
call DestroyTimer(GetExpiredTimer())
endfunction
private function init_function takes nothing returns nothing
set filter = Filter(function FilterFunction)
call TimerStart(CreateTimer(), 0, false, function init_functionAt0s)
endfunction
endlibrary
library Interface requires RegisterPlayerUnitEvent, GetMainSelectedUnit
/* --------------------------------------- Interface v1.4 --------------------------------------- */
// Credits
// - Tasyen - GetMainSelectedUnit
// - Magtheridon96 - RegisterPlayerUnitEvent
/* ---------------------------------------- By Chopinski ---------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* Configuration */
/* ---------------------------------------------------------------------------------------------- */
globals
// Set this to a texture to replace the default gold icon
private constant string GOLD_ICON = ""
// Set this to a texture to replace the default lumber icon
private constant string LUMBER_ICON = ""
// When true and a unit that has "Select Unit" or "Select Hero" or "Shop Purchase Item"
// abilities is select a panel above the portrait is created to show the items/units
private constant boolean DISPLAY_SHOP = true
endglobals
/* ---------------------------------------------------------------------------------------------- */
/* System */
/* ---------------------------------------------------------------------------------------------- */
private struct UI
private static trigger maptrigger = CreateTrigger()
private static trigger herotrigger = CreateTrigger()
private static trigger menutrigger = CreateTrigger()
private static trigger trigger = CreateTrigger()
private static timer timer = CreateTimer()
private static integer key = -1
private static thistype array array
private static thistype array struct
private static framehandle handle = null
private static framehandle UI = null
private static framehandle ShopSlots = null
private static framehandle HealthBar = null
private static framehandle ManaBar = null
private static framehandle HeroCheck = null
private static framehandle HPText = null
private static framehandle MPText = null
private static framehandle Gold = null
private static framehandle Lumber = null
private static framehandle CheckBL = null
private static framehandle CheckBR = null
private static framehandle Minimap = null
private static framehandle MenuCheck = null
private static framehandle LumberIcon = null
private static framehandle GoldIcon = null
private static real array x1
private static real array x2
private static real array y01
private static real array y02
private static real array y11
private static real array y12
private static real array y21
private static real array y22
private static real array y31
private static real array y32
private static real array y41
private static real array y42
private static real array y51
private static real array y52
private static real array y61
private static real array y62
private static real array mapX1
private static real array mapY1
private static real array mapX2
private static real array mapY2
private static real array frameX1
private static real array frameY1
private static real array frameX2
private static real array frameY2
private static real array command0X1
private static real array command0Y1
private static real array command0X2
private static real array command0Y2
private static real array command1X1
private static real array command1Y1
private static real array command1X2
private static real array command1Y2
private static real array command2X1
private static real array command2Y1
private static real array command2X2
private static real array command2Y2
private static real array command3X1
private static real array command3Y1
private static real array command3X2
private static real array command3Y2
private static real array command4X1
private static real array command4Y1
private static real array command4X2
private static real array command4Y2
private static real array command5X1
private static real array command5Y1
private static real array command5X2
private static real array command5Y2
private static real array command6X1
private static real array command6Y1
private static real array command6X2
private static real array command6Y2
private static real array command7X1
private static real array command7Y1
private static real array command7X2
private static real array command7Y2
private static real array command8X1
private static real array command8Y1
private static real array command8X2
private static real array command8Y2
private static real array command9X1
private static real array command9Y1
private static real array command9X2
private static real array command9Y2
private static real array command10X1
private static real array command10Y1
private static real array command10X2
private static real array command10Y2
private static real array command11X1
private static real array command11Y1
private static real array command11X2
private static real array command11Y2
private static boolean array shop
private static unit array main
private static boolean array checkL
private static boolean array checkR
private static boolean array checkMenu
unit unit
player player
integer id
real health
real mana
string hp
string mp
method remove takes integer i returns integer
set array[i] = array[key]
set key = key - 1
set struct[id] = 0
set unit = null
set player = null
if key == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
private static method onCommandButtons takes nothing returns nothing
local integer id = GetPlayerId(GetLocalPlayer())
if shop[id] then
set command0X1[id] = 0.333500
set command0Y1[id] = 0.213950
set command0X2[id] = 0.366760
set command0Y2[id] = 0.180700
set command1X1[id] = 0.370500
set command1Y1[id] = 0.213950
set command1X2[id] = 0.403760
set command1Y2[id] = 0.180700
set command2X1[id] = 0.407400
set command2Y1[id] = 0.213650
set command2X2[id] = 0.440660
set command2Y2[id] = 0.180400
set command3X1[id] = 0.444400
set command3Y1[id] = 0.213650
set command3X2[id] = 0.477660
set command3Y2[id] = 0.180400
set command4X1[id] = 0.333500
set command4Y1[id] = 0.175250
set command4X2[id] = 0.366760
set command4Y2[id] = 0.142000
set command5X1[id] = 0.370500
set command5Y1[id] = 0.175250
set command5X2[id] = 0.403760
set command5Y2[id] = 0.142000
set command6X1[id] = 0.407400
set command6Y1[id] = 0.175250
set command6X2[id] = 0.440660
set command6Y2[id] = 0.142000
set command7X1[id] = 0.444400
set command7Y1[id] = 0.175250
set command7X2[id] = 0.477660
set command7Y2[id] = 0.142000
set command8X1[id] = 0.333500
set command8Y1[id] = 0.136850
set command8X2[id] = 0.366760
set command8Y2[id] = 0.103600
set command9X1[id] = 0.370500
set command9Y1[id] = 0.136850
set command9X2[id] = 0.403760
set command9Y2[id] = 0.103600
set command10X1[id] = 0.407400
set command10Y1[id] = 0.136850
set command10X2[id] = 0.440660
set command10Y2[id] = 0.103600
set command11X1[id] = 0.444400
set command11Y1[id] = 0.136850
set command11X2[id] = 0.477660
set command11Y2[id] = 0.103600
else
set command0X1[id] = 999.0
set command0Y1[id] = 999.0
set command0X2[id] = 999.0
set command0Y2[id] = 999.0
set command1X1[id] = 999.0
set command1Y1[id] = 999.0
set command1X2[id] = 999.0
set command1Y2[id] = 999.0
set command2X1[id] = 999.0
set command2Y1[id] = 999.0
set command2X2[id] = 999.0
set command2Y2[id] = 999.0
set command3X1[id] = 999.0
set command3Y1[id] = 999.0
set command3X2[id] = 999.0
set command3Y2[id] = 999.0
set command4X1[id] = 999.0
set command4Y1[id] = 999.0
set command4X2[id] = 999.0
set command4Y2[id] = 999.0
set command5X1[id] = 0.186900
set command5Y1[id] = 0.0467700
set command5X2[id] = 0.216900
set command5Y2[id] = 0.0150000
set command6X1[id] = 0.223700
set command6Y1[id] = 0.0467700
set command6X2[id] = 0.254200
set command6Y2[id] = 0.0150000
set command7X1[id] = 0.00242900
set command7Y1[id] = 0.0467700
set command7X2[id] = 0.0342090
set command7Y2[id] = 0.0150000
set command8X1[id] = 0.0399070
set command8Y1[id] = 0.0467700
set command8X2[id] = 0.0716870
set command8Y2[id] = 0.0150000
set command9X1[id] = 0.0765555
set command9Y1[id] = 0.0467700
set command9X2[id] = 0.1095555
set command9Y2[id] = 0.0150000
set command10X1[id] = 0.113070
set command10Y1[id] = 0.0467700
set command10X2[id] = 0.144850
set command10Y2[id] = 0.0150000
set command11X1[id] = 0.150070
set command11Y1[id] = 0.0467700
set command11X2[id] = 0.181850
set command11Y2[id] = 0.0150000
endif
// Display the 12 slot grid
call BlzFrameSetVisible(ShopSlots, shop[id])
// Reposition the Move command button
set handle = BlzGetFrameByName("CommandButton_0", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command0X1[id], command0Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command0X2[id], command0Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the Stop command button
set handle = BlzGetFrameByName("CommandButton_1", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command1X1[id], command1Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command1X2[id], command1Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the Hold command button
set handle = BlzGetFrameByName("CommandButton_2", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command2X1[id], command2Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command2X2[id], command2Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the Attack command button
set handle = BlzGetFrameByName("CommandButton_3", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command3X1[id], command3Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command3X2[id], command3Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the Patrol command button
set handle = BlzGetFrameByName("CommandButton_4", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command4X1[id], command4Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command4X2[id], command4Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the D command button
set handle = BlzGetFrameByName("CommandButton_5", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command5X1[id], command5Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command5X2[id], command5Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the F command button
set handle = BlzGetFrameByName("CommandButton_6", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command6X1[id], command6Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command6X2[id], command6Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the + command button
set handle = BlzGetFrameByName("CommandButton_7", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command7X1[id], command7Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command7X2[id], command7Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the Q command button
set handle = BlzGetFrameByName("CommandButton_8", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command8X1[id], command8Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command8X2[id], command8Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the W command button
set handle = BlzGetFrameByName("CommandButton_9", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command9X1[id], command9Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command9X2[id], command9Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the E command button
set handle = BlzGetFrameByName("CommandButton_10", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command10X1[id], command10Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command10X2[id], command10Y2[id])
call BlzFrameSetScale(handle, 0.82)
// Reposition the R command button
set handle = BlzGetFrameByName("CommandButton_11", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, command11X1[id], command11Y1[id])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, command11X2[id], command11Y2[id])
call BlzFrameSetScale(handle, 0.82)
set handle = null
endmethod
private static method onInventoryButtons takes nothing returns nothing
// Reposition the 0 inventory button
set handle = BlzGetFrameByName("InventoryButton_0", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.552700, 0.0467700)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.584480, 0.0150000)
call BlzFrameSetSize(handle, 0.03178, 0.03178)
// Reposition the 1 inventory button
set handle = BlzGetFrameByName("InventoryButton_1", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.589100, 0.0467700)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.621900, 0.0150000)
call BlzFrameSetSize(handle, 0.03178, 0.03178)
// Reposition the 2 inventory button
set handle = BlzGetFrameByName("InventoryButton_2", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.625750, 0.0467700)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.657530, 0.0150000)
call BlzFrameSetSize(handle, 0.03178, 0.03178)
// Reposition the 3 inventory button
set handle = BlzGetFrameByName("InventoryButton_3", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.662999, 0.0467700)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.694999, 0.0150000)
call BlzFrameSetSize(handle, 0.03178, 0.03178)
// Reposition the 4 inventory button
set handle = BlzGetFrameByName("InventoryButton_4", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.699700, 0.0467700)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.731480, 0.0150000)
call BlzFrameSetSize(handle, 0.03178, 0.03178)
// Reposition the 5 inventory button
set handle = BlzGetFrameByName("InventoryButton_5", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.736555, 0.0467700)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.768555, 0.0150000)
call BlzFrameSetSize(handle, 0.03178, 0.03178)
set handle = null
endmethod
private static method onInfoPanel takes nothing returns nothing
// Reposition the Buff bar
set handle = BlzGetOriginFrame(ORIGIN_FRAME_UNIT_PANEL_BUFF_BAR, 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.364600, 0.0280800)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.476200, 0.0147800)
call BlzFrameSetScale(handle, 0.9)
//Remove the Status text
call BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_UNIT_PANEL_BUFF_BAR_LABEL, 0), 0.00001)
// Remove Names and Descriptions
call BlzFrameSetScale(BlzGetFrameByName("SimpleNameValue", 0), 0.00001)
call BlzFrameSetScale(BlzGetFrameByName("SimpleClassValue", 0), 0.00001)
call BlzFrameSetScale(BlzGetFrameByName("SimpleBuildingNameValue", 1), 0.00001)
call BlzFrameSetScale(BlzGetFrameByName("SimpleBuildingActionLabel", 1), 0.00001)
call BlzFrameSetScale(BlzGetFrameByName("SimpleHoldNameValue", 2), 0.00001)
call BlzFrameSetScale(BlzGetFrameByName("SimpleHoldDescriptionNameValue", 2), 0.00001)
call BlzFrameSetScale(BlzGetFrameByName("SimpleItemNameValue", 3), 0.00001)
call BlzFrameSetScale(BlzGetFrameByName("SimpleItemDescriptionValue", 3), 0.00001)
call BlzFrameSetScale(BlzGetFrameByName("SimpleDestructableNameValue", 4), 0.00001)
// Reposition the Hero Main Stat
set handle = BlzGetFrameByName("InfoPanelIconHeroIcon", 6)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.449800, 0.0581100)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.474930, 0.0329900)
// Reposition the Strength label and value
set handle = BlzGetFrameByName("InfoPanelIconHeroStrengthLabel", 6)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.476900, 0.0757800)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.530850, 0.0624800)
set handle = BlzGetFrameByName("InfoPanelIconHeroStrengthValue", 6)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.480000, 0.0657200)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.550000, 0.0553800)
// Reposition the Agility label and value
set handle = BlzGetFrameByName("InfoPanelIconHeroAgilityLabel", 6)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.477400, 0.0559200)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.532090, 0.0426200)
set handle = BlzGetFrameByName("InfoPanelIconHeroAgilityValue", 6)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.480300, 0.0445700)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.550000, 0.0342300)
// Reposition the Intelligence label and value
set handle = BlzGetFrameByName("InfoPanelIconHeroIntellectLabel", 6)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.476900, 0.0346500)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.531590, 0.0213500)
set handle = BlzGetFrameByName("InfoPanelIconHeroIntellectValue", 6)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.480600, 0.0240700)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.550000, 0.0137300)
// Reposition the Timed Life bar
set handle = BlzGetFrameByName("SimpleProgressIndicator", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.00000, 0.0100000)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.770000, 0.00000)
call BlzFrameSetSize(handle, 0.77000, 0.01000)
// Reposition the XP bar
set handle = BlzGetFrameByName("SimpleHeroLevelBar", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.00000, 0.0100000)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.770000, 0.00000)
call BlzFrameSetSize(handle, 0.77000, 0.01000)
// Reposition the Training bar
set handle = BlzGetFrameByName("SimpleBuildTimeIndicator", 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.00000, 0.0100000)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.770000, 0.00000)
call BlzFrameSetSize(handle, 0.77000, 0.01000)
// Reposition the Attack 1 block
set handle = BlzGetFrameByName("InfoPanelIconBackdrop", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.261800, 0.0723200)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.289140, 0.0449800)
call BlzFrameSetSize(handle, 0.02734, 0.02734)
// Reposition the Armor block
set handle = BlzGetFrameByName("InfoPanelIconBackdrop", 2)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.261100, 0.0439700)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.288440, 0.0166300)
call BlzFrameSetSize(handle, 0.02734, 0.02734)
set handle = null
endmethod
private static method onPortrait takes nothing returns nothing
set handle = BlzGetOriginFrame(ORIGIN_FRAME_PORTRAIT, 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.373500, 0.0977600)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.431555, 0.0157400)
set handle = null
endmethod
private static method onHeroCheck takes nothing returns nothing
local integer i = GetPlayerId(GetLocalPlayer())
if BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_CHECKED then
if GetLocalPlayer() == GetTriggerPlayer() then
set x1[i] = -0.131300
set x2[i] = -0.103220
set y01[i] = 0.581980
set y02[i] = 0.553900
set y11[i] = 0.544980
set y12[i] = 0.516900
set y21[i] = 0.510680
set y22[i] = 0.482600
set y31[i] = 0.474280
set y32[i] = 0.446200
set y41[i] = 0.437880
set y42[i] = 0.409800
set y51[i] = 0.401480
set y52[i] = 0.373400
set y61[i] = 0.365080
set y62[i] = 0.337000
endif
// Reposition the hero button 0
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y01[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y02[i])
call BlzFrameSetScale(handle, 0.7)
call BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 0), 0.71)
// Reposition the hero button 1
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y11[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y12[i])
call BlzFrameSetScale(handle, 0.7)
call BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 1), 0.71)
// Reposition the hero button 2
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 2)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y21[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y22[i])
call BlzFrameSetScale(handle, 0.7)
call BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 2), 0.71)
// Reposition the hero button 3
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 3)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y31[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y32[i])
call BlzFrameSetScale(handle, 0.7)
call BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 3), 0.71)
// Reposition the hero button 4
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 4)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y41[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y42[i])
call BlzFrameSetScale(handle, 0.7)
call BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 4), 0.71)
// Reposition the hero button 5
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 5)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y51[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y52[i])
call BlzFrameSetScale(handle, 0.7)
call BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 5), 0.71)
// Reposition the hero button 6
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 6)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y61[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y62[i])
call BlzFrameSetScale(handle, 0.7)
call BlzFrameSetScale(BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, 6), 0.71)
set handle = null
else
if GetLocalPlayer() == GetTriggerPlayer() then
set x1[i] = 999.0
set x2[i] = 999.0
set y01[i] = 999.0
set y02[i] = 999.0
set y11[i] = 999.0
set y12[i] = 999.0
set y21[i] = 999.0
set y22[i] = 999.0
set y31[i] = 999.0
set y32[i] = 999.0
set y41[i] = 999.0
set y42[i] = 999.0
set y51[i] = 999.0
set y52[i] = 999.0
set y61[i] = 999.0
set y62[i] = 999.0
endif
// Hides the hero button 0
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y01[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y02[i])
// Hides the hero button 1
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y11[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y12[i])
// Hides the hero button 2
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 2)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y21[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y22[i])
// Hides the hero button 3
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 3)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y31[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y32[i])
// Hides the hero button 4
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 4)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y41[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y42[i])
// Hides the hero button 5
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 5)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y51[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y52[i])
// Hides the hero button 6
set handle = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 6)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, x1[i], y61[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, x2[i], y62[i])
set handle = null
endif
endmethod
private static method onGroupSelection takes nothing returns nothing
// Reposistion the Group selection button 0
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 0), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.262600, 0.0776200)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.285600, 0.0546200)
// Reposistion the Group selection button 1
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 1), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.295800, 0.0731200)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.318800, 0.0501200)
// Reposistion the Group selection button 2
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 2), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.328300, 0.0731200)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.351300, 0.0501200)
// Reposistion the Group selection button 3
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 3), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.262600, 0.0414100)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.285600, 0.0184100)
// Reposistion the Group selection button 4
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 4), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.295800, 0.0414000)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.318800, 0.0184000)
// Reposistion the Group selection button 5
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 5), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.329100, 0.0414000)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.352100, 0.0184000)
// Reposistion the Group selection button 6
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 6), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.449300, 0.0731200)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.472300, 0.0501200)
// Reposistion the Group selection button 7
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 7), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.483500, 0.0731200)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.506500, 0.0501200)
// Reposistion the Group selection button 8
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 8), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.516800, 0.0731200)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.539800, 0.0501200)
// Reposistion the Group selection button 9
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 9), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.450300, 0.0414000)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.473300, 0.0184000)
// Reposistion the Group selection button 10
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 10), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.483500, 0.0414000)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.506500, 0.0184000)
// Reposistion the Group selection button 11
set handle = BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetParent(BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)), 5), 0), 11), 1)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.516800, 0.0414000)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.539800, 0.0184000)
set handle = null
endmethod
private static method onResources takes nothing returns nothing
call BlzFrameSetText(Gold, "|cffffcc00" + I2S(GetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_GOLD)) + "|r")
call BlzFrameSetText(Lumber, "|cff00ff00" + I2S(GetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_LUMBER)) + "|r")
endmethod
private static method onChat takes nothing returns nothing
set handle = BlzGetOriginFrame(ORIGIN_FRAME_CHAT_MSG, 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.000212200, 0.302800)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.400212, 0.100300)
set handle = BlzGetOriginFrame(ORIGIN_FRAME_UNIT_MSG, 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, 0.000212200, 0.302800)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, 0.400212, 0.100300)
set handle = null
endmethod
private static method onMinimap takes nothing returns nothing
local integer i = GetPlayerId(GetLocalPlayer())
if BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_CHECKED then
if BlzGetTriggerFrame() == CheckBL then
if GetLocalPlayer() == GetTriggerPlayer() then
set mapX1[i] = - 0.132100
set mapY1[i] = 0.0986970
set mapX2[i] = - 0.0351000
set mapY2[i] = 0.00169700
set frameX1[i] = - 0.133600
set frameY1[i] = 0.100939
set frameX2[i] = - 0.0338300
set frameY2[i] = 0.000438700
set checkL[i] = true
endif
else
if GetLocalPlayer() == GetTriggerPlayer() then
set mapX1[i] = 0.835800
set mapY1[i] = 0.0999999
set mapX2[i] = 0.933610
set mapY2[i] = 0.000219400
set frameX1[i] = 0.833900
set frameY1[i] = 0.100939
set frameX2[i] = 0.933670
set frameY2[i] = 0.000438700
set checkR[i] = true
endif
endif
else
if BlzGetTriggerFrame() == CheckBL then
if GetLocalPlayer() == GetTriggerPlayer() then
if checkR[i] then
set mapX1[i] = 0.835800
set mapY1[i] = 0.0999999
set mapX2[i] = 0.933610
set mapY2[i] = 0.000219400
set frameX1[i] = 0.833900
set frameY1[i] = 0.100939
set frameX2[i] = 0.933670
set frameY2[i] = 0.000438700
else
set mapX1[i] = 999.0
set mapY1[i] = 999.0
set mapX2[i] = 999.0
set mapY2[i] = 999.0
set frameX1[i] = 999.0
set frameY1[i] = 999.0
set frameX2[i] = 999.0
set frameY2[i] = 999.0
endif
set checkL[i] = false
endif
else
if GetLocalPlayer() == GetTriggerPlayer() then
if checkL[i] then
set mapX1[i] = - 0.132100
set mapY1[i] = 0.0986970
set mapX2[i] = - 0.0351000
set mapY2[i] = 0.00169700
set frameX1[i] = - 0.133600
set frameY1[i] = 0.100939
set frameX2[i] = - 0.0338300
set frameY2[i] = 0.000438700
else
set mapX1[i] = 999.0
set mapY1[i] = 999.0
set mapX2[i] = 999.0
set mapY2[i] = 999.0
set frameX1[i] = 999.0
set frameY1[i] = 999.0
set frameX2[i] = 999.0
set frameY2[i] = 999.0
endif
set checkR[i] = false
endif
endif
endif
set handle = BlzGetFrameByName("MiniMapFrame", 0)
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_TOPLEFT, mapX1[i], mapY1[i])
call BlzFrameSetAbsPoint(handle, FRAMEPOINT_BOTTOMRIGHT, mapX2[i], mapY2[i])
call BlzFrameSetAbsPoint(Minimap, FRAMEPOINT_TOPLEFT, frameX1[i], frameY1[i])
call BlzFrameSetAbsPoint(Minimap, FRAMEPOINT_BOTTOMRIGHT, frameX2[i], frameY2[i])
set handle = null
endmethod
private static method onMenu takes nothing returns nothing
local integer i = GetPlayerId(GetLocalPlayer())
if BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_CHECKED then
if GetLocalPlayer() == GetTriggerPlayer() then
set checkMenu[i] = true
endif
else
if GetLocalPlayer() == GetTriggerPlayer() then
set checkMenu[i] = false
endif
endif
call BlzFrameSetVisible(BlzGetFrameByName("UpperButtonBarFrame", 0), checkMenu[i])
call BlzFrameSetVisible(BlzGetFrameByName("ResourceBarFrame", 0), checkMenu[i])
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local real newHP
local real newMP
local string newHptext
local string newMptext
local thistype this
loop
exitwhen i > key
set this = array[i]
if GetPlayerSlotState(player) != PLAYER_SLOT_STATE_LEFT then
set unit = GetMainSelectedUnitEx()
static if DISPLAY_SHOP then
if main[id] != unit then
set main[id] = unit
set shop[id] = (GetUnitAbilityLevel(unit, 'Aneu') > 0 or GetUnitAbilityLevel(unit, 'Ane2') > 0 or GetUnitAbilityLevel(unit, 'Apit') > 0) and not IsUnitEnemy(unit, player)
call onCommandButtons()
endif
endif
if not IsUnitVisible(unit, player) then
set unit = null
endif
set health = BlzFrameGetValue(HealthBar)
set mana = BlzFrameGetValue(ManaBar)
set newHP = GetUnitLifePercent(unit)
set newMP = GetUnitManaPercent(unit)
set hp = BlzFrameGetText(HPText)
set mp = BlzFrameGetText(MPText)
set newHptext = I2S(R2I(GetWidgetLife(unit))) + " / " + I2S(BlzGetUnitMaxHP(unit))
set newMptext = I2S(R2I(GetUnitState(unit, UNIT_STATE_MANA))) + " / " + I2S(BlzGetUnitMaxMana(unit))
if GetLocalPlayer() == player then
set health = newHP
set mana = newMP
set hp = newHptext
set mp = newMptext
endif
call BlzFrameSetValue(HealthBar, health)
call BlzFrameSetValue(ManaBar, mana)
call BlzFrameSetText(HPText, "|cffFFFFFF" + hp + "|r")
call BlzFrameSetText(MPText, "|cffFFFFFF" + mp + "|r")
else
set i = remove(i)
endif
set i = i + 1
endloop
endmethod
private static method onSelect takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local thistype this
if struct[id] != 0 then
set this = struct[id]
else
set this = thistype.allocate()
set .id = id
set player = GetTriggerPlayer()
set health = 0
set mana = 0
set hp = "0 / 0"
set mp = "0 / 0"
set key = key + 1
set array[key] = this
set struct[id] = this
if key == 0 then
call TimerStart(timer, 0.05, true, function thistype.onPeriod)
endif
endif
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
call BlzFrameSetAlpha(BlzGetFrameByName("SimpleInventoryCover", 0), 0)
call BlzFrameSetScale(BlzGetFrameByName("InventoryText", 0), 0.0001)
call BlzFrameSetAbsPoint(BlzGetFrameByName("ConsoleUI", 0), FRAMEPOINT_TOPLEFT, 0.0, 0.633)
call BlzFrameSetVisible(BlzGetFrameByName("ResourceBarFrame", 0), false)
call BlzFrameSetVisible(BlzGetFrameByName("UpperButtonBarFrame", 0), false)
call BlzFrameSetVisible(BlzFrameGetChild(BlzGetFrameByName("ConsoleUI", 0), 7), false)
call BlzFrameSetVisible(BlzFrameGetChild(BlzFrameGetChild(BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 5),0), false)
call BlzFrameSetParent(BlzGetFrameByName("MiniMapFrame", 0), BlzGetFrameByName("ConsoleUIBackdrop", 0))
set UI = BlzCreateFrameByType("BACKDROP", "UI", BlzGetFrameByName("ConsoleUIBackdrop", 0), "", 1)
call BlzFrameSetAbsPoint(UI, FRAMEPOINT_TOPLEFT, 0.00000, 0.100000)
call BlzFrameSetAbsPoint(UI, FRAMEPOINT_BOTTOMRIGHT, 0.770000, 0.00000)
call BlzFrameSetTexture(UI, "UI.blp", 0, true)
set ShopSlots = BlzCreateFrameByType("BACKDROP", "ShopSlots", BlzGetFrameByName("ConsoleUIBackdrop", 0), "", 1)
call BlzFrameSetAbsPoint(ShopSlots, FRAMEPOINT_TOPLEFT, 0.330600, 0.216500)
call BlzFrameSetAbsPoint(ShopSlots, FRAMEPOINT_BOTTOMRIGHT, 0.478600, 0.100700)
call BlzFrameSetTexture(ShopSlots, "12Slot.blp", 0, true)
set HealthBar = BlzCreateFrameByType("SIMPLESTATUSBAR", "", UI, "", 0)
call BlzFrameSetTexture(HealthBar, "replaceabletextures\\teamcolor\\teamcolor00", 0, true)
call BlzFrameSetAbsPoint(HealthBar, FRAMEPOINT_TOPLEFT, 0.0386400, 0.0778900)
call BlzFrameSetAbsPoint(HealthBar, FRAMEPOINT_BOTTOMRIGHT, 0.255140, 0.0535100)
call BlzFrameSetValue(HealthBar, 0)
set ManaBar = BlzCreateFrameByType("SIMPLESTATUSBAR", "", UI, "", 0)
call BlzFrameSetTexture(ManaBar, "replaceabletextures\\teamcolor\\teamcolor01", 0, true)
call BlzFrameSetAbsPoint(ManaBar, FRAMEPOINT_TOPLEFT, 0.551500, 0.0778000)
call BlzFrameSetAbsPoint(ManaBar, FRAMEPOINT_BOTTOMRIGHT, 0.768000, 0.0534200)
call BlzFrameSetValue(ManaBar, 0)
set HeroCheck = BlzCreateFrame("QuestCheckBox", UI, 0, 0)
call BlzFrameSetAbsPoint(HeroCheck, FRAMEPOINT_TOPLEFT, -0.131300, 0.600240)
call BlzFrameSetAbsPoint(HeroCheck, FRAMEPOINT_BOTTOMRIGHT, -0.117260, 0.586200)
set HPText = BlzCreateFrameByType("TEXT", "HPTEXT", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
call BlzFrameSetAbsPoint(HPText, FRAMEPOINT_TOPLEFT, 0.108100, 0.0726300)
call BlzFrameSetAbsPoint(HPText, FRAMEPOINT_BOTTOMRIGHT, 0.184960, 0.0585900)
call BlzFrameSetText(HPText, "|cffFFFFFF|r")
call BlzFrameSetEnable(HPText, false)
call BlzFrameSetScale(HPText, 1.00)
call BlzFrameSetTextAlignment(HPText, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_MIDDLE)
set MPText = BlzCreateFrameByType("TEXT", "MPTEXT", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
call BlzFrameSetAbsPoint(MPText, FRAMEPOINT_TOPLEFT, 0.622500, 0.0726000)
call BlzFrameSetAbsPoint(MPText, FRAMEPOINT_BOTTOMRIGHT, 0.699360, 0.0585600)
call BlzFrameSetText(MPText, "|cffFFFFFF|r")
call BlzFrameSetEnable(MPText, false)
call BlzFrameSetScale(MPText, 1.00)
call BlzFrameSetTextAlignment(MPText, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_MIDDLE)
set Lumber = BlzCreateFrameByType("TEXT", "GOLD", UI, "", 0)
call BlzFrameSetAbsPoint(Lumber, FRAMEPOINT_TOPLEFT, 0.291100, 0.0970200)
call BlzFrameSetAbsPoint(Lumber, FRAMEPOINT_BOTTOMRIGHT, 0.346530, 0.0815000)
call BlzFrameSetText(Lumber, "|cff00ff00|r")
call BlzFrameSetEnable(Lumber, false)
call BlzFrameSetScale(Lumber, 1.00)
call BlzFrameSetTextAlignment(Lumber, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_RIGHT)
set Gold = BlzCreateFrameByType("TEXT", "LUMBER", UI, "", 0)
call BlzFrameSetAbsPoint(Gold, FRAMEPOINT_TOPLEFT, 0.460600, 0.0972500)
call BlzFrameSetAbsPoint(Gold, FRAMEPOINT_BOTTOMRIGHT, 0.516030, 0.0817300)
call BlzFrameSetText(Gold, "|cffffcc00|r")
call BlzFrameSetEnable(Gold, false)
call BlzFrameSetScale(Gold, 1.00)
call BlzFrameSetTextAlignment(Gold, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_LEFT)
set CheckBL = BlzCreateFrame("QuestCheckBox", UI, 0, 0)
call BlzFrameSetAbsPoint(CheckBL, FRAMEPOINT_TOPLEFT, 0.269200, 0.102200)
call BlzFrameSetAbsPoint(CheckBL, FRAMEPOINT_BOTTOMRIGHT, 0.292850, 0.0778100)
set CheckBR = BlzCreateFrame("QuestCheckBox", UI, 0, 0)
call BlzFrameSetAbsPoint(CheckBR, FRAMEPOINT_TOPLEFT, 0.514800, 0.102200)
call BlzFrameSetAbsPoint(CheckBR, FRAMEPOINT_BOTTOMRIGHT, 0.538450, 0.0778100)
set Minimap = BlzCreateFrameByType("BACKDROP", "Minimap", UI, "", 1)
call BlzFrameSetAbsPoint(Minimap, FRAMEPOINT_TOPLEFT, 999.0, 999.0)
call BlzFrameSetAbsPoint(Minimap, FRAMEPOINT_BOTTOMRIGHT, 999.0, 999.0)
call BlzFrameSetTexture(Minimap, "Minimap.blp", 0, true)
set MenuCheck = BlzCreateFrame("QuestCheckBox", UI, 0, 0)
call BlzFrameSetAbsPoint(MenuCheck, FRAMEPOINT_TOPLEFT, 0.918800, 0.601640)
call BlzFrameSetAbsPoint(MenuCheck, FRAMEPOINT_BOTTOMRIGHT, 0.932840, 0.587600)
set LumberIcon = BlzCreateFrameByType("BACKDROP", "LumberIcon", UI, "", 1)
call BlzFrameSetAbsPoint(LumberIcon, FRAMEPOINT_TOPLEFT, 0.347600, 0.0966800)
call BlzFrameSetAbsPoint(LumberIcon, FRAMEPOINT_BOTTOMRIGHT, 0.362600, 0.0816800)
if LUMBER_ICON != "" then
call BlzFrameSetTexture(LumberIcon, LUMBER_ICON, 0, true)
else
call BlzFrameSetVisible(LumberIcon, false)
endif
set GoldIcon = BlzCreateFrameByType("BACKDROP", "GoldIcon", UI, "", 1)
call BlzFrameSetAbsPoint(GoldIcon, FRAMEPOINT_TOPLEFT, 0.445900, 0.0966600)
call BlzFrameSetAbsPoint(GoldIcon, FRAMEPOINT_BOTTOMRIGHT, 0.460900, 0.0816600)
if GOLD_ICON != "" then
call BlzFrameSetTexture(GoldIcon, GOLD_ICON, 0, true)
else
call BlzFrameSetVisible(GoldIcon, false)
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED, function thistype.onSelect)
call BlzTriggerRegisterFrameEvent(herotrigger, HeroCheck, FRAMEEVENT_CHECKBOX_CHECKED)
call BlzTriggerRegisterFrameEvent(herotrigger, HeroCheck, FRAMEEVENT_CHECKBOX_UNCHECKED)
call TriggerAddAction(herotrigger, function thistype.onHeroCheck)
call BlzTriggerRegisterFrameEvent(maptrigger, CheckBL, FRAMEEVENT_CHECKBOX_CHECKED)
call BlzTriggerRegisterFrameEvent(maptrigger, CheckBL, FRAMEEVENT_CHECKBOX_UNCHECKED)
call BlzTriggerRegisterFrameEvent(maptrigger, CheckBR, FRAMEEVENT_CHECKBOX_CHECKED)
call BlzTriggerRegisterFrameEvent(maptrigger, CheckBR, FRAMEEVENT_CHECKBOX_UNCHECKED)
call TriggerAddAction(maptrigger, function thistype.onMinimap)
call BlzTriggerRegisterFrameEvent(menutrigger, MenuCheck, FRAMEEVENT_CHECKBOX_CHECKED)
call BlzTriggerRegisterFrameEvent(menutrigger, MenuCheck, FRAMEEVENT_CHECKBOX_UNCHECKED)
call TriggerAddAction(menutrigger, function thistype.onMenu)
call TimerStart(CreateTimer(), 0.2, true, function thistype.onResources)
loop
exitwhen i > bj_MAX_PLAYER_SLOTS
set x1[i] = 999.0
set x2[i] = 999.0
set y01[i] = 999.0
set y02[i] = 999.0
set y11[i] = 999.0
set y12[i] = 999.0
set y21[i] = 999.0
set y22[i] = 999.0
set y31[i] = 999.0
set y32[i] = 999.0
set y41[i] = 999.0
set y42[i] = 999.0
set y51[i] = 999.0
set y52[i] = 999.0
set y61[i] = 999.0
set y62[i] = 999.0
set mapX1[i] = 999.0
set mapY1[i] = 999.0
set mapX2[i] = 999.0
set mapY2[i] = 999.0
set frameX1[i] = 999.0
set frameY1[i] = 999.0
set frameX2[i] = 999.0
set frameY2[i] = 999.0
set command0X1[i] = 999.0
set command0Y1[i] = 999.0
set command1X1[i] = 999.0
set command1Y1[i] = 999.0
set command2X1[i] = 999.0
set command2Y1[i] = 999.0
set command3X1[i] = 999.0
set command3Y1[i] = 999.0
set command4X1[i] = 999.0
set command4Y1[i] = 999.0
set command5X1[i] = 999.0
set command5Y1[i] = 999.0
set command6X1[i] = 999.0
set command6Y1[i] = 999.0
set command7X1[i] = 999.0
set command7Y1[i] = 999.0
set command8X1[i] = 999.0
set command8Y1[i] = 999.0
set command9X1[i] = 999.0
set command9Y1[i] = 999.0
set command10X1[i] = 999.0
set command10Y1[i] = 999.0
set command11X1[i] = 999.0
set command11Y1[i] = 999.0
set command0X2[i] = 999.0
set command0Y2[i] = 999.0
set command1X2[i] = 999.0
set command1Y2[i] = 999.0
set command2X2[i] = 999.0
set command2Y2[i] = 999.0
set command3X2[i] = 999.0
set command3Y2[i] = 999.0
set command4X2[i] = 999.0
set command4Y2[i] = 999.0
set command5X2[i] = 999.0
set command5Y2[i] = 999.0
set command6X2[i] = 999.0
set command6Y2[i] = 999.0
set command7X2[i] = 999.0
set command7Y2[i] = 999.0
set command8X2[i] = 999.0
set command8Y2[i] = 999.0
set command9X2[i] = 999.0
set command9Y2[i] = 999.0
set command10X2[i] = 999.0
set command10Y2[i] = 999.0
set command11X2[i] = 999.0
set command11Y2[i] = 999.0
set shop[i] = false
set main[i] = null
set checkL[i] = false
set checkR[i] = false
set checkMenu[i] = false
set i = i + 1
endloop
call onCommandButtons()
call onInventoryButtons()
call onInfoPanel()
call onPortrait()
call onGroupSelection()
call onChat()
endmethod
endstruct
endlibrary
library NewBonus requires optional DamageInterface, optional Evasion, optional CriticalStrike, optional SpellPower, optional LifeSteal, optional SpellVamp, optional CooldownReduction, optional Tenacity
/* ---------------------------------------- NewBonus v2.4 --------------------------------------- */
// Since ObjectMerger is broken and we still have no means to edit
// bonus values (green values) i decided to create a light weight
// Bonus library that works in the same way that the original Bonus Mod
// by Earth Fury did. NewBonus requires patch 1.30+.
// Credits to Earth Fury for the original Bonus idea
// How to Import?
// Importing bonus mod is really simple. Just copy the 9 abilities with the
// prefix "NewBonus" from the Object Editor into your map and match their new raw
// code to the bonus types in the global block below. Then create a trigger called
// NewBonus, convert it to custom text and paste this code there. You done!
/* ---------------------------------------- By Chopinski ---------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* Configuration */
/* ---------------------------------------------------------------------------------------------- */
globals
// If true will use the extended version of the system.
// Make sure you have the DamageInterface and Cooldown Reduction libraries
public constant boolean EXTENDED = true
// This is the maximum recursion limit allowed by the system.
// It's value must be greater than or equal to 0. When equal to 0
// no recursion is allowed. Values too big can cause screen freezes.
private constant integer RECURSION_LIMIT = 8
//The bonus types
constant integer BONUS_DAMAGE = 1
constant integer BONUS_ARMOR = 2
constant integer BONUS_AGILITY = 3
constant integer BONUS_STRENGTH = 4
constant integer BONUS_INTELLIGENCE = 5
constant integer BONUS_HEALTH = 6
constant integer BONUS_MANA = 7
constant integer BONUS_MOVEMENT_SPEED = 8
constant integer BONUS_SIGHT_RANGE = 9
constant integer BONUS_HEALTH_REGEN = 10
constant integer BONUS_MANA_REGEN = 11
constant integer BONUS_ATTACK_SPEED = 12
constant integer BONUS_MAGIC_RESISTANCE = 13
constant integer BONUS_EVASION_CHANCE = 14
constant integer BONUS_CRITICAL_DAMAGE = 15
constant integer BONUS_CRITICAL_CHANCE = 16
constant integer BONUS_LIFE_STEAL = 17
constant integer BONUS_MISS_CHANCE = 18
constant integer BONUS_SPELL_POWER_FLAT = 19
constant integer BONUS_SPELL_POWER_PERCENT = 20
constant integer BONUS_SPELL_VAMP = 21
constant integer BONUS_COOLDOWN_REDUCTION = 22
constant integer BONUS_COOLDOWN_REDUCTION_FLAT = 23
constant integer BONUS_COOLDOWN_OFFSET = 24
constant integer BONUS_TENACITY = 25
constant integer BONUS_TENACITY_FLAT = 26
constant integer BONUS_TENACITY_OFFSET = 27
//The abilities codes for each bonus
//When pasting the abilities over to your map
//their raw code should match the bonus here
private constant integer DAMAGE_ABILITY = 'Z001'
private constant integer ARMOR_ABILITY = 'Z002'
private constant integer STATS_ABILITY = 'Z003'
private constant integer HEALTH_ABILITY = 'Z004'
private constant integer MANA_ABILITY = 'Z005'
private constant integer HEALTHREGEN_ABILITY = 'Z006'
private constant integer MANAREGEN_ABILITY = 'Z007'
private constant integer ATTACKSPEED_ABILITY = 'Z008'
private constant integer MOVEMENTSPEED_ABILITY = 'Z009'
private constant integer SIGHT_RANGE_ABILITY = 'Z00A'
private constant integer MAGIC_RESISTANCE_ABILITY = 'Z00B'
private constant integer CRITICAL_STRIKE_ABILITY = 'Z00C'
private constant integer EVASION_ABILITY = 'Z00D'
private constant integer LIFE_STEAL_ABILITY = 'Z00E'
//The abilities fields that are modified. For the sake of readability
private constant abilityintegerlevelfield DAMAGE_FIELD = ABILITY_ILF_ATTACK_BONUS
private constant abilityintegerlevelfield ARMOR_FIELD = ABILITY_ILF_DEFENSE_BONUS_IDEF
private constant abilityintegerlevelfield AGILITY_FIELD = ABILITY_ILF_AGILITY_BONUS
private constant abilityintegerlevelfield STRENGTH_FIELD = ABILITY_ILF_STRENGTH_BONUS_ISTR
private constant abilityintegerlevelfield INTELLIGENCE_FIELD = ABILITY_ILF_INTELLIGENCE_BONUS
private constant abilityintegerlevelfield HEALTH_FIELD = ABILITY_ILF_MAX_LIFE_GAINED
private constant abilityintegerlevelfield MANA_FIELD = ABILITY_ILF_MAX_MANA_GAINED
private constant abilityintegerlevelfield MOVEMENTSPEED_FIELD = ABILITY_ILF_MOVEMENT_SPEED_BONUS
private constant abilityintegerlevelfield SIGHT_RANGE_FIELD = ABILITY_ILF_SIGHT_RANGE_BONUS
private constant abilityreallevelfield HEALTHREGEN_FIELD = ABILITY_RLF_AMOUNT_OF_HIT_POINTS_REGENERATED
private constant abilityreallevelfield MANAREGEN_FIELD = ABILITY_RLF_AMOUNT_REGENERATED
private constant abilityreallevelfield ATTACKSPEED_FIELD = ABILITY_RLF_ATTACK_SPEED_INCREASE_ISX1
private constant abilityreallevelfield MAGIC_RESISTANCE_FIELD = ABILITY_RLF_DAMAGE_REDUCTION_ISR2
private constant abilityreallevelfield CRITICAL_CHANCE_FIELD = ABILITY_RLF_CHANCE_TO_CRITICAL_STRIKE
private constant abilityreallevelfield CRITICAL_DAMAGE_FIELD = ABILITY_RLF_DAMAGE_MULTIPLIER_OCR2
private constant abilityreallevelfield EVASION_FIELD = ABILITY_RLF_CHANCE_TO_EVADE_EEV1
private constant abilityreallevelfield LIFE_STEAL_FIELD = ABILITY_RLF_LIFE_STOLEN_PER_ATTACK
endglobals
/* ---------------------------------------------------------------------------------------------- */
/* JASS API */
/* ---------------------------------------------------------------------------------------------- */
function GetUnitBonus takes unit source, integer bonus returns real
return NewBonus.get(source, bonus)
endfunction
function SetUnitBonus takes unit source, integer bonus, real amount returns real
return NewBonus.Set(source, bonus, amount, false)
endfunction
function RemoveUnitBonus takes unit source, integer bonus returns nothing
if bonus == BONUS_CRITICAL_DAMAGE then
call NewBonus.Set(source, bonus, 1, false)
else
call NewBonus.Set(source, bonus, 0, false)
endif
if bonus == BONUS_LIFE_STEAL then
call UnitRemoveAbility(source, LIFE_STEAL_ABILITY)
endif
endfunction
function AddUnitBonus takes unit source, integer bonus, real amount returns real
return NewBonus.add(source, bonus, amount)
endfunction
function RegisterBonusEvent takes code c returns nothing
call NewBonus.register(c, 0)
endfunction
function RegisterBonusTypeEvent takes integer bonus, code c returns nothing
call NewBonus.register(c, bonus)
endfunction
function GetBonusUnit takes nothing returns unit
return NewBonus.unit[NewBonus.key]
endfunction
function GetBonusType takes nothing returns integer
return NewBonus.type[NewBonus.key]
endfunction
function SetBonusType takes integer bonus returns nothing
if bonus >= BONUS_DAMAGE and bonus <= NewBonus.last then
set NewBonus.type[NewBonus.key] = bonus
endif
endfunction
function GetBonusAmount takes nothing returns real
return NewBonus.amount[NewBonus.key]
endfunction
function SetBonusAmount takes real amount returns nothing
set NewBonus.amount[NewBonus.key] = amount
endfunction
/* ---------------------------------------------------------------------------------------------- */
/* System */
/* ---------------------------------------------------------------------------------------------- */
struct NewBonus
private static trigger trigger = CreateTrigger()
readonly static integer key = -1
private static trigger array event
private static integer count = 0
readonly static unit array unit
readonly static integer last
readonly static integer linkType
static integer array type
static real array amount
private static method checkOverflow takes real current, real value returns real
if value > 0 and current > 2147483647 - value then
return 2147483647 - current
elseif value < 0 and current < -2147483648 - value then
return -2147483648 - current
else
return value
endif
endmethod
private static method onEvent takes integer key returns nothing
local integer i = 0
local integer next = -1
local integer prev = -2
set count = count + 1
if amount[key] != 0 and (count - last < RECURSION_LIMIT) then
loop
exitwhen type[key] == next or (i - last > RECURSION_LIMIT)
set next = type[key]
if event[next] != null then
call TriggerEvaluate(event[next])
endif
if type[key] != next then
set i = i + 1
else
if next != prev then
call TriggerEvaluate(trigger)
if type[key] != next then
set i = i + 1
set prev = next
endif
endif
endif
endloop
endif
set count = count - 1
set .key = key
endmethod
private static method setAbilityI takes unit source, integer id, abilityintegerlevelfield field, real value, boolean adding returns real
if GetUnitAbilityLevel(source, id) == 0 then
call UnitAddAbility(source, id)
call UnitMakeAbilityPermanent(source, true, id)
endif
if adding then
if BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(source, id), field, 0, BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, id), field, 0) + R2I(value)) then
call IncUnitAbilityLevel(source, id)
call DecUnitAbilityLevel(source, id)
endif
else
if BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(source, id), field, 0, R2I(value)) then
call IncUnitAbilityLevel(source, id)
call DecUnitAbilityLevel(source, id)
endif
endif
set linkType = type[key]
if key > -1 then
set key = key - 1
endif
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, id), field, 0))
endmethod
private static method setAbilityR takes unit source, integer id, abilityreallevelfield field, real value returns real
if GetUnitAbilityLevel(source, id) == 0 then
call UnitAddAbility(source, id)
call UnitMakeAbilityPermanent(source, true, id)
endif
if BlzSetAbilityRealLevelField(BlzGetUnitAbility(source, id), field, 0, value) then
call IncUnitAbilityLevel(source, id)
call DecUnitAbilityLevel(source, id)
endif
set linkType = type[key]
if key > -1 then
set key = key - 1
endif
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, id), field, 0)
endmethod
static method get takes unit source, integer bonus returns real
if bonus == BONUS_DAMAGE then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, DAMAGE_ABILITY), DAMAGE_FIELD, 0))
elseif bonus == BONUS_ARMOR then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, ARMOR_ABILITY), ARMOR_FIELD, 0))
elseif bonus == BONUS_HEALTH then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, HEALTH_ABILITY), HEALTH_FIELD, 0))
elseif bonus == BONUS_MANA then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, MANA_ABILITY), MANA_FIELD, 0))
elseif bonus == BONUS_AGILITY then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, STATS_ABILITY), AGILITY_FIELD, 0))
elseif bonus == BONUS_STRENGTH then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, STATS_ABILITY), STRENGTH_FIELD, 0))
elseif bonus == BONUS_INTELLIGENCE then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, STATS_ABILITY), INTELLIGENCE_FIELD, 0))
elseif bonus == BONUS_MOVEMENT_SPEED then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, MOVEMENTSPEED_ABILITY), MOVEMENTSPEED_FIELD, 0))
elseif bonus == BONUS_SIGHT_RANGE then
return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, SIGHT_RANGE_ABILITY), SIGHT_RANGE_FIELD, 0))
elseif bonus == BONUS_HEALTH_REGEN then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, HEALTHREGEN_ABILITY), HEALTHREGEN_FIELD, 0)
elseif bonus == BONUS_MANA_REGEN then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, MANAREGEN_ABILITY), MANAREGEN_FIELD, 0)
elseif bonus == BONUS_ATTACK_SPEED then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, ATTACKSPEED_ABILITY), ATTACKSPEED_FIELD, 0)
elseif bonus == BONUS_MAGIC_RESISTANCE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, MAGIC_RESISTANCE_ABILITY), MAGIC_RESISTANCE_FIELD, 0)
elseif bonus >= BONUS_EVASION_CHANCE and bonus <= last then
static if EXTENDED and LIBRARY_DamageInterface and LIBRARY_Evasion and LIBRARY_CriticalStrike and LIBRARY_SpellPower and LIBRARY_LifeSteal and LIBRARY_SpellVamp and LIBRARY_Tenacity then
if bonus == BONUS_EVASION_CHANCE then
return GetUnitEvasionChance(source)
elseif bonus == BONUS_MISS_CHANCE then
return GetUnitMissChance(source)
elseif bonus == BONUS_CRITICAL_CHANCE then
return GetUnitCriticalChance(source)
elseif bonus == BONUS_CRITICAL_DAMAGE then
return GetUnitCriticalMultiplier(source)
elseif bonus == BONUS_SPELL_POWER_FLAT then
return GetUnitSpellPowerFlat(source)
elseif bonus == BONUS_SPELL_POWER_PERCENT then
return GetUnitSpellPowerPercent(source)
elseif bonus == BONUS_LIFE_STEAL then
return GetUnitLifeSteal(source)
elseif bonus == BONUS_SPELL_VAMP then
return GetUnitSpellVamp(source)
elseif bonus == BONUS_COOLDOWN_REDUCTION then
return GetUnitCooldownReduction(source)
elseif bonus == BONUS_COOLDOWN_REDUCTION_FLAT then
return GetUnitCooldownReductionFlat(source)
elseif bonus == BONUS_COOLDOWN_OFFSET then
return GetUnitCooldownOffset(source)
elseif bonus == BONUS_TENACITY then
return GetUnitTenacity(source)
elseif bonus == BONUS_TENACITY_FLAT then
return GetUnitTenacityFlat(source)
elseif bonus == BONUS_TENACITY_OFFSET then
return GetUnitTenacityOffset(source)
endif
else
if bonus == BONUS_CRITICAL_CHANCE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, CRITICAL_STRIKE_ABILITY), CRITICAL_CHANCE_FIELD, 0)
elseif bonus == BONUS_CRITICAL_DAMAGE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, CRITICAL_STRIKE_ABILITY), CRITICAL_DAMAGE_FIELD, 0)
elseif bonus == BONUS_EVASION_CHANCE then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, EVASION_ABILITY), EVASION_FIELD, 0)
elseif bonus == BONUS_LIFE_STEAL then
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, LIFE_STEAL_ABILITY), LIFE_STEAL_FIELD, 0)
endif
endif
else
call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
endif
return -1.
endmethod
static method Set takes unit source, integer bonus, real value, boolean adding returns real
local real p
if not adding then
set key = key + 1
set unit[key] = source
set type[key] = bonus
set amount[key] = value
call onEvent(key)
if amount[key] != value then
set value = amount[key]
endif
if type[key] != bonus then
return Set(unit[key], type[key], amount[key], not adding)
endif
else
set unit[key] = source
set type[key] = bonus
set amount[key] = value
endif
if bonus == BONUS_DAMAGE then
return setAbilityI(source, DAMAGE_ABILITY, DAMAGE_FIELD, value, adding)
elseif bonus == BONUS_ARMOR then
return setAbilityI(source, ARMOR_ABILITY, ARMOR_FIELD, value, adding)
elseif bonus == BONUS_HEALTH then
set p = GetUnitLifePercent(source)
if value == 0 and not adding then
call BlzSetUnitMaxHP(source, R2I(BlzGetUnitMaxHP(source) - get(source, bonus)))
else
call BlzSetUnitMaxHP(source, R2I(BlzGetUnitMaxHP(source) + value))
endif
call setAbilityI(source, HEALTH_ABILITY, HEALTH_FIELD, value, adding)
call SetUnitLifePercentBJ(source, p)
return value
elseif bonus == BONUS_MANA then
set p = GetUnitManaPercent(source)
if value == 0 and not adding then
call BlzSetUnitMaxMana(source, R2I(BlzGetUnitMaxMana(source) - get(source, bonus)))
else
call BlzSetUnitMaxMana(source, R2I(BlzGetUnitMaxMana(source) + value))
endif
call setAbilityI(source, MANA_ABILITY, MANA_FIELD, value, adding)
call SetUnitManaPercentBJ(source, p)
return value
elseif bonus == BONUS_AGILITY then
return setAbilityI(source, STATS_ABILITY, AGILITY_FIELD, value, adding)
elseif bonus == BONUS_STRENGTH then
return setAbilityI(source, STATS_ABILITY, STRENGTH_FIELD, value, adding)
elseif bonus == BONUS_INTELLIGENCE then
return setAbilityI(source, STATS_ABILITY, INTELLIGENCE_FIELD, value, adding)
elseif bonus == BONUS_MOVEMENT_SPEED then
return setAbilityI(source, MOVEMENTSPEED_ABILITY, MOVEMENTSPEED_FIELD, value, adding)
elseif bonus == BONUS_SIGHT_RANGE then
if value == 0 and not adding then
call BlzSetUnitRealField(source, UNIT_RF_SIGHT_RADIUS, (BlzGetUnitRealField(source, UNIT_RF_SIGHT_RADIUS) - get(source, bonus)))
else
call BlzSetUnitRealField(source, UNIT_RF_SIGHT_RADIUS, (BlzGetUnitRealField(source, UNIT_RF_SIGHT_RADIUS) + value))
endif
call setAbilityI(source, SIGHT_RANGE_ABILITY, SIGHT_RANGE_FIELD, value, adding)
return value
elseif bonus == BONUS_HEALTH_REGEN then
return setAbilityR(source, HEALTHREGEN_ABILITY, HEALTHREGEN_FIELD, value)
elseif bonus == BONUS_MANA_REGEN then
return setAbilityR(source, MANAREGEN_ABILITY, MANAREGEN_FIELD, value)
elseif bonus == BONUS_ATTACK_SPEED then
return setAbilityR(source, ATTACKSPEED_ABILITY, ATTACKSPEED_FIELD, value)
elseif bonus == BONUS_MAGIC_RESISTANCE then
return setAbilityR(source, MAGIC_RESISTANCE_ABILITY, MAGIC_RESISTANCE_FIELD, value)
elseif bonus >= BONUS_EVASION_CHANCE and bonus <= last then
static if EXTENDED and LIBRARY_DamageInterface and LIBRARY_Evasion and LIBRARY_CriticalStrike and LIBRARY_SpellPower and LIBRARY_LifeSteal and LIBRARY_SpellVamp and LIBRARY_Tenacity then
if bonus == BONUS_EVASION_CHANCE then
call SetUnitEvasionChance(source, value)
elseif bonus == BONUS_MISS_CHANCE then
call SetUnitMissChance(source, value)
elseif bonus == BONUS_CRITICAL_CHANCE then
call SetUnitCriticalChance(source, value)
elseif bonus == BONUS_CRITICAL_DAMAGE then
call SetUnitCriticalMultiplier(source, value)
elseif bonus == BONUS_SPELL_POWER_FLAT then
call SetUnitSpellPowerFlat(source, value)
elseif bonus == BONUS_SPELL_POWER_PERCENT then
call SetUnitSpellPowerPercent(source, value)
elseif bonus == BONUS_LIFE_STEAL then
call SetUnitLifeSteal(source, value)
elseif bonus == BONUS_SPELL_VAMP then
call SetUnitSpellVamp(source, value)
elseif bonus == BONUS_COOLDOWN_REDUCTION then
if adding then
call UnitAddCooldownReduction(source, value)
else
call SetUnitCooldownReduction(source, value)
endif
elseif bonus == BONUS_COOLDOWN_REDUCTION_FLAT then
call SetUnitCooldownReductionFlat(source, value)
elseif bonus == BONUS_COOLDOWN_OFFSET then
call SetUnitCooldownOffset(source, value)
elseif bonus == BONUS_TENACITY then
if adding then
call UnitAddTenacity(source, value)
else
call SetUnitTenacity(source, value)
endif
elseif bonus == BONUS_TENACITY_FLAT then
call SetUnitTenacityFlat(source, value)
elseif bonus == BONUS_TENACITY_OFFSET then
call SetUnitTenacityOffset(source, value)
endif
set linkType = bonus
if key > -1 then
set key = key - 1
endif
return value
else
if bonus == BONUS_CRITICAL_CHANCE then
return setAbilityR(source, CRITICAL_STRIKE_ABILITY, CRITICAL_CHANCE_FIELD, value)
elseif bonus == BONUS_CRITICAL_DAMAGE then
return setAbilityR(source, CRITICAL_STRIKE_ABILITY, CRITICAL_DAMAGE_FIELD, value)
elseif bonus == BONUS_EVASION_CHANCE then
return setAbilityR(source, EVASION_ABILITY, EVASION_FIELD, value)
elseif bonus == BONUS_LIFE_STEAL then
return setAbilityR(source, LIFE_STEAL_ABILITY, LIFE_STEAL_FIELD, value)
endif
endif
else
call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
endif
return -1.
endmethod
static method add takes unit source, integer bonus, real value returns real
if value != 0 then
set key = key + 1
set unit[key] = source
set type[key] = bonus
set amount[key] = value
if bonus <= BONUS_SIGHT_RANGE then
set amount[key] = checkOverflow(get(source, bonus), R2I(value))
endif
call onEvent(key)
set value = amount[key]
if type[key] <= BONUS_SIGHT_RANGE then
call Set(unit[key], type[key], checkOverflow(get(unit[key], type[key]), R2I(amount[key])), true)
else
static if EXTENDED and LIBRARY_DamageInterface and LIBRARY_Evasion and LIBRARY_CriticalStrike and LIBRARY_SpellPower and LIBRARY_LifeSteal and LIBRARY_SpellVamp and LIBRARY_Tenacity then
if type[key] == BONUS_COOLDOWN_REDUCTION or type[key] == BONUS_TENACITY then
call Set(unit[key], type[key], amount[key], true)
else
call Set(unit[key], type[key], get(unit[key], type[key]) + amount[key], true)
endif
else
call Set(unit[key], type[key], get(unit[key], type[key]) + amount[key], true)
endif
endif
return value
endif
return 0.
endmethod
static method register takes code c, integer bonus returns nothing
if bonus >= BONUS_DAMAGE and bonus <= last then
if event[bonus] == null then
set event[bonus] = CreateTrigger()
endif
call TriggerAddCondition(event[bonus], Filter(c))
else
call TriggerAddCondition(trigger, Filter(c))
endif
endmethod
private static method onInit takes nothing returns nothing
static if EXTENDED and LIBRARY_DamageInterface and LIBRARY_Evasion and LIBRARY_CriticalStrike and LIBRARY_SpellPower and LIBRARY_LifeSteal and LIBRARY_SpellVamp and LIBRARY_Tenacity then
set last = BONUS_TENACITY_OFFSET
else
set last = BONUS_LIFE_STEAL
endif
endmethod
endstruct
endlibrary
library NewBonusUtils requires NewBonus, RegisterPlayerUnitEvent
/* ------------------------------------- NewBonusUtils v2.4 ------------------------------------- */
// Required Library: RegisterPlayerUnitEvent -> www.hiveworkshop.com/threads/snippet-registerplayerunitevent.203338/
// API:
// function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
// -> Add the specified amount for the specified bonus type for unit for a duration
// -> Example: call AddUnitBonusTimed(GetTriggerUnit(), BONUS_ARMOR, 13, 10.5)
// function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
// -> Links the bonus amount specified to a buff or ability. As long as the unit has the buff or
// -> the ability represented by the parameter buffId the bonus is not removed.
// -> Example: call LinkBonusToBuff(GetTriggerUnit(), BONUS_ARMOR, 10, 'B000')
// function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
// -> Links the bonus amount specified to an item. As long as the unit has that item the bonus is not removed.
// -> Note that it will work for items with the same id, because it takes as parameter the item object.
// -> Example: call LinkBonusToItem(GetManipulatingUnit(), BONUS_ARMOR, 10, GetManipulatedItem())
// function UnitCopyBonuses takes unit source, unit target returns nothing
// -> Copy the source unit bonuses using the Add functionality to the target unit
// -> Example: call UnitCopyBonuses(GetTriggerUnit(), GetSummonedUnit())
// function UnitMirrorBonuses takes unit source, unit target returns nothing
// -> Copy the source unit bonuses using the Set functionality to the target unit
// -> Example: call UnitMirrorBonuses(GetTriggerUnit(), GetSummonedUnit())
/* ---------------------------------------- By Chopinski ---------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* JASS API */
/* ---------------------------------------------------------------------------------------------- */
function AddUnitBonusTimed takes unit source, integer bonus, real amount, real duration returns nothing
call NewBonusUtils.linkTimed(source, bonus, amount, duration, true)
endfunction
function LinkBonusToBuff takes unit source, integer bonus, real amount, integer id returns nothing
call NewBonusUtils.linkBuff(source, bonus, amount, id, false)
endfunction
function LinkBonusToItem takes unit source, integer bonus, real amount, item i returns nothing
call NewBonusUtils.linkItem(source, bonus, amount, i)
endfunction
function UnitCopyBonuses takes unit source, unit target returns nothing
call NewBonusUtils.copy(source, target)
endfunction
function UnitMirrorBonuses takes unit source, unit target returns nothing
call NewBonusUtils.mirror(source, target)
endfunction
/* ---------------------------------------------------------------------------------------------- */
/* System */
/* ---------------------------------------------------------------------------------------------- */
struct NewBonusUtils extends NewBonus
static constant real period = 0.03125000
static timer timer = CreateTimer()
static integer index = -1
static thistype array array
static integer k = -1
static thistype array items
unit source
item item
real duration
integer bonus_t
integer buff
real value
boolean link
method remove takes integer i, boolean isItem returns integer
static if NewBonus_EXTENDED and LIBRARY_DamageInterface and LIBRARY_Evasion and LIBRARY_CriticalStrike and LIBRARY_SpellPower and LIBRARY_LifeSteal and LIBRARY_SpellVamp and LIBRARY_Tenacity then
if bonus_t == BONUS_COOLDOWN_REDUCTION then
call UnitRemoveCooldownReduction(source, value)
elseif bonus_t == BONUS_TENACITY then
call UnitRemoveTenacity(source, value)
else
call AddUnitBonus(source, bonus_t, -value)
endif
else
call AddUnitBonus(source, bonus_t, -value)
endif
if isItem then
set items[i] = items[k]
set k = k - 1
else
set array[i] = array[index]
set index = index - 1
if index == -1 then
call PauseTimer(timer)
endif
endif
set source = null
set item = null
call deallocate()
return i - 1
endmethod
static method onDrop takes nothing returns nothing
local item itm = GetManipulatedItem()
local integer i = 0
local thistype this
loop
exitwhen i > k
set this = items[i]
if item == itm then
set i = remove(i, true)
endif
set i = i + 1
endloop
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > index
set this = array[i]
if link then
if duration <= 0 then
set i = remove(i, false)
endif
set duration = duration - period
else
if GetUnitAbilityLevel(source, buff) == 0 then
set i = remove(i, false)
endif
endif
set i = i + 1
endloop
endmethod
static method linkTimed takes unit source, integer bonus, real amount, real duration, boolean link returns nothing
local thistype this = thistype.allocate()
set this.source = source
set this.duration = duration
set this.link = link
set this.value = AddUnitBonus(source, bonus, amount)
set this.bonus_t = linkType
set index = index + 1
set array[index] = this
if index == 0 then
call TimerStart(timer, period, true, function thistype.onPeriod)
endif
endmethod
static method linkBuff takes unit source, integer bonus, real amount, integer id, boolean link returns nothing
local thistype this = thistype.allocate()
set this.source = source
set this.buff = id
set this.link = link
set this.value = AddUnitBonus(source, bonus, amount)
set this.bonus_t = linkType
set index = index + 1
set array[index] = this
if index == 0 then
call TimerStart(timer, period, true, function thistype.onPeriod)
endif
endmethod
static method linkItem takes unit source, integer bonus, real amount, item i returns nothing
local thistype this = thistype.allocate()
set this.source = source
set this.item = i
set this.value = AddUnitBonus(source, bonus, amount)
set this.bonus_t = linkType
set k = k + 1
set items[k] = this
endmethod
static method copy takes unit source, unit target returns nothing
local integer i = 1
loop
exitwhen i > last
if GetUnitBonus(source, i) != 0 then
call AddUnitBonus(target, i, GetUnitBonus(source, i))
endif
set i = i + 1
endloop
endmethod
static method mirror takes unit source, unit target returns nothing
local integer i = 1
loop
exitwhen i > last
call SetUnitBonus(target, i, GetUnitBonus(source, i))
set i = i + 1
endloop
endmethod
static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.onDrop)
endmethod
endstruct
endlibrary
library CrowdControl requires Utilities, WorldBounds, Indexer, TimerUtils, RegisterPlayerUnitEvent, optional Tenacity
/* ------------------------------------- Crowd Control v1.0 ------------------------------------- */
// How to Import:
// 1 - Copy the Utilities library over to your map and follow its install instructions
// 2 - Copy the WorldBounds library over to your map and follow its install instructions
// 3 - Copy the Indexer library over to your map and follow its install instructions
// 4 - Copy the TimerUtils library over to your map and follow its install instructions
// 5 - Copy the RegisterPlayerUnitEvent library over to your map and follow its install instructions
// 6 - Copy the Tenacity library over to your map and follow its install instructions
// 7 - Copy this library into your map
// 8 - Copy the 14 buffs and 15 abilities with the CC prefix and match their raw code below.
/* ---------------------------------------- By Chopinski ---------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* Configuration */
/* ---------------------------------------------------------------------------------------------- */
globals
// The raw code of the silence ability
private constant integer SILENCE = 'U000'
// The raw code of the stun ability
private constant integer STUN = 'U001'
// The raw code of the attack slow ability
private constant integer ATTACK_SLOW = 'U002'
// The raw code of the movement slow ability
private constant integer MOVEMENT_SLOW = 'U003'
// The raw code of the banish ability
private constant integer BANISH = 'U004'
// The raw code of the ensnare ability
private constant integer ENSNARE = 'U005'
// The raw code of the purge ability
private constant integer PURGE = 'U006'
// The raw code of the hex ability
private constant integer HEX = 'U007'
// The raw code of the sleep ability
private constant integer SLEEP = 'U008'
// The raw code of the cyclone ability
private constant integer CYCLONE = 'U009'
// The raw code of the entangle ability
private constant integer ENTANGLE = 'U010'
// The raw code of the disarm ability
private constant integer DISARM = 'U011'
// The raw code of the fear ability
private constant integer FEAR = 'U012'
// The raw code of the taunt ability
private constant integer TAUNT = 'U013'
// The raw code of the true sight ability
private constant integer TRUE_SIGHT = 'U014'
// The raw code of the silence buff
private constant integer SILENCE_BUFF = 'BU00'
// The raw code of the stun buff
private constant integer STUN_BUFF = 'BU01'
// The raw code of the attack slow buff
private constant integer ATTACK_SLOW_BUFF = 'BU02'
// The raw code of the movement slow buff
private constant integer MOVEMENT_SLOW_BUFF = 'BU03'
// The raw code of the banish buff
private constant integer BANISH_BUFF = 'BU04'
// The raw code of the ensnare buff
private constant integer ENSNARE_BUFF = 'BU05'
// The raw code of the purge buff
private constant integer PURGE_BUFF = 'BU06'
// The raw code of the hex buff
private constant integer HEX_BUFF = 'BU07'
// The raw code of the sleep buff
private constant integer SLEEP_BUFF = 'BU08'
// The raw code of the cyclone buff
private constant integer CYCLONE_BUFF = 'BU09'
// The raw code of the entangle buff
private constant integer ENTANGLE_BUFF = 'BU10'
// The raw code of the disarm buff
private constant integer DISARM_BUFF = 'BU11'
// The raw code of the fear buff
private constant integer FEAR_BUFF = 'BU12'
// The raw code of the taunt buff
private constant integer TAUNT_BUFF = 'BU13'
// This is the maximum recursion limit allowed by the system.
// Its value must be greater than or equal to 0. When equal to 0
// no recursion is allowed. Values too big can cause screen freezes.
private constant integer RECURSION_LIMIT = 8
// The Crowd Control types
constant integer CROWD_CONTROL_SILENCE = 0
constant integer CROWD_CONTROL_STUN = 1
constant integer CROWD_CONTROL_SLOW = 2
constant integer CROWD_CONTROL_SLOW_ATTACK = 3
constant integer CROWD_CONTROL_BANISH = 4
constant integer CROWD_CONTROL_ENSNARE = 5
constant integer CROWD_CONTROL_PURGE = 6
constant integer CROWD_CONTROL_HEX = 7
constant integer CROWD_CONTROL_SLEEP = 8
constant integer CROWD_CONTROL_CYCLONE = 9
constant integer CROWD_CONTROL_ENTANGLE = 10
constant integer CROWD_CONTROL_DISARM = 11
constant integer CROWD_CONTROL_FEAR = 12
constant integer CROWD_CONTROL_TAUNT = 13
constant integer CROWD_CONTROL_KNOCKBACK = 14
constant integer CROWD_CONTROL_KNOCKUP = 15
endglobals
/* ---------------------------------------------------------------------------------------------- */
/* JASS API */
/* ---------------------------------------------------------------------------------------------- */
/* ------------------------------------------- Disarm ------------------------------------------- */
function DisarmUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.disarm(target, duration, model, point, stack)
endfunction
function IsUnitDisarmed takes unit target returns boolean
return CrowdControl.disarmed(target)
endfunction
/* -------------------------------------------- Fear -------------------------------------------- */
function FearUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.fear(target, duration, model, point, stack)
endfunction
function IsUnitFeared takes unit target returns boolean
return CrowdControl.feared(target)
endfunction
/* -------------------------------------------- Taunt ------------------------------------------- */
function TauntUnit takes unit source, unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.taunt(source, target, duration, model, point, stack)
endfunction
function IsUnitTaunted takes unit target returns boolean
return CrowdControl.taunted(target)
endfunction
/* ------------------------------------------ Knockback ----------------------------------------- */
function KnockbackUnit takes unit target, real angle, real distance, real duration, string model, string point, boolean onCliff, boolean onDestructable, boolean onUnit, boolean stack returns nothing
call CrowdControl.knockback(target, angle, distance, duration, model, point, onCliff, onDestructable, onUnit, stack)
endfunction
function IsUnitKnockedBack takes unit target returns boolean
return CrowdControl.knockedback(target)
endfunction
/* ------------------------------------------- Knockup ------------------------------------------ */
function KnockupUnit takes unit target, real maxHeight, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.knockup(target, maxHeight, duration, model, point, stack)
endfunction
function IsUnitKnockedUp takes unit target returns boolean
return CrowdControl.knockedup(target)
endfunction
/* ------------------------------------------- Silence ------------------------------------------ */
function SilenceUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.silence(target, duration, model, point, stack)
endfunction
function IsUnitSilenced takes unit target returns boolean
return CrowdControl.silenced(target)
endfunction
/* -------------------------------------------- Stun -------------------------------------------- */
function StunUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.stun(target, duration, model, point, stack)
endfunction
function IsUnitStunned takes unit target returns boolean
return CrowdControl.stunned(target)
endfunction
/* ---------------------------------------- Movement Slow --------------------------------------- */
function SlowUnit takes unit target, real amount, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.slow(target, amount, duration, model, point, stack)
endfunction
function IsUnitSlowed takes unit target returns boolean
return CrowdControl.slowed(target)
endfunction
/* ----------------------------------------- Attack Slow ---------------------------------------- */
function SlowUnitAttack takes unit target, real amount, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.slowAttack(target, amount, duration, model, point, stack)
endfunction
function IsUnitAttackSlowed takes unit target returns boolean
return CrowdControl.attackSlowed(target)
endfunction
/* ------------------------------------------- Banish ------------------------------------------- */
function BanishUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.banish(target, duration, model, point, stack)
endfunction
function IsUnitBanished takes unit target returns boolean
return CrowdControl.banished(target)
endfunction
/* ------------------------------------------- Ensnare ------------------------------------------ */
function EnsnareUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.ensnare(target, duration, model, point, stack)
endfunction
function IsUnitEnsnared takes unit target returns boolean
return CrowdControl.ensnared(target)
endfunction
/* -------------------------------------------- Purge ------------------------------------------- */
function PurgeUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.purge(target, duration, model, point, stack)
endfunction
function IsUnitPurged takes unit target returns boolean
return CrowdControl.purged(target)
endfunction
/* --------------------------------------------- Hex -------------------------------------------- */
function HexUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.hex(target, duration, model, point, stack)
endfunction
function IsUnitHexed takes unit target returns boolean
return CrowdControl.hexed(target)
endfunction
/* -------------------------------------------- Sleep ------------------------------------------- */
function SleepUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.sleep(target, duration, model, point, stack)
endfunction
function IsUnitSleeping takes unit target returns boolean
return CrowdControl.sleeping(target)
endfunction
/* ------------------------------------------- Cyclone ------------------------------------------ */
function CycloneUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.cyclone(target, duration, model, point, stack)
endfunction
function IsUnitCycloned takes unit target returns boolean
return CrowdControl.cycloned(target)
endfunction
/* ------------------------------------------ Entangle ------------------------------------------ */
function EntangleUnit takes unit target, real duration, string model, string point, boolean stack returns nothing
call CrowdControl.entangle(target, duration, model, point, stack)
endfunction
function IsUnitEntangled takes unit target returns boolean
return CrowdControl.entangled(target)
endfunction
/* ------------------------------------------- Dispel ------------------------------------------- */
function UnitDispelCrowdControl takes unit target, integer id returns nothing
call CrowdControl.dispel(target, id)
endfunction
function UnitDispelAllCrowdControl takes unit target returns nothing
call CrowdControl.dispelAll(target)
endfunction
/* ------------------------------------------- Events ------------------------------------------- */
function RegisterCrowdControlEvent takes integer id, code c returns nothing
call CrowdControl.register(id, c)
endfunction
function RegisterAnyCrowdControlEvent takes code c returns nothing
call CrowdControl.register(-1, c)
endfunction
function GetCrowdControlUnit takes nothing returns unit
return CrowdControl.unit[CrowdControl.key]
endfunction
function GetCrowdControlType takes nothing returns integer
return CrowdControl.type[CrowdControl.key]
endfunction
function GetCrowdControlDuration takes nothing returns real
return CrowdControl.duration[CrowdControl.key]
endfunction
function GetCrowdControlAmount takes nothing returns real
return CrowdControl.amount[CrowdControl.key]
endfunction
function GetCrowdControlModel takes nothing returns string
return CrowdControl.model[CrowdControl.key]
endfunction
function GetCrowdControlBone takes nothing returns string
return CrowdControl.point[CrowdControl.key]
endfunction
function GetCrowdControlStack takes nothing returns boolean
return CrowdControl.stack[CrowdControl.key]
endfunction
function GetCrowdControlRemaining takes unit target, integer id returns real
return CrowdControl.remaining(target, id)
endfunction
function GetTauntSource takes nothing returns unit
return CrowdControl.source[CrowdControl.key]
endfunction
function GetKnockbackAngle takes nothing returns real
return CrowdControl.angle[CrowdControl.key]
endfunction
function GetKnockbackDistance takes nothing returns real
return CrowdControl.distance[CrowdControl.key]
endfunction
function GetKnockupHeight takes nothing returns real
return CrowdControl.height[CrowdControl.key]
endfunction
function GetKnockbackOnCliff takes nothing returns boolean
return CrowdControl.cliff[CrowdControl.key]
endfunction
function GetKnockbackOnDestructable takes nothing returns boolean
return CrowdControl.destructable[CrowdControl.key]
endfunction
function GetKnockbackOnUnit takes nothing returns boolean
return CrowdControl.agent[CrowdControl.key]
endfunction
function SetCrowdControlUnit takes unit u returns nothing
set CrowdControl.unit[CrowdControl.key] = u
endfunction
function SetCrowdControlType takes integer id returns nothing
if id >= CROWD_CONTROL_SILENCE and id <= CROWD_CONTROL_KNOCKUP then
set CrowdControl.type[CrowdControl.key] = id
endif
endfunction
function SetCrowdControlDuration takes real duration returns nothing
set CrowdControl.duration[CrowdControl.key] = duration
endfunction
function SetCrowdControlAmount takes real amount returns nothing
set CrowdControl.amount[CrowdControl.key] = amount
endfunction
function SetCrowdControlModel takes string model returns nothing
set CrowdControl.model[CrowdControl.key] = model
endfunction
function SetCrowdControlBone takes string point returns nothing
set CrowdControl.point[CrowdControl.key] = point
endfunction
function SetCrowdControlStack takes boolean stack returns nothing
set CrowdControl.stack[CrowdControl.key] = stack
endfunction
function SetTauntSource takes unit u returns nothing
set CrowdControl.source[CrowdControl.key] = u
endfunction
function SetKnockbackAngle takes real angle returns nothing
set CrowdControl.angle[CrowdControl.key] = angle
endfunction
function SetKnockbackDistance takes real distance returns nothing
set CrowdControl.distance[CrowdControl.key] = distance
endfunction
function SetKnockupHeight takes real height returns nothing
set CrowdControl.height[CrowdControl.key] = height
endfunction
function SetKnockbackOnCliff takes boolean onCliff returns nothing
set CrowdControl.cliff[CrowdControl.key] = onCliff
endfunction
function SetKnockbackOnDestructable takes boolean onDestructable returns nothing
set CrowdControl.destructable[CrowdControl.key] = onDestructable
endfunction
function SetKnockbackOnUnit takes boolean onUnit returns nothing
set CrowdControl.agent[CrowdControl.key] = onUnit
endfunction
/* ---------------------------------------------------------------------------------------------- */
/* Systems */
/* ---------------------------------------------------------------------------------------------- */
/* ------------------------------------------ Knockback ----------------------------------------- */
struct Knockback
private static timer timer = CreateTimer()
private static rect rect = Rect(0., 0., 0., 0.)
private static constant real period = 0.03125
private static thistype array array
private static integer array struct
private static integer key = -1
private static thistype temp
private unit unit
private group group
private real angle
private real offset
private real distance
private real duration
private real collision
private integer id
private effect effect
private boolean onCliff
private boolean onDest
private boolean onUnit
private method remove takes integer i returns integer
call DestroyGroup(group)
call DestroyEffect(effect)
call BlzPauseUnitEx(unit, false)
set unit = null
set group = null
set effect = null
set struct[id] = 0
set array[i] = array[key]
set key = key - 1
call deallocate()
if key == -1 then
call PauseTimer(timer)
endif
return i - 1
endmethod
private static method onDestructable takes nothing returns nothing
local thistype this = temp
if GetDestructableLife(GetEnumDestructable()) > 0 then
set duration = 0
return
endif
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
local real x
local real y
local unit u
loop
exitwhen i > key
set this = array[i]
if duration > 0 and UnitAlive(unit) then
set duration = duration - period
set x = GetUnitX(unit) + offset*Cos(angle)
set y = GetUnitY(unit) + offset*Sin(angle)
if onUnit and collision > 0 then
call GroupEnumUnitsInRange(group, x, y, collision, null)
call GroupRemoveUnit(group, unit)
loop
set u = FirstOfGroup(group)
exitwhen u == null
if UnitAlive(u) then
set duration = 0
set u = null
exitwhen true
endif
call GroupRemoveUnit(group, u)
endloop
endif
if onDest and duration > 0 and collision > 0 then
set temp = this
call SetRect(rect, x - collision, y - collision, x + collision, y + collision)
call EnumDestructablesInRect(rect, null, function thistype.onDestructable)
endif
if onCliff and duration > 0 then
if GetTerrainCliffLevel(GetUnitX(unit), GetUnitY(unit)) < GetTerrainCliffLevel(x, y) and GetUnitZ(unit) < (GetTerrainCliffLevel(x, y) - GetTerrainCliffLevel(WorldBounds.maxX, WorldBounds.maxY))*bj_CLIFFHEIGHT then
set duration = 0
endif
endif
if duration > 0 then
call SetUnitX(unit, x)
call SetUnitY(unit, y)
endif
else
set i = remove(i)
endif
set i = i + 1
endloop
endmethod
static method knocked takes unit u returns boolean
return struct[GetUnitUserData(u)] != 0
endmethod
static method apply takes unit target, real angle, real distance, real duration, string model, string point, boolean onCliff, boolean onDestructable, boolean onUnit returns nothing
local integer id = GetUnitUserData(target)
local thistype this
if duration > 0 and UnitAlive(target) then
if struct[id] != 0 then
set this = struct[id]
else
set this = thistype.allocate()
set .id = id
set .unit = target
set .collision = 2*BlzGetUnitCollisionSize(target)
set .group = CreateGroup()
set key = key + 1
set array[key] = this
set struct[id] = this
call BlzPauseUnitEx(target, true)
if model != null and point != null then
set effect = AddSpecialEffectTarget(model, target, point)
endif
if key == 0 then
call TimerStart(timer, period, true, function thistype.onPeriod)
endif
endif
set .angle = angle
set .distance = distance
set .duration = duration
set .onCliff = onCliff
set .onDest = onDestructable
set .onUnit = onUnit
set .offset = RMaxBJ(0.00000001, distance*period/RMaxBJ(0.00000001, duration))
endif
endmethod
endstruct
/* ------------------------------------------- Knockup ------------------------------------------ */
struct Knockup
private static integer array knocked
timer timer
unit unit
effect effect
integer key
boolean up
real rate
real airTime
static method isUnitKnocked takes unit u returns boolean
return knocked[GetUnitUserData(u)] > 0
endmethod
private static method onPeriod takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
if up then
set up = false
call SetUnitFlyHeight(unit, GetUnitDefaultFlyHeight(unit), rate)
call TimerStart(timer, airTime/2, false, function thistype.onPeriod)
else
call DestroyEffect(effect)
call ReleaseTimer(timer)
call deallocate()
set knocked[key] = knocked[key] - 1
if knocked[key] == 0 then
call BlzPauseUnitEx(unit, false)
endif
set timer = null
set unit = null
set effect = null
endif
endmethod
static method apply takes unit whichUnit, real airTime, real maxHeight, string model, string point returns nothing
local thistype this
if airTime > 0 then
set this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = whichUnit
set rate = maxHeight/airTime
set .airTime = airTime
set up = true
set key = GetUnitUserData(unit)
set knocked[key] = knocked[key] + 1
if model != null and point != null then
set effect = AddSpecialEffectTarget(model, unit, point)
endif
if knocked[key] == 1 then
call BlzPauseUnitEx(whichUnit, true)
endif
call UnitAddAbility(unit, 'Amrf')
call UnitRemoveAbility(unit, 'Amrf')
call SetUnitFlyHeight(unit, (GetUnitDefaultFlyHeight(unit) + maxHeight), rate)
call TimerStart(timer, airTime/2, false, function thistype.onPeriod)
endif
endmethod
endstruct
/* -------------------------------------------- Fear -------------------------------------------- */
struct Fear
private static timer timer = CreateTimer()
private static constant integer DIRECTION_CHANGE = 5
private static constant real MAX_CHANGE = 200.
private static constant real PERIOD = 1./5.
private static integer key = -1
private static thistype array array
private static integer array struct
private static boolean array flag
private static real array x
private static real array y
private static ability ability
private static unit dummy
unit unit
effect effect
integer id
integer change
static method feared takes unit target returns boolean
return GetUnitAbilityLevel(target, FEAR_BUFF) > 0
endmethod
method remove takes integer i returns integer
set flag[id] = true
call IssueImmediateOrder(unit, "stop")
call DestroyEffect(effect)
set struct[id] = 0
set unit = null
set effect = null
set array[i] = array[key]
set key = key - 1
call deallocate()
if key == -1 then
call PauseTimer(timer)
endif
return i - 1
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > key
set this = array[i]
if GetUnitAbilityLevel(unit, FEAR_BUFF) > 0 then
set change = change + 1
if change >= DIRECTION_CHANGE then
set change = 0
set flag[id] = true
set x[id] = GetRandomReal(GetUnitX(unit) - MAX_CHANGE, GetUnitX(unit) + MAX_CHANGE)
set y[id] = GetRandomReal(GetUnitY(unit) - MAX_CHANGE, GetUnitY(unit) + MAX_CHANGE)
call IssuePointOrder(unit, "move", x[id], y[id])
endif
else
set i = remove(i)
endif
set i = i + 1
endloop
endmethod
static method apply takes unit whichUnit, real duration, string model, string point returns nothing
local integer id = GetUnitUserData(whichUnit)
local thistype this
if duration > 0 then
call BlzSetAbilityRealLevelField(ability, ABILITY_RLF_DURATION_NORMAL, 0, duration)
call BlzSetAbilityRealLevelField(ability, ABILITY_RLF_DURATION_HERO, 0, duration)
call IncUnitAbilityLevel(dummy, FEAR)
call DecUnitAbilityLevel(dummy, FEAR)
if IssueTargetOrder(dummy, "drunkenhaze", whichUnit) then
if struct[id] != 0 then
set this = struct[id]
else
set this = thistype.allocate()
set .id = id
set unit = whichUnit
set change = 0
set key = key + 1
set array[key] = this
set struct[id] = this
if model != null and point != null then
set effect = AddSpecialEffectTarget(model, whichUnit, point)
endif
if key == 0 then
call TimerStart(timer, PERIOD, true, function thistype.onPeriod)
endif
endif
set flag[id] = true
set x[id] = GetRandomReal(GetUnitX(whichUnit) - MAX_CHANGE, GetUnitX(whichUnit) + MAX_CHANGE)
set y[id] = GetRandomReal(GetUnitY(whichUnit) - MAX_CHANGE, GetUnitY(whichUnit) + MAX_CHANGE)
call IssuePointOrder(whichUnit, "move", x[id], y[id])
endif
endif
endmethod
private static method onOrder takes nothing returns nothing
local unit source = GetOrderedUnit()
local integer id
if feared(source) and GetIssuedOrderId() != 851973 then
set id = GetUnitUserData(source)
if not flag[id] then
set flag[id] = true
call IssuePointOrder(source, "move", x[id], y[id])
else
set flag[id] = false
endif
endif
set source = null
endmethod
private static method onInit takes nothing returns nothing
set dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetRectCenterX(GetWorldBounds()), GetRectCenterY(GetWorldBounds()), 0, 0)
call UnitAddAbility(dummy, TRUE_SIGHT)
call UnitAddAbility(dummy, FEAR)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER, function thistype.onOrder)
set ability = BlzGetUnitAbility(dummy, FEAR)
endmethod
endstruct
/* -------------------------------------------- Taunt ------------------------------------------- */
struct Taunt
private static constant real PERIOD = 0.2
private static unit dummy
private static integer key = -1
private static thistype array array
private static integer array struct
private static timer timer = CreateTimer()
private static ability ability
readonly static unit array source
unit unit
effect effect
integer id
boolean selected
static method taunted takes unit target returns boolean
return GetUnitAbilityLevel(target, TAUNT_BUFF) > 0
endmethod
method remove takes integer i returns integer
call UnitDispelCrowdControl(unit, CROWD_CONTROL_TAUNT)
call IssueImmediateOrder(unit, "stop")
call DestroyEffect(effect)
if selected and UnitAlive(unit) then
call SelectUnitAddForPlayer(unit, GetOwningPlayer(unit))
endif
set struct[id] = 0
set source[id] = null
set unit = null
set effect = null
set array[i] = array[key]
set key = key - 1
call deallocate()
if key == -1 then
call PauseTimer(timer)
endif
return i - 1
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > key
set this = array[i]
if GetUnitAbilityLevel(unit, TAUNT_BUFF) > 0 and UnitAlive(source[id]) and UnitAlive(unit) then
if IsUnitVisible(source[id], GetOwningPlayer(unit)) then
call IssueTargetOrderById(unit, 851983, source[id])
else
call IssuePointOrderById(unit, 851986, GetUnitX(source[id]), GetUnitY(source[id]))
endif
else
set i = remove(i)
endif
set i = i + 1
endloop
endmethod
static method apply takes unit source, unit target, real duration, string model, string point returns nothing
local integer id = GetUnitUserData(target)
local thistype this
if duration > 0 and UnitAlive(source) and UnitAlive(target) then
call BlzSetAbilityRealLevelField(ability, ABILITY_RLF_DURATION_NORMAL, 0, duration)
call BlzSetAbilityRealLevelField(ability, ABILITY_RLF_DURATION_HERO, 0, duration)
call IncUnitAbilityLevel(dummy, TAUNT)
call DecUnitAbilityLevel(dummy, TAUNT)
if IssueTargetOrder(dummy, "drunkenhaze", target) then
if struct[id] != 0 then
set this = struct[id]
else
set this = thistype.allocate()
set .id = id
set unit = target
set selected = IsUnitSelected(target, GetOwningPlayer(target))
set key = key + 1
set array[key] = this
set struct[id] = this
if selected then
call SelectUnit(target, false)
endif
if model != null and point != null then
set effect = AddSpecialEffectTarget(model, target, point)
endif
if key == 0 then
call TimerStart(timer, PERIOD, true, function thistype.onPeriod)
endif
endif
set .source[id] = source
if IsUnitVisible(source, GetOwningPlayer(target)) then
call IssueTargetOrderById(target, 851983, source)
else
call IssuePointOrderById(target, 851986, GetUnitX(source), GetUnitY(source))
endif
endif
endif
endmethod
private static method onOrder takes nothing returns nothing
local unit target = GetOrderedUnit()
local integer order = GetIssuedOrderId()
local integer id
if taunted(target) and order != 851973 then
set id = GetUnitUserData(target)
if order != 851983 and order != 851986 then
if IsUnitVisible(source[id], GetOwningPlayer(target)) then
call IssueTargetOrderById(target, 851983, source[id])
else
call IssuePointOrderById(target, 851986, GetUnitX(source[id]), GetUnitY(source[id]))
endif
else
if GetOrderTargetUnit() != source[id] and GetOrderTargetUnit() != null then
if IsUnitVisible(source[id], GetOwningPlayer(target)) then
call IssueTargetOrderById(target, 851983, source[id])
else
call IssuePointOrderById(target, 851986, GetUnitX(source[id]), GetUnitY(source[id]))
endif
endif
endif
endif
set target = null
endmethod
private static method onSelect takes nothing returns nothing
local unit target = GetTriggerUnit()
if taunted(target) then
if IsUnitSelected(target, GetOwningPlayer(target)) then
call SelectUnit(target, false)
endif
endif
set target = null
endmethod
private static method onInit takes nothing returns nothing
set dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetRectCenterX(GetWorldBounds()), GetRectCenterY(GetWorldBounds()), 0, 0)
call UnitAddAbility(dummy, TRUE_SIGHT)
call UnitAddAbility(dummy, TAUNT)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED, function thistype.onSelect)
set ability = BlzGetUnitAbility(dummy, TAUNT)
endmethod
endstruct
/* ---------------------------------------- Crowd Control --------------------------------------- */
struct CrowdControl extends array
private static trigger trigger = CreateTrigger()
private static hashtable timer = InitHashtable()
private static trigger array event
private static integer array ability
private static integer array buff
private static string array order
private static integer count = 0
private static unit dummy
readonly static integer key = -1
static unit array unit
static unit array source
static real array amount
static real array duration
static real array angle
static real array distance
static real array height
static string array model
static string array point
static boolean array stack
static boolean array cliff
static boolean array destructable
static boolean array agent
static integer array type
private static method onInit takes nothing returns nothing
set dummy = DummyRetrieve(Player(PLAYER_NEUTRAL_PASSIVE), GetRectCenterX(GetWorldBounds()), GetRectCenterY(GetWorldBounds()), 0, 0)
call UnitAddAbility(dummy, SILENCE)
call UnitAddAbility(dummy, STUN)
call UnitAddAbility(dummy, ATTACK_SLOW)
call UnitAddAbility(dummy, MOVEMENT_SLOW)
call UnitAddAbility(dummy, BANISH)
call UnitAddAbility(dummy, ENSNARE)
call UnitAddAbility(dummy, PURGE)
call UnitAddAbility(dummy, HEX)
call UnitAddAbility(dummy, SLEEP)
call UnitAddAbility(dummy, CYCLONE)
call UnitAddAbility(dummy, ENTANGLE)
call UnitAddAbility(dummy, DISARM)
call UnitAddAbility(dummy, TRUE_SIGHT)
call BlzUnitDisableAbility(dummy, SILENCE, true, true)
call BlzUnitDisableAbility(dummy, STUN, true, true)
call BlzUnitDisableAbility(dummy, ATTACK_SLOW, true, true)
call BlzUnitDisableAbility(dummy, MOVEMENT_SLOW, true, true)
call BlzUnitDisableAbility(dummy, BANISH, true, true)
call BlzUnitDisableAbility(dummy, ENSNARE, true, true)
call BlzUnitDisableAbility(dummy, PURGE, true, true)
call BlzUnitDisableAbility(dummy, HEX, true, true)
call BlzUnitDisableAbility(dummy, SLEEP, true, true)
call BlzUnitDisableAbility(dummy, CYCLONE, true, true)
call BlzUnitDisableAbility(dummy, ENTANGLE, true, true)
call BlzUnitDisableAbility(dummy, DISARM, true, true)
set ability[CROWD_CONTROL_SILENCE] = SILENCE
set ability[CROWD_CONTROL_STUN] = STUN
set ability[CROWD_CONTROL_SLOW] = MOVEMENT_SLOW
set ability[CROWD_CONTROL_SLOW_ATTACK] = ATTACK_SLOW
set ability[CROWD_CONTROL_BANISH] = BANISH
set ability[CROWD_CONTROL_ENSNARE] = ENSNARE
set ability[CROWD_CONTROL_PURGE] = PURGE
set ability[CROWD_CONTROL_HEX] = HEX
set ability[CROWD_CONTROL_SLEEP] = SLEEP
set ability[CROWD_CONTROL_CYCLONE] = CYCLONE
set ability[CROWD_CONTROL_ENTANGLE] = ENTANGLE
set ability[CROWD_CONTROL_DISARM] = DISARM
set ability[CROWD_CONTROL_FEAR] = FEAR
set ability[CROWD_CONTROL_TAUNT] = TAUNT
set buff[CROWD_CONTROL_SILENCE] = SILENCE_BUFF
set buff[CROWD_CONTROL_STUN] = STUN_BUFF
set buff[CROWD_CONTROL_SLOW] = MOVEMENT_SLOW_BUFF
set buff[CROWD_CONTROL_SLOW_ATTACK] = ATTACK_SLOW_BUFF
set buff[CROWD_CONTROL_BANISH] = BANISH_BUFF
set buff[CROWD_CONTROL_ENSNARE] = ENSNARE_BUFF
set buff[CROWD_CONTROL_PURGE] = PURGE_BUFF
set buff[CROWD_CONTROL_HEX] = HEX_BUFF
set buff[CROWD_CONTROL_SLEEP] = SLEEP_BUFF
set buff[CROWD_CONTROL_CYCLONE] = CYCLONE_BUFF
set buff[CROWD_CONTROL_ENTANGLE] = ENTANGLE_BUFF
set buff[CROWD_CONTROL_DISARM] = DISARM_BUFF
set buff[CROWD_CONTROL_FEAR] = FEAR_BUFF
set buff[CROWD_CONTROL_TAUNT] = TAUNT_BUFF
set order[CROWD_CONTROL_SILENCE] = "drunkenhaze"
set order[CROWD_CONTROL_STUN] = "thunderbolt"
set order[CROWD_CONTROL_SLOW] = "cripple"
set order[CROWD_CONTROL_SLOW_ATTACK] = "cripple"
set order[CROWD_CONTROL_BANISH] = "banish"
set order[CROWD_CONTROL_ENSNARE] = "ensnare"
set order[CROWD_CONTROL_PURGE] = "purge"
set order[CROWD_CONTROL_HEX] = "hex"
set order[CROWD_CONTROL_SLEEP] = "sleep"
set order[CROWD_CONTROL_CYCLONE] = "cyclone"
set order[CROWD_CONTROL_ENTANGLE] = "entanglingroots"
set order[CROWD_CONTROL_DISARM] = "drunkenhaze"
endmethod
private static method onExpire takes nothing returns nothing
local timer t = GetExpiredTimer()
call RemoveSavedHandle(timer, GetHandleId(LoadUnitHandle(timer, GetHandleId(t), 0)), LoadInteger(timer, GetHandleId(t), 1))
call FlushChildHashtable(timer, GetHandleId(t))
call DestroyTimer(t)
set t = null
endmethod
private static method onEvent takes integer key returns nothing
local integer i = 0
local integer next = -1
local integer prev = -2
set count = count + 1
if count - CROWD_CONTROL_KNOCKUP < RECURSION_LIMIT then
loop
exitwhen type[key] == next or (i - CROWD_CONTROL_KNOCKUP > RECURSION_LIMIT)
set next = type[key]
if event[next] != null then
call TriggerEvaluate(event[next])
endif
if type[key] != next then
set i = i + 1
else
if next != prev then
call TriggerEvaluate(trigger)
if type[key] != next then
set i = i + 1
set prev = next
endif
endif
endif
endloop
endif
set count = count - 1
set .key = key
endmethod
private static method cast takes unit source, unit target, real amount, real angle, real distance, real height, real duration, string model, string point, boolean stack, boolean onCliff, boolean onDestructable, boolean onUnit, integer id returns nothing
local ability spell
local timer t
if not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) and UnitAlive(target) and duration > 0 then
set key = key + 1
set .unit[key] = target
set .source[key] = source
set .amount[key] = amount
set .angle[key] = angle
set .distance[key] = distance
set .height[key] = height
set .duration[key] = duration
set .model[key] = model
set .point[key] = point
set .stack[key] = stack
set .cliff[key] = onCliff
set .destructable[key] = onDestructable
set .agent[key] = onUnit
set .type[key] = id
call onEvent(key)
static if LIBRARY_Tenacity then
set .duration[key] = GetTenacityDuration(unit[key], .duration[key])
endif
if .duration[key] > 0 and UnitAlive(unit[key]) then
if not HaveSavedHandle(timer, GetHandleId(unit[key]), type[key]) then
set t = CreateTimer()
call SaveTimerHandle(timer, GetHandleId(unit[key]), type[key], t)
call SaveUnitHandle(timer, GetHandleId(t), 0, unit[key])
call SaveInteger(timer, GetHandleId(t), 1, type[key])
endif
if .stack[key] then
if type[key] != CROWD_CONTROL_TAUNT then
set .duration[key] = .duration[key] + TimerGetRemaining(LoadTimerHandle(timer, GetHandleId(unit[key]), type[key]))
else
if Taunt.source[GetUnitUserData(unit[key])] == .source[key] then
set .duration[key] = .duration[key] + TimerGetRemaining(LoadTimerHandle(timer, GetHandleId(unit[key]), type[key]))
endif
endif
endif
if type[key] != CROWD_CONTROL_FEAR and type[key] != CROWD_CONTROL_TAUNT and type[key] != CROWD_CONTROL_KNOCKBACK and type[key] != CROWD_CONTROL_KNOCKUP then
set spell = BlzGetUnitAbility(dummy, ability[type[key]])
call BlzUnitDisableAbility(dummy, ability[type[key]], false, false)
call BlzSetAbilityRealLevelField(spell, ABILITY_RLF_DURATION_NORMAL, 0, .duration[key])
call BlzSetAbilityRealLevelField(spell, ABILITY_RLF_DURATION_HERO, 0, .duration[key])
if type[key] == CROWD_CONTROL_SLOW then
call BlzSetAbilityRealLevelField(spell, ABILITY_RLF_MOVEMENT_SPEED_REDUCTION_PERCENT_CRI1, 0, .amount[key])
elseif type[key] == CROWD_CONTROL_SLOW_ATTACK then
call BlzSetAbilityRealLevelField(spell, ABILITY_RLF_ATTACK_SPEED_REDUCTION_PERCENT_CRI2, 0, .amount[key])
endif
call IncUnitAbilityLevel(dummy, ability[type[key]])
call DecUnitAbilityLevel(dummy, ability[type[key]])
if IssueTargetOrder(dummy, order[type[key]], unit[key]) then
call UnitRemoveAbility(unit[key], buff[type[key]])
call IssueTargetOrder(dummy, order[type[key]], unit[key])
call TimerStart(LoadTimerHandle(timer, GetHandleId(unit[key]), type[key]), .duration[key], false, function thistype.onExpire)
if .model[key] != null and .model[key] != "" then
if .point[key] != null and .point[key] != "" then
call LinkEffectToBuff(unit[key], buff[type[key]], .model[key], .point[key])
else
call DestroyEffect(AddSpecialEffect(.model[key], GetUnitX(unit[key]), GetUnitY(unit[key])))
endif
endif
else
call RemoveSavedHandle(timer, GetHandleId(unit[key]), type[key])
call FlushChildHashtable(timer, GetHandleId(t))
call DestroyTimer(t)
endif
call BlzUnitDisableAbility(dummy, ability[type[key]], true, true)
else
if type[key] == CROWD_CONTROL_FEAR then
call Fear.apply(unit[key], .duration[key], .model[key], .point[key])
elseif type[key] == CROWD_CONTROL_TAUNT then
call Taunt.apply(.source[key], unit[key], .duration[key], .model[key], .point[key])
elseif type[key] == CROWD_CONTROL_KNOCKBACK then
call Knockback.apply(unit[key], .angle[key], .distance[key], .duration[key], .model[key], .point[key], .cliff[key], .destructable[key], .agent[key])
elseif type[key] == CROWD_CONTROL_KNOCKUP then
call Knockup.apply(unit[key], .duration[key], .height[key], .model[key], .point[key])
endif
call TimerStart(LoadTimerHandle(timer, GetHandleId(unit[key]), type[key]), .duration[key], false, function thistype.onExpire)
endif
endif
if key > -1 then
set key = key - 1
endif
endif
set t = null
set spell = null
endmethod
static method silence takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_SILENCE)
endmethod
static method silenced takes unit target returns boolean
return GetUnitAbilityLevel(target, SILENCE_BUFF) > 0
endmethod
static method stun takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_STUN)
endmethod
static method stunned takes unit target returns boolean
return GetUnitAbilityLevel(target, STUN_BUFF) > 0
endmethod
static method slow takes unit target, real amount, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, amount, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_SLOW)
endmethod
static method slowed takes unit target returns boolean
return GetUnitAbilityLevel(target, MOVEMENT_SLOW_BUFF) > 0
endmethod
static method slowAttack takes unit target, real amount, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, amount, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_SLOW_ATTACK)
endmethod
static method attackSlowed takes unit target returns boolean
return GetUnitAbilityLevel(target, ATTACK_SLOW_BUFF) > 0
endmethod
static method banish takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_BANISH)
endmethod
static method banished takes unit target returns boolean
return GetUnitAbilityLevel(target, BANISH_BUFF) > 0
endmethod
static method ensnare takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_ENSNARE)
endmethod
static method ensnared takes unit target returns boolean
return GetUnitAbilityLevel(target, ENSNARE_BUFF) > 0
endmethod
static method purge takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_PURGE)
endmethod
static method purged takes unit target returns boolean
return GetUnitAbilityLevel(target, PURGE_BUFF) > 0
endmethod
static method hex takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_HEX)
endmethod
static method hexed takes unit target returns boolean
return GetUnitAbilityLevel(target, HEX_BUFF) > 0
endmethod
static method sleep takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_SLEEP)
endmethod
static method sleeping takes unit target returns boolean
return GetUnitAbilityLevel(target, SLEEP_BUFF) > 0
endmethod
static method cyclone takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_CYCLONE)
endmethod
static method cycloned takes unit target returns boolean
return GetUnitAbilityLevel(target, CYCLONE_BUFF) > 0
endmethod
static method entangle takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_ENTANGLE)
endmethod
static method entangled takes unit target returns boolean
return GetUnitAbilityLevel(target, ENTANGLE_BUFF) > 0
endmethod
static method knockback takes unit target, real angle, real distance, real duration, string model, string point, boolean onCliff, boolean onDestructable, boolean onUnit, boolean stack returns nothing
call cast(null, target, 0, angle, distance, 0, duration, model, point, stack, onCliff, onDestructable, onUnit, CROWD_CONTROL_KNOCKBACK)
endmethod
static method knockedback takes unit target returns boolean
return Knockback.knocked(target)
endmethod
static method knockup takes unit target, real maxHeight, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, maxHeight, duration, model, point, stack, false, false, false, CROWD_CONTROL_KNOCKUP)
endmethod
static method knockedup takes unit target returns boolean
return Knockup.isUnitKnocked(target)
endmethod
static method fear takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_FEAR)
endmethod
static method feared takes unit target returns boolean
return Fear.feared(target)
endmethod
static method disarm takes unit target, real duration, string model, string point, boolean stack returns nothing
call cast(null, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_DISARM)
endmethod
static method disarmed takes unit target returns boolean
return GetUnitAbilityLevel(target, DISARM_BUFF) > 0
endmethod
static method taunt takes unit source, unit target, real duration, string model, string point, boolean stack returns nothing
call cast(source, target, 0, 0, 0, 0, duration, model, point, stack, false, false, false, CROWD_CONTROL_TAUNT)
endmethod
static method taunted takes unit target returns boolean
return Taunt.taunted(target)
endmethod
static method dispel takes unit target, integer id returns nothing
local timer t
if buff[id] != 0 then
call UnitRemoveAbility(target, buff[id])
if HaveSavedHandle(timer, GetHandleId(target), id) then
set t = LoadTimerHandle(timer, GetHandleId(target), id)
call RemoveSavedHandle(timer, GetHandleId(target), id)
call FlushChildHashtable(timer, GetHandleId(t))
call DestroyTimer(t)
endif
endif
set t = null
endmethod
static method dispelAll takes unit target returns nothing
call dispel(target, CROWD_CONTROL_SILENCE)
call dispel(target, CROWD_CONTROL_STUN)
call dispel(target, CROWD_CONTROL_SLOW)
call dispel(target, CROWD_CONTROL_SLOW_ATTACK)
call dispel(target, CROWD_CONTROL_BANISH)
call dispel(target, CROWD_CONTROL_ENSNARE)
call dispel(target, CROWD_CONTROL_PURGE)
call dispel(target, CROWD_CONTROL_HEX)
call dispel(target, CROWD_CONTROL_SLEEP)
call dispel(target, CROWD_CONTROL_CYCLONE)
call dispel(target, CROWD_CONTROL_ENTANGLE)
call dispel(target, CROWD_CONTROL_DISARM)
call dispel(target, CROWD_CONTROL_FEAR)
call dispel(target, CROWD_CONTROL_TAUNT)
endmethod
static method remaining takes unit target, integer id returns real
return TimerGetRemaining(LoadTimerHandle(timer, GetHandleId(target), id))
endmethod
static method register takes integer id, code c returns nothing
if id >= CROWD_CONTROL_SILENCE and id <= CROWD_CONTROL_KNOCKUP then
if event[id] == null then
set event[id] = CreateTrigger()
endif
call TriggerAddCondition(event[id], Filter(c))
else
call TriggerAddCondition(trigger, Filter(c))
endif
endmethod
endstruct
endlibrary
library DamageInterface requires optional Table
/* --------------------- DamageInterface v2.4 by Chopinski --------------------- */
// Allows for easy registration of specific damage type events like on attack
// damage or on spell damage, etc...
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// This constant is used to define if the system will cache
// extra information from a Damage Event, like the unit
// Custom value (UnitUserData), a unit Handle Id, and more
// Additionaly you can see the CacheResponse method below
// to have an idea and comment the members you want cached or not
private constant boolean CACHE_EXTRA = true
// Since Table can be a bit slow due to using only one hastable
// for everything, you can choose to use it or not with this
// system in particular.
private constant boolean USE_TABLE = false
endglobals
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
struct Unit
unit unit
player player
integer handle
boolean isHero
boolean isMelee
boolean isRanged
boolean isStructure
boolean isMagicImmune
integer id
real x
real y
real z
static method create takes nothing returns thistype
return thistype.allocate()
endmethod
endstruct
struct Damage extends array
static if LIBRARY_Table and USE_TABLE then
private static HashTable after
private static HashTable before
else
private static hashtable after = InitHashtable()
private static hashtable before = InitHashtable()
endif
static trigger damaged = CreateTrigger()
static trigger damaging = CreateTrigger()
readonly static location location = Location(0, 0)
readonly static damagetype damagetype
readonly static attacktype attacktype
readonly static Unit source
readonly static Unit target
readonly static boolean isSpell
readonly static boolean isAttack
readonly static boolean isEnemy
readonly static boolean isAlly
private static method GetUnitZ takes unit u returns real
call MoveLocation(location, GetUnitX(u), GetUnitY(u))
return GetUnitFlyHeight(u) + GetLocationZ(location)
endmethod
private static method cache takes unit src, unit tgt, damagetype dmg_type, attacktype atk_type returns nothing
set damagetype = dmg_type
set attacktype = atk_type
set source.unit = src
set target.unit = tgt
set isAttack = damagetype == DAMAGE_TYPE_NORMAL
set isSpell = attacktype == ATTACK_TYPE_NORMAL
// You can comment the members you dont want to be cached
// or set CACHE_EXTRA = false to not save them at all
if CACHE_EXTRA then
set source.player = GetOwningPlayer(src)
set target.player = GetOwningPlayer(tgt)
set isEnemy = IsUnitEnemy(tgt, source.player)
set isAlly = IsUnitAlly(tgt, source.player)
set source.isMelee = IsUnitType(src, UNIT_TYPE_MELEE_ATTACKER)
set source.isRanged = IsUnitType(src, UNIT_TYPE_RANGED_ATTACKER)
set target.isMelee = IsUnitType(tgt, UNIT_TYPE_MELEE_ATTACKER)
set target.isRanged = IsUnitType(tgt, UNIT_TYPE_RANGED_ATTACKER)
set source.isHero = IsUnitType(src, UNIT_TYPE_HERO)
set target.isHero = IsUnitType(tgt, UNIT_TYPE_HERO)
set source.isStructure = IsUnitType(src, UNIT_TYPE_STRUCTURE)
set target.isStructure = IsUnitType(tgt, UNIT_TYPE_STRUCTURE)
set source.isMagicImmune = IsUnitType(src, UNIT_TYPE_MAGIC_IMMUNE)
set target.isMagicImmune = IsUnitType(tgt, UNIT_TYPE_MAGIC_IMMUNE)
set source.x = GetUnitX(src)
set source.y = GetUnitY(src)
set source.z = GetUnitZ(src)
set target.x = GetUnitX(tgt)
set target.y = GetUnitY(tgt)
set target.z = GetUnitZ(tgt)
set source.id = GetUnitUserData(src)
set target.id = GetUnitUserData(tgt)
set source.handle = GetHandleId(src)
set target.handle = GetHandleId(tgt)
endif
endmethod
private static method onDamaging takes nothing returns nothing
local integer i
local integer j
call cache(GetEventDamageSource(), BlzGetEventDamageTarget(), BlzGetEventDamageType(), BlzGetEventAttackType())
if damagetype != DAMAGE_TYPE_UNKNOWN then
set i = GetHandleId(attacktype)
set j = GetHandleId(damagetype)
static if LIBRARY_Table and USE_TABLE then
if before[i].trigger[0] != null then
call TriggerEvaluate(before[i].trigger[0])
endif
if before[0].trigger[j] != null then
call TriggerEvaluate(before[0].trigger[j])
endif
if before[i].trigger[j] != null then
call TriggerEvaluate(before[i].trigger[j])
endif
else
if HaveSavedHandle(before, i, 0) then
call TriggerEvaluate(LoadTriggerHandle(before, i, 0))
endif
if HaveSavedHandle(before, 0, j) then
call TriggerEvaluate(LoadTriggerHandle(before, 0, j))
endif
if HaveSavedHandle(before, i, j) then
call TriggerEvaluate(LoadTriggerHandle(before, i, j))
endif
endif
endif
endmethod
private static method onDamage takes nothing returns nothing
local integer i
local integer j
call cache(GetEventDamageSource(), BlzGetEventDamageTarget(), BlzGetEventDamageType(), BlzGetEventAttackType())
if damagetype != DAMAGE_TYPE_UNKNOWN then
set i = GetHandleId(attacktype)
set j = GetHandleId(damagetype)
static if LIBRARY_Table and USE_TABLE then
if after[i].trigger[0] != null then
call TriggerEvaluate(after[i].trigger[0])
endif
if after[0].trigger[j] != null then
static if LIBRARY_Evasion then
if isAttack then
if not Evasion.evade then
call TriggerEvaluate(after[0].trigger[j])
endif
else
call TriggerEvaluate(after[0].trigger[j])
endif
else
call TriggerEvaluate(after[0].trigger[j])
endif
endif
if after[i].trigger[j] != null then
call TriggerEvaluate(after[i].trigger[j])
endif
else
if HaveSavedHandle(after, i, 0) then
call TriggerEvaluate(LoadTriggerHandle(after, i, 0))
endif
if HaveSavedHandle(after, 0, j) then
static if LIBRARY_Evasion then
if isAttack then
if not Evasion.evade then
call TriggerEvaluate(LoadTriggerHandle(after, 0, j))
endif
else
call TriggerEvaluate(LoadTriggerHandle(after, 0, j))
endif
else
call TriggerEvaluate(LoadTriggerHandle(after, 0, j))
endif
endif
if HaveSavedHandle(after, i, j) then
call TriggerEvaluate(LoadTriggerHandle(after, i, j))
endif
endif
endif
endmethod
static method register takes attacktype attack, damagetype damage, code c, boolean onDamaged returns nothing
local integer i = GetHandleId(attack)
local integer j = GetHandleId(damage)
if onDamaged then
static if LIBRARY_Table and USE_TABLE then
if after[i].trigger[j] == null then
set after[i].trigger[j] = CreateTrigger()
endif
call TriggerAddCondition(after[i].trigger[j], Filter(c))
else
if not HaveSavedHandle(after, i, j) then
call SaveTriggerHandle(after, i, j, CreateTrigger())
endif
call TriggerAddCondition(LoadTriggerHandle(after, i, j), Filter(c))
endif
else
static if LIBRARY_Table and USE_TABLE then
if before[i].trigger[j] == null then
set before[i].trigger[j] = CreateTrigger()
endif
call TriggerAddCondition(before[i].trigger[j], Filter(c))
else
if not HaveSavedHandle(before, i, j) then
call SaveTriggerHandle(before, i, j, CreateTrigger())
endif
call TriggerAddCondition(LoadTriggerHandle(before, i, j), Filter(c))
endif
endif
endmethod
static method onInit takes nothing returns nothing
static if LIBRARY_Table and USE_TABLE then
set after = HashTable.create()
set before = HashTable.create()
endif
set source = Unit.create()
set target = Unit.create()
call TriggerRegisterAnyUnitEventBJ(damaged, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(damaged, Condition(function thistype.onDamage))
call TriggerRegisterAnyUnitEventBJ(damaging, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(damaging, Condition(function thistype.onDamaging))
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function RegisterAttackDamageEvent takes code c returns nothing
call Damage.register(null, DAMAGE_TYPE_NORMAL, c, true)
endfunction
function RegisterSpellDamageEvent takes code c returns nothing
call Damage.register(ATTACK_TYPE_NORMAL, null, c, true)
endfunction
function RegisterDamageEvent takes attacktype attack, damagetype damage, code c returns nothing
call Damage.register(attack, damage, c, true)
endfunction
function RegisterAnyDamageEvent takes code c returns nothing
call TriggerAddCondition(Damage.damaged, Filter(c))
endfunction
function RegisterAttackDamagingEvent takes code c returns nothing
call Damage.register(null, DAMAGE_TYPE_NORMAL, c, false)
endfunction
function RegisterSpellDamagingEvent takes code c returns nothing
call Damage.register(ATTACK_TYPE_NORMAL, null, c, false)
endfunction
function RegisterDamagingEvent takes attacktype attack, damagetype damage, code c returns nothing
call Damage.register(attack, damage, c, false)
endfunction
function RegisterAnyDamagingEvent takes code c returns nothing
call TriggerAddCondition(Damage.damaging, Filter(c))
endfunction
endlibrary
library Evasion requires DamageInterface
/* ------------------------ Evasion v2.4 by Chopinski ----------------------- */
// Evasion implements an easy way to register and detect a custom evasion event.
// It works by monitoring custom evasion and missing values given to units,
// and nulling damage when the odds given occurs.
// It will only detect custom evasion, so all evasion or miss values given to a
// unit must be done so using the public API provided by this system.
// *Evasion requires DamageInterface. Do not use TriggerSleepAction() with Evasion.
// The API:
// function RegisterEvasionEvent(function YourFunction)
// -> YourFunction will run when a unit evades an attack.
// function GetMissingUnit takes nothing returns unit
// -> Returns the unit missing the attack
// function GetEvadingUnit takes nothing returns unit
// -> Returns the unit evading the attack
// function GetEvadedDamage takes nothing returns real
// -> Returns the amount of evaded damage
// function GetUnitEvasionChance takes unit u returns real
// -> Returns this system amount of evasion chance given to a unit
// function GetUnitMissChance takes unit u returns real
// -> Returns this system amount of miss chance given to a unit
// function SetUnitEvasionChance takes unit u, real chance returns nothing
// -> Sets unit evasion chance to specified amount
// function SetUnitMissChance takes unit u, real chance returns nothing
// -> Sets unit miss chance to specified amount
// function UnitAddEvasionChance takes unit u, real chance returns nothing
// -> Add to a unit Evasion chance the specified amount
// function UnitAddMissChance takes unit u, real chance returns nothing
// -> Add to a unit Miss chance the specified amount
// function MakeUnitNeverMiss takes unit u, boolean flag returns nothing
// -> Will make a unit never miss attacks no matter the evasion chance of the attacked unit
// function DoUnitNeverMiss takes unit u returns boolean
// -> Returns true if the unit will never miss an attack
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
struct Evasion
static Unit source
static Unit target
static real damage
static real array evasion
static real array miss
static integer array neverMiss
readonly static boolean evade = false
readonly static trigger trigger = CreateTrigger()
static constant real TEXT_SIZE = 0.016
static method getEvasionChance takes unit u returns real
return evasion[GetUnitUserData(u)]
endmethod
static method getMissChance takes unit u returns real
return miss[GetUnitUserData(u)]
endmethod
static method setEvasionChance takes unit u, real value returns nothing
set evasion[GetUnitUserData(u)] = value
endmethod
static method setMissChance takes unit u, real value returns nothing
set miss[GetUnitUserData(u)] = value
endmethod
static method text takes unit whichUnit, string text, real duration, integer red, integer green, integer blue, integer alpha returns nothing
local texttag tx = CreateTextTag()
call SetTextTagText(tx, text, TEXT_SIZE)
call SetTextTagPosUnit(tx, whichUnit, 0)
call SetTextTagColor(tx, red, green, blue, alpha)
call SetTextTagLifespan(tx, duration)
call SetTextTagVelocity(tx, 0.0, 0.0355)
call SetTextTagPermanent(tx, false)
set tx = null
endmethod
static method onDamage takes nothing returns nothing
local real amount = GetEventDamage()
set evade = false
if amount > 0 and not (neverMiss[Damage.source.id] > 0) then
set evade = GetRandomReal(0, 100) <= evasion[Damage.target.id] or GetRandomReal(0, 100) <= miss[Damage.source.id]
if evade then
set source = Damage.source
set target = Damage.target
set damage = amount
call TriggerEvaluate(trigger)
call BlzSetEventDamage(0)
call BlzSetEventWeaponType(WEAPON_TYPE_WHOKNOWS)
call text(source.unit, "miss", 1.5, 255, 0, 0, 255)
set damage = 0
set source = 0
set target = 0
endif
endif
endmethod
static method register takes code c returns nothing
call TriggerAddCondition(trigger, Filter(c))
endmethod
static method onInit takes nothing returns nothing
call RegisterAttackDamagingEvent(function thistype.onDamage)
endmethod
endstruct
//endregion
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function RegisterEvasionEvent takes code c returns nothing
call Evasion.register(c)
endfunction
function GetMissingUnit takes nothing returns unit
return Evasion.source.unit
endfunction
function GetEvadingUnit takes nothing returns unit
return Evasion.target.unit
endfunction
function GetEvadedDamage takes nothing returns real
return Evasion.damage
endfunction
function GetUnitEvasionChance takes unit u returns real
return Evasion.getEvasionChance(u)
endfunction
function GetUnitMissChance takes unit u returns real
return Evasion.getMissChance(u)
endfunction
function SetUnitEvasionChance takes unit u, real chance returns nothing
call Evasion.setEvasionChance(u, chance)
endfunction
function SetUnitMissChance takes unit u, real chance returns nothing
call Evasion.setMissChance(u, chance)
endfunction
function UnitAddEvasionChance takes unit u, real chance returns nothing
call Evasion.setEvasionChance(u, Evasion.getEvasionChance(u) + chance)
endfunction
function UnitAddMissChance takes unit u, real chance returns nothing
call Evasion.setMissChance(u, Evasion.getMissChance(u) + chance)
endfunction
function MakeUnitNeverMiss takes unit u, boolean flag returns nothing
if flag then
set Evasion.neverMiss[GetUnitUserData(u)] = Evasion.neverMiss[GetUnitUserData(u)] + 1
else
set Evasion.neverMiss[GetUnitUserData(u)] = Evasion.neverMiss[GetUnitUserData(u)] - 1
endif
endfunction
function DoUnitNeverMiss takes unit u returns boolean
return Evasion.neverMiss[GetUnitUserData(u)] > 0
endfunction
endlibrary
library CriticalStrike requires DamageInterface optional Evasion
/* ------------------------ CriticalStrike v2.4 by Chopinski ----------------------- */
// CriticalStrike implements an easy way to register and detect a custom critical event.
// allows the manipulation of a unit critical strike chance and multiplier, as well as
// manipulating the critical damage dealt.
// It works by monitoring custom critical strike chance and multiplier values given to units.
// It will only detect custom critical strikes, so all critical chance given to a
// unit must be done so using the public API provided by this system.
// *CriticalStrike requires DamageInterface. Do not use TriggerSleepAction() with Evasion.
// It also requires optional Evasion so that this library is written after the Evasion
// library, so both custom events will not fire at the same time.
// The API:
// function RegisterCriticalStrikeEvent(function YourFunction)
// -> YourFunction will run when a unit hits a critical strike.
// function GetCriticalSource takes nothing returns unit
// -> Returns the unit hitting a critical strike.
// function GetCriticalTarget takes nothing returns unit
// -> Returns the unit being hit by a critical strike.
// function GetCriticalDamage takes nothing returns real
// -> Returns the critical strike damage amount.
// function GetUnitCriticalChance takes unit u returns real
// -> Returns the chance to hit a critical strike to specified unit.
// function GetUnitCriticalMultiplier takes unit u returns real
// -> Returns the chance to hit a critical strike to specified unit.
// function SetUnitCriticalChance takes unit u, real value returns nothing
// -> Set's the unit chance to hit a critical strike to specified value.
// -> 15.0 = 15%
// function SetUnitCriticalMultiplier takes unit u, real value returns nothing
// -> Set's the unit multiplier of damage when hitting a critical to value
// -> 1.0 = increases the multiplier by 1. all units have a multiplier of 1.0
// by default, so by adding 1.0, for example, the critical damage will be
// 2x the normal damage
// function SetCriticalEventDamage takes real newValue returns nothing
// -> Modify the critical damage dealt to the specified value.
// function UnitAddCriticalStrike takes unit u, real chance, real multiplier returns nothing
// -> Adds the specified values of chance and multiplier to a unit
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
struct Critical
static constant real TEXT_SIZE = 0.016
readonly static trigger trigger = CreateTrigger()
static Unit source
static Unit target
static real damage
static real array chance
static real array multiplier
static method getChance takes unit u returns real
return chance[GetUnitUserData(u)]
endmethod
static method getMultiplier takes unit u returns real
return multiplier[GetUnitUserData(u)]
endmethod
static method setChance takes unit u, real value returns nothing
set chance[GetUnitUserData(u)] = value
endmethod
static method setMultiplier takes unit u, real value returns nothing
set multiplier[GetUnitUserData(u)] = value
endmethod
static method add takes unit u, real chance, real multuplier returns nothing
call setChance(u, getChance(u) + chance)
call setMultiplier(u, getMultiplier(u) + multuplier)
endmethod
static method text takes unit whichUnit, string text, real duration, integer red, integer green, integer blue, integer alpha returns nothing
local texttag tx = CreateTextTag()
call SetTextTagText(tx, text, TEXT_SIZE)
call SetTextTagPosUnit(tx, whichUnit, 0)
call SetTextTagColor(tx, red, green, blue, alpha)
call SetTextTagLifespan(tx, duration)
call SetTextTagVelocity(tx, 0.0, 0.0355)
call SetTextTagPermanent(tx, false)
set tx = null
endmethod
static method onDamage takes nothing returns nothing
local real amount = GetEventDamage()
if amount > 0 and GetRandomReal(0, 100) <= chance[Damage.source.id] and Damage.isEnemy and not Damage.target.isStructure and multiplier[Damage.source.id] > 0 then
set source = Damage.source
set target = Damage.target
set damage = amount*(1 + multiplier[Damage.source.id])
call TriggerEvaluate(trigger)
call BlzSetEventDamage(damage)
if damage > 0 then
call text(target.unit, (I2S(R2I(damage)) + "!"), 1.5, 255, 0, 0, 255)
endif
set damage = 0
set source = 0
set target = 0
endif
endmethod
static method register takes code c returns nothing
call TriggerAddCondition(trigger, Filter(c))
endmethod
static method onInit takes nothing returns nothing
call RegisterAttackDamageEvent(function thistype.onDamage)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function RegisterCriticalStrikeEvent takes code c returns nothing
call Critical.register(c)
endfunction
function GetCriticalSource takes nothing returns unit
return Critical.source.unit
endfunction
function GetCriticalTarget takes nothing returns unit
return Critical.target.unit
endfunction
function GetCriticalDamage takes nothing returns real
return Critical.damage
endfunction
function GetUnitCriticalChance takes unit u returns real
return Critical.getChance(u)
endfunction
function GetUnitCriticalMultiplier takes unit u returns real
return Critical.getMultiplier(u)
endfunction
function SetUnitCriticalChance takes unit u, real value returns nothing
call Critical.setChance(u, value)
endfunction
function SetUnitCriticalMultiplier takes unit u, real value returns nothing
call Critical.setMultiplier(u, value)
endfunction
function SetCriticalEventDamage takes real newValue returns nothing
set Critical.damage = newValue
endfunction
function UnitAddCriticalStrike takes unit u, real chance, real multiplier returns nothing
call Critical.add(u, chance, multiplier)
endfunction
endlibrary
library SpellPower requires DamageInterface
/* ------------------------ SpellPower v2.4 by Chopinski ----------------------- */
// SpellPower intends to simulate a system similiar to Ability Power from LoL or
// Spell Amplification from Dota 2.
// Whenever a units deals Spell damage, that dealt damage will be amplified by a flat
// and percentile amount that represents a unit spell power bonus.
// The formula for amplification is:
// final damage = (initial damage + flat bonus) * (1 + percent bonus)
// for percent bonus: 0.1 = 10% bonus
// *SpellPower requires DamageInterface. Do not use TriggerSleepAction() within triggers.
// The API:
// function GetUnitSpellPowerFlat takes unit u returns real
// -> Returns the Flat bonus of spell power of a unit
// function GetUnitSpellPowerPercent takes unit u returns real
// -> Returns the Percent bonus of spell power of a unit
// function SetUnitSpellPowerFlat takes unit u, real value returns nothing
// -> Set's the Flat amount of Spell Power of a unit
// function SetUnitSpellPowerPercent takes unit u, real value returns nothing
// -> Set's the Flat amount of Spell Power of a unit
// function UnitAddSpellPowerFlat takes unit u, real amount returns nothing
// -> Add to the Flat amount of Spell Power of a unit
// function UnitAddSpellPowerPercent takes unit u, real amount returns nothing
// -> Add to the Percent amount of Spell Power of a unit
// function GetSpellDamage takes real amount, unit u returns real
// -> Returns the amount of spell damage that would be dealt given an initial damage
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
struct SpellPower
static real array flat
static real array percent
static method getFlat takes unit u returns real
return flat[GetUnitUserData(u)]
endmethod
static method getPercent takes unit u returns real
return percent[GetUnitUserData(u)]
endmethod
static method setFlat takes unit u, real value returns nothing
set flat[GetUnitUserData(u)] = value
endmethod
static method setPercent takes unit u, real value returns nothing
set percent[GetUnitUserData(u)] = value
endmethod
static method onDamage takes nothing returns nothing
local real damage = GetEventDamage()
if damage > 0 then
call BlzSetEventDamage((damage + flat[Damage.source.id])*(1 + percent[Damage.source.id]))
endif
endmethod
static method onInit takes nothing returns nothing
call RegisterSpellDamageEvent(function thistype.onDamage)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function GetUnitSpellPowerFlat takes unit u returns real
return SpellPower.getFlat(u)
endfunction
function GetUnitSpellPowerPercent takes unit u returns real
return SpellPower.getPercent(u)
endfunction
function SetUnitSpellPowerFlat takes unit u, real value returns nothing
call SpellPower.setFlat(u, value)
endfunction
function SetUnitSpellPowerPercent takes unit u, real value returns nothing
call SpellPower.setPercent(u, value)
endfunction
function UnitAddSpellPowerFlat takes unit u, real amount returns nothing
call SpellPower.setFlat(u, SpellPower.getFlat(u) + amount)
endfunction
function UnitAddSpellPowerPercent takes unit u, real amount returns nothing
call SpellPower.setPercent(u, SpellPower.getPercent(u) + amount)
endfunction
function GetSpellDamage takes real amount, unit u returns real
return ((amount + SpellPower.getFlat(u))*(1 + SpellPower.getPercent(u)))
endfunction
endlibrary
library LifeSteal requires DamageInterface
/* ------------------------ LifeSteal v2.4 by Chopinski ----------------------- */
// LifeSteal intends to simulate the Life Steal system in warcraft, and allow you
// to easily change the life steal amount of any unit.
// Whenever a unit deals Physical damage, and it has a value of life steal given by
// this system, it will heal based of this value and the damage amount.
// The formula for life steal is:
// heal = damage * life steal
// fror life steal: 0.1 = 10%
// *LifeSteal requires DamageInterface. Do not use TriggerSleepAction() within triggers.
// The API:
// function SetUnitLifeSteal takes unit u, real amount returns nothing
// -> Set the Life Steal amount for a unit
// function GetUnitLifeSteal takes unit u returns real
// -> Returns the Life Steal amount of a unit
// function UnitAddLifeSteal takes unit u, real amount returns nothing
// -> Add to the Life Steal amount of a unit the given amount
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
struct LifeSteal
static string effect = "Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl"
static real array amount
static method Get takes unit u returns real
return amount[GetUnitUserData(u)]
endmethod
static method Set takes unit u, real value returns nothing
set amount[GetUnitUserData(u)] = value
endmethod
static method onDamage takes nothing returns nothing
local real damage = GetEventDamage()
if damage > 0 and amount[Damage.source.id] > 0 and not Damage.target.isStructure then
call SetWidgetLife(Damage.source.unit, (GetWidgetLife(Damage.source.unit) + (damage * amount[Damage.source.id])))
call DestroyEffect(AddSpecialEffectTarget(effect, Damage.source.unit, "origin"))
endif
endmethod
static method onInit takes nothing returns nothing
call RegisterAttackDamageEvent(function thistype.onDamage)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function SetUnitLifeSteal takes unit u, real amount returns nothing
call LifeSteal.Set(u, amount)
endfunction
function GetUnitLifeSteal takes unit u returns real
return LifeSteal.Get(u)
endfunction
function UnitAddLifeSteal takes unit u, real amount returns nothing
call LifeSteal.Set(u, LifeSteal.Get(u) + amount)
endfunction
endlibrary
library SpellVamp requires DamageInterface
/* ------------------------ SpellVamp v2.4 by Chopinski ----------------------- */
// SpellVamp intends to introduce to warcraft a healing based on Spell damage, like
// in LoL or Dota 2.
// Whenever a unit deals Spell damage, and it has a value of spell vamp given by
// this system, it will heal based of this value and the damage amount.
// The formula for spell vamp is:
// heal = damage * lspell vamp
// fror spell vamp: 0.1 = 10%
// *SpellVamp requires DamageInterface. Do not use TriggerSleepAction() within triggers.
// The API:
// function SetUnitSpellVamp takes unit u, real amount returns nothing
// -> Set the Spell Vamp amount for a unit
// function GetUnitSpellVamp takes unit u returns real
// -> Returns the Spell Vamp amount of a unit
// function UnitAddSpellVamp takes unit u, real amount returns nothing
// -> Add to the Spell Vamp amount of a unit the given amount
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
struct SpellVamp
static real array amount
static method Get takes unit u returns real
return amount[GetUnitUserData(u)]
endmethod
static method Set takes unit u, real value returns nothing
set amount[GetUnitUserData(u)] = value
endmethod
static method onDamage takes nothing returns nothing
local real damage = GetEventDamage()
if damage > 0 and amount[Damage.source.id] > 0 and not Damage.target.isStructure then
call SetWidgetLife(Damage.source.unit, (GetWidgetLife(Damage.source.unit) + (damage * amount[Damage.source.id])))
endif
endmethod
static method onInit takes nothing returns nothing
call RegisterSpellDamageEvent(function thistype.onDamage)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function SetUnitSpellVamp takes unit u, real amount returns nothing
call SpellVamp.Set(u, amount)
endfunction
function GetUnitSpellVamp takes unit u returns real
return SpellVamp.Get(u)
endfunction
function UnitAddSpellVamp takes unit u, real amount returns nothing
call SpellVamp.Set(u, SpellVamp.Get(u) + amount)
endfunction
endlibrary
library DamageInterfaceUtils requires Evasion, CriticalStrike, LifeSteal, SpellPower, SpellVamp
/* ------- Utility Library for all the Damage Interface Custom Events ------- */
/* ---------------------------- v2.4 by Chopinski --------------------------- */
// JASS API:
// Evasion System:
// function UnitAddEvasionChanceTimed takes unit u, real amount, real duration returns nothing
// -> Add to a unit Evasion chance the specified amount for a given period
// function UnitAddMissChanceTimed takes unit u, real amount, real duration returns nothing
// -> Add to a unit Miss chance the specified amount for a given period
// Critical Strike System:
// function UnitAddCriticalStrikeTimed takes unit u, real chance, real multiplier, real duration returns nothing
// -> Adds the specified values of chance and multiplier to a unit for a given period
// function UnitAddCriticalChanceTimed takes unit u, real chance, real duration returns nothing
// -> Adds the specified values of critical chance to a unit for a given period
// function UnitAddCriticalMultiplierTimed takes unit u, real multiplier, real duration returns nothing
// -> Adds the specified values of critical multiplier to a unit for a given period
// Spell Power System:
// function UnitAddSpellPowerFlatTimed takes unit u, real amount, real duration returns nothing
// -> Add to the Flat amount of Spell Power of a unit for a given period
// function UnitAddSpellPowerPercentTimed takes unit u, real amount, real duration returns nothing
// -> Add to the Percent amount of Spell Power of a unit for a given period
// function AbilitySpellDamage takes unit u, integer abilityId, abilityreallevelfield field returns string
// -> Given an ability field, will return a string that represents the damage that would be dealt
// taking into consideration the spell power bonusses of a unit.
// function AbilitySpellDamageEx takes real amount, unit u returns string
// -> Similar to GetSpellDamage will return the damage that would be dealt but as a string
// Life Steal System:
// function UnitAddLifeStealTimed takes unit u, real amount, real duration returns nothing
// -> Add to the Life Steal amount of a unit the given amount for a given period
// Spell Vamp System:
// function UnitAddSpellVampTimed takes unit u, real amount, real duration returns nothing
// -> Add to the Spell Vamp amount of a unit the given amount for a given period
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Evasion utils */
/* -------------------------------------------------------------------------- */
private struct EvasionUtils extends Evasion
static thistype array data
static integer didx = -1
static timer timer = CreateTimer()
unit unit
real amount
real ticks
boolean type
method remove takes integer i returns integer
if type then
call setEvasionChance(unit, getEvasionChance(unit) - amount)
else
call setMissChance(unit, getMissChance(unit) - amount)
endif
set data[i] = data[didx]
set didx = didx - 1
set unit = null
set ticks = 0
if didx == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > didx
set this = data[i]
if ticks <= 0 then
set i = remove(i)
endif
set ticks = ticks - 1
set i = i + 1
endloop
endmethod
static method addTimed takes unit u, real amount, real duration, boolean evasion returns nothing
local thistype this = thistype.allocate()
set .unit = u
set .amount = amount
set .ticks = duration/0.03125000
set .type = evasion
set didx = didx + 1
set data[didx] = this
if type then
call setEvasionChance(u, getEvasionChance(u) + amount)
else
call setMissChance(u, getMissChance(u) + amount)
endif
if didx == 0 then
call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* Critical Strike Utils */
/* -------------------------------------------------------------------------- */
//region Critical Strike
private struct CriticalUtils extends Critical
static thistype array data
static integer didx = -1
static timer timer = CreateTimer()
unit unit
real crit
real multi
real ticks
integer type
method remove takes integer i returns integer
if type == 0 then
call add(unit, -crit, -multi)
elseif type == 1 then
call setChance(unit, getChance(unit) - crit)
else
call setMultiplier(unit, getMultiplier(unit) - multi)
endif
set data[i] = data[didx]
set didx = didx - 1
set unit = null
set ticks = 0
if didx == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > didx
set this = data[i]
if ticks <= 0 then
set i = remove(i)
endif
set ticks = ticks - 1
set i = i + 1
endloop
endmethod
static method addTimed takes unit u, real chance, real multiplier, real duration, integer types returns nothing
local thistype this = thistype.allocate()
set .unit = u
set .crit = chance
set .multi = multiplier
set .ticks = duration/0.03125000
set .type = types
set didx = didx + 1
set data[didx] = this
if types == 0 then
call add(u, crit, multi)
elseif types == 1 then
call setChance(u, getChance(u) + crit)
else
call setMultiplier(u, getMultiplier(u) + multi)
endif
if didx == 0 then
call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
endstruct
//endregion
/* -------------------------------------------------------------------------- */
/* Spell Power Utils */
/* -------------------------------------------------------------------------- */
//region Spell Power
private struct SpellPowerUtils extends SpellPower
static thistype array data
static integer didx = -1
static timer timer = CreateTimer()
unit unit
real amount
real ticks
boolean isFlat
method remove takes integer i returns integer
if isFlat then
call setFlat(unit, getFlat(unit) - amount)
else
call setPercent(unit, getPercent(unit) - amount)
endif
set data[i] = data[didx]
set didx = didx - 1
set unit = null
set ticks = 0
if didx == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > didx
set this = data[i]
if ticks <= 0 then
set i = remove(i)
endif
set ticks = ticks - 1
set i = i + 1
endloop
endmethod
static method addTimed takes unit u, real amount, real duration, boolean isFlat returns nothing
local thistype this = thistype.allocate()
set .unit = u
set .amount = amount
set .ticks = duration/0.03125000
set .isFlat = isFlat
set didx = didx + 1
set data[didx] = this
if isFlat then
call setFlat(u, getFlat(u) + amount)
else
call setPercent(u, getPercent(u) + amount)
endif
if didx == 0 then
call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
endstruct
//endregion
/* -------------------------------------------------------------------------- */
/* Life Steal Utils */
/* -------------------------------------------------------------------------- */
//region Life Steal
private struct LifeStealUtils extends LifeSteal
static thistype array data
static integer didx = -1
static timer timer = CreateTimer()
unit unit
real lifeSteal
real ticks
method remove takes integer i returns integer
call Set(unit, Get(unit) - lifeSteal)
set data[i] = data[didx]
set didx = didx - 1
set unit = null
set ticks = 0
if didx == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > didx
set this = data[i]
if ticks <= 0 then
set i = remove(i)
endif
set ticks = ticks - 1
set i = i + 1
endloop
endmethod
static method addTimed takes unit u, real amount, real duration returns nothing
local thistype this = thistype.allocate()
set .unit = u
set .lifeSteal = amount
set .ticks = duration/0.03125000
set didx = didx + 1
set data[didx] = this
call Set(u, Get(u) + lifeSteal)
if didx == 0 then
call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
endstruct
//endregion
/* -------------------------------------------------------------------------- */
/* Spell Vamp Utils */
/* -------------------------------------------------------------------------- */
//region Spell Vamp
private struct SpellVampUtils extends SpellVamp
static thistype array data
static integer didx = -1
static timer timer = CreateTimer()
unit unit
real spellVamp
real ticks
method remove takes integer i returns integer
call Set(unit, Get(unit) - spellVamp)
set data[i] = data[didx]
set didx = didx - 1
set unit = null
set ticks = 0
if didx == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > didx
set this = data[i]
if ticks <= 0 then
set i = remove(i)
endif
set ticks = ticks - 1
set i = i + 1
endloop
endmethod
static method addTimed takes unit u, real amount, real duration returns nothing
local thistype this = thistype.allocate()
set .unit = u
set .spellVamp = amount
set .ticks = duration/0.03125000
set didx = didx + 1
set data[didx] = this
call Set(u, Get(u) + spellVamp)
if didx == 0 then
call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function UnitAddEvasionChanceTimed takes unit u, real amount, real duration returns nothing
call EvasionUtils.addTimed(u, amount, duration, true)
endfunction
function UnitAddMissChanceTimed takes unit u, real amount, real duration returns nothing
call EvasionUtils.addTimed(u, amount, duration, false)
endfunction
function UnitAddCriticalStrikeTimed takes unit u, real chance, real multiplier, real duration returns nothing
call CriticalUtils.addTimed(u, chance, multiplier, duration, 0)
endfunction
function UnitAddCriticalChanceTimed takes unit u, real chance, real duration returns nothing
call CriticalUtils.addTimed(u, chance, 0, duration, 1)
endfunction
function UnitAddCriticalMultiplierTimed takes unit u, real multiplier, real duration returns nothing
call CriticalUtils.addTimed(u, 0, multiplier, duration, 2)
endfunction
function UnitAddSpellPowerFlatTimed takes unit u, real amount, real duration returns nothing
call SpellPowerUtils.addTimed(u, amount, duration, true)
endfunction
function UnitAddSpellPowerPercentTimed takes unit u, real amount, real duration returns nothing
call SpellPowerUtils.addTimed(u, amount, duration, false)
endfunction
function AbilitySpellDamage takes unit u, integer abilityId, abilityreallevelfield field returns string
return I2S(R2I((BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, abilityId), field, GetUnitAbilityLevel(u, abilityId) - 1) + SpellPower.getFlat(u)) * (1 + SpellPower.getPercent(u))))
endfunction
function AbilitySpellDamageEx takes real amount, unit u returns string
return I2S(R2I((amount + SpellPower.getFlat(u)) * (1 + SpellPower.getPercent(u))))
endfunction
function UnitAddLifeStealTimed takes unit u, real amount, real duration returns nothing
call LifeStealUtils.addTimed(u, amount, duration)
endfunction
function UnitAddSpellVampTimed takes unit u, real amount, real duration returns nothing
call SpellVampUtils.addTimed(u, amount, duration)
endfunction
endlibrary
library CooldownReduction requires RegisterPlayerUnitEvent, Table, Alloc, Indexer
/* ------------------ Cooldown Reduction v1.9 by Chopinski ------------------ */
// Intro
// This library intension in to introduce to warcraft an easy way to
// manipulate abilities cooldowns based on a cooldown reduction value that
// is unique for each unit.
// How it Works?
// When casting an ability, its "new" cooldown is calculated based on the
// amount of cooldown reduction of the casting unit. the formula for
// calculation is:
// Cooldown = (Default Cooldown - Cooldown Offset) * [(1 - source1)*(1 - source2)*...] * (1 - Cooldown Reduction Flat)
// The system also allow negative values for CDR, resulting in increased
// ability cooldown.
// It does not acumulate because the abilities are registered automatically
// on the first cast, saving its base cooldown (Object Editor values) and
// always using this base value for calculation, so you can still edit
// the ability via the editor and the system takes care of the rest.
// How to Import
// simply copy the CooldownReduction folder over to your map, and start
// use the API functions
// Requirements
// CooldownReduction requires RegisterPlayerUnitEvent, Alloc and a Unit Indexer.
// Credits to Magtheridon96 for RegisterPlayerUnitEvent and to Bribe for
// the UnitIndexer. It also requires patch 1.31+.
// RegisterPlayerUnitEvent: www.hiveworkshop.com/threads/snippet-registerplayerunitevent.203338/
// UnitIndexer: www.hiveworkshop.com/threads/gui-unit-indexer-1-4-0-0.197329/#resource-45899
// Alloc: www.hiveworkshop.com/threads/snippet-alloc.192348/
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
// Use this function to filter out units you dont want to have abilities registered.
// By default dummy units do not trigger the system.
private function UnitFilter takes unit source returns boolean
return GetUnitAbilityLevel(source, 'Aloc') == 0
endfunction
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private module List
readonly thistype next
readonly thistype prev
method init takes nothing returns thistype
set next = this
set prev = this
return this
endmethod
method push takes thistype node returns thistype
set node.prev = prev
set node.next = this
set prev.next = node
set prev = node
return node
endmethod
method pop takes nothing returns nothing
set prev.next = next
set next.prev = prev
endmethod
endmodule
private struct AbilityList extends array
implement Alloc
implement List
unit unit
ability ability
Table defaults
integer id
integer levels
method destroy takes nothing returns nothing
local thistype node = this.next
loop
exitwhen node == this
set node.ability = null
call node.defaults.destroy()
call node.pop()
call node.deallocate()
set node = node.next
endloop
call deallocate()
set unit = null
endmethod
method insert takes integer id returns thistype
local thistype node = push(allocate())
local integer i = 0
set node.id = id
set node.ability = BlzGetUnitAbility(unit, id)
set node.levels = BlzGetAbilityIntegerField(node.ability, ABILITY_IF_LEVELS)
set node.defaults = Table.create()
loop
exitwhen i >= node.levels
set node.defaults.real[i] = BlzGetAbilityRealLevelField(node.ability, ABILITY_RLF_COOLDOWN, i)
set i = i + 1
endloop
return node
endmethod
method update takes integer count, real normal, real flat, real offset returns nothing
local thistype node = this.next
local real cooldown
local integer i
loop
exitwhen node == this
set i = 0
loop
exitwhen i >= node.levels
if count > 0 then
set cooldown = ((node.defaults.real[i] - offset) * normal * (1 - flat))
else
set cooldown = ((node.defaults.real[i] - offset) * (1 - flat))
endif
call BlzSetAbilityRealLevelField(node.ability, ABILITY_RLF_COOLDOWN, i, cooldown)
call IncUnitAbilityLevel(unit, node.id)
call DecUnitAbilityLevel(unit, node.id)
set i = i + 1
endloop
set node = node.next
endloop
endmethod
method calculate takes integer id, integer level, real cooldown, integer count, real normal, real flat, real offset returns nothing
if count > 0 then
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(unit, id), ABILITY_RLF_COOLDOWN, level, ((cooldown - offset) * normal * (1 - flat)))
else
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(unit, id), ABILITY_RLF_COOLDOWN, level, ((cooldown - offset) * (1 - flat)))
endif
call IncUnitAbilityLevel(unit, id)
call DecUnitAbilityLevel(unit, id)
endmethod
method simulate takes real cooldown, integer count, real normal, real flat, real offset returns real
local real cd
if count > 0 then
set cd = ((cooldown - offset) * normal * (1 - flat))
else
set cd = ((cooldown - offset) * (1 - flat))
endif
return cd
endmethod
static method create takes unit source returns thistype
local thistype this = thistype(allocate()).init()
set unit = source
return this
endmethod
endstruct
struct CDR
readonly static hashtable hashtable = InitHashtable()
private static AbilityList array n
private static integer array count
readonly static real array normal
readonly static real array flat
readonly static real array offset
private static method getInstance takes unit source returns AbilityList
local integer i = GetUnitUserData(source)
if n[i] == 0 then
set n[i] = AbilityList.create(source)
endif
return n[i]
endmethod
private static method update takes unit u returns nothing
local integer id = GetUnitUserData(u)
local AbilityList list = getInstance(u)
call list.update(count[id], normal[id], flat[id], offset[id])
endmethod
private static method calculate takes unit u returns real
local integer idx = GetUnitUserData(u)
local integer id = GetHandleId(u)
local integer i = 0
local real cdr = 0
local real aux
loop
exitwhen i > count[idx]
set aux = LoadReal(hashtable, id, i)
if i > 0 then
set cdr = cdr * (1 - aux)
else
set cdr = 1 - aux
endif
set i = i + 1
endloop
return cdr
endmethod
static method get takes unit u, integer types returns real
if types == 0 then
return normal[GetUnitUserData(u)]
elseif types == 1 then
return flat[GetUnitUserData(u)]
else
return offset[GetUnitUserData(u)]
endif
endmethod
static method Set takes unit u, real value, integer types returns nothing
if types == 0 then
set normal[GetUnitUserData(u)] = value
elseif types == 1 then
set flat[GetUnitUserData(u)] = value
else
set offset[GetUnitUserData(u)] = value
endif
call update(u)
endmethod
static method add takes unit u, real amount returns nothing
local integer i = GetUnitUserData(u)
if amount != 0 then
call SaveReal(hashtable, GetHandleId(u), count[i], amount)
set normal[i] = calculate(u)
set count[i] = count[i] + 1
call update(u)
endif
endmethod
static method remove takes unit u, real amount returns nothing
local integer idx = GetUnitUserData(u)
local integer id = GetHandleId(u)
local integer i = 0
local real aux
if amount == 0 then
return
endif
loop
exitwhen i > count[idx] - 1
set aux = LoadReal(hashtable, id, i)
if aux == amount then
call RemoveSavedReal(hashtable, id, i)
if i != count[idx] - 1 then
set aux = LoadReal(hashtable, id, count[idx] - 1)
call SaveReal(hashtable, id, i, aux)
call RemoveSavedReal(hashtable, id, count[idx] - 1)
endif
set count[idx] = count[idx] - 1
set normal[idx] = calculate(u)
set i = count[idx] + 1
call update(u)
else
set i = i + 1
endif
endloop
endmethod
static method calculateCooldown takes unit u, integer id, integer level, real cooldown returns nothing
local integer i = GetUnitUserData(u)
local AbilityList list = getInstance(u)
call list.calculate(id, level - 1, cooldown, count[i], normal[i], flat[i], offset[i])
endmethod
static method simulateCooldown takes unit u, real cooldown returns real
local integer i = GetUnitUserData(u)
local AbilityList list = getInstance(u)
return list.simulate(cooldown, count[i], normal[i], flat[i], offset[i])
endmethod
static method register takes unit u, integer id returns nothing
local AbilityList list
local integer i
if UnitFilter(u) then
set list = getInstance(u)
set i = GetUnitUserData(u)
if not LoadBoolean(hashtable, list, id) then
call list.insert(id)
call SaveBoolean(hashtable, list, id, true)
if count[i] > 0 or normal[i] != 0 or flat[i] != 0 or offset[i] != 0 then
call update(u)
endif
endif
endif
endmethod
private static method onCast takes nothing returns nothing
call register(GetTriggerUnit(), GetSpellAbilityId())
endmethod
private static method onLevel takes nothing returns nothing
call register(GetTriggerUnit(), GetLearnedSkill())
endmethod
private static method onDeindex takes nothing returns nothing
local unit source = GetIndexUnit()
local integer i = GetUnitUserData(source)
local AbilityList list = getInstance(source)
set n[i] = 0
set normal[i] = 0
set flat[i] = 0
set offset[i] = 0
set count[i] = 0
if list != 0 then
call list.destroy()
call FlushChildHashtable(hashtable, list)
endif
call FlushChildHashtable(hashtable, GetHandleId(source))
endmethod
private static method onInit takes nothing returns nothing
call RegisterUnitDeindexEvent(function thistype.onDeindex)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function thistype.onLevel)
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function GetUnitCooldownReduction takes unit u returns real
return 1 - CDR.get(u, 0)
endfunction
function GetUnitCooldownReductionFlat takes unit u returns real
return CDR.get(u, 1)
endfunction
function GetUnitCooldownOffset takes unit u returns real
return CDR.get(u, 2)
endfunction
function SetUnitCooldownReduction takes unit u, real value returns nothing
call CDR.Set(u, value, 0)
endfunction
function SetUnitCooldownReductionFlat takes unit u, real value returns nothing
call CDR.Set(u, value, 1)
endfunction
function SetUnitCooldownOffset takes unit u, real value returns nothing
call CDR.Set(u, value, 2)
endfunction
function UnitAddCooldownReduction takes unit u, real value returns nothing
call CDR.add(u, value)
endfunction
function UnitAddCooldownReductionFlat takes unit u, real value returns nothing
call CDR.Set(u, CDR.get(u, 1) + value, 1)
endfunction
function UnitAddCooldownOffset takes unit u, real value returns nothing
call CDR.Set(u, CDR.get(u, 2) + value, 2)
endfunction
function UnitRemoveCooldownReduction takes unit u, real value returns nothing
call CDR.remove(u, value)
endfunction
function CalculateAbilityCooldown takes unit u, integer id, integer level, real cooldown returns nothing
call CDR.calculateCooldown(u, id, level, cooldown)
endfunction
function SimulateAbilityCooldown takes unit u, real cooldown returns real
return CDR.simulateCooldown(u, cooldown)
endfunction
function RegisterAbility takes unit u, integer id returns nothing
call CDR.register(u, id)
endfunction
endlibrary
library CooldownReductionUtils requires CooldownReduction
/* --------------- Cooldown Reduction Utils v1.9 by Chopinski --------------- */
// Intro
// Utility Library that include a few extra functions to deal with
// Cooldown Reduction
// JASS API
// function UnitAddCooldownReductionTimed takes unit u, real value, real duration returns nothing
// -> Add to the amount of cdr of a unit for a given duration. Accepts positive and negative values.
// -> It handles removing the bonus automatically
// function UnitAddCooldownReductionFlatTimed takes unit u, real value, real duration returns nothing
// -> Add to the amount of cdr flat of a unit for a given period. Accepts positive and negative values.
// -> It handles removing the bonus automatically
// function UnitAddCooldownOffsetTimed takes unit u, real value, real duration returns nothing
// -> Add to the amount of cdr offset of a unit for a given period. Accepts positive and negative values.
// -> It handles removing the bonus automatically
// function GetUnitCooldownReductionEx takes unit u returns string
// -> Returns the amount of cdr a unit has as a string factored by 100
// -> example of return: 10.50 -> 0.105 internally.
// function GetUnitCooldownReductionFlatEx takes unit u returns string
// -> Returns the amount of cdr flat a unit has as a string factored by 100
// -> example of return: 10.50 -> 0.105 internally.
// function GetUnitCooldownOffsetEx takes unit u returns string
// -> Returns the amount of cdr offset a unit has as a string
// function GetAbilityTable takes nothing returns hashtable
// -> Returns the hashtable that holds the units default cooldown reduction values.
// -> Use with caution! you might break stuff
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private struct CDRUtils extends CDR
static timer t = CreateTimer()
//----------------------------------------------
static integer didx = -1
static thistype array data
//----------------------------------------------
unit u
real ticks
real amount
integer tipo
method destroy takes nothing returns nothing
if didx == -1 then
call PauseTimer(t)
endif
set .u = null
set .ticks = 0
call .deallocate()
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
loop
exitwhen i > didx
set this = data[i]
set .ticks = .ticks - 1
if .ticks <= 0 then
if .tipo == 0 then
call remove(.u, .amount)
elseif .tipo == 1 then
call Set(.u, get(.u, 1) - .amount, 1)
else
call Set(.u, get(.u, 2) - .amount, 2)
endif
set data[i] = data[didx]
set didx = didx - 1
set i = i - 1
call .destroy()
endif
set i = i + 1
endloop
endmethod
static method addTimed takes unit u, real amount, real duration, integer tipo returns nothing
local thistype this = thistype.allocate()
set .u = u
set .amount = amount
set .tipo = tipo
set .ticks = duration/0.03125000
set didx = didx + 1
set data[didx] = this
if tipo == 0 then
call add(u, amount)
elseif tipo == 1 then
call Set(u, get(u, 1) + amount, 1)
else
call Set(u, get(u, 2) + amount, 2)
endif
if didx == 0 then
call TimerStart(t, 0.03125000, true, function thistype.onPeriod)
endif
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* JASS API */
/* -------------------------------------------------------------------------- */
function UnitAddCooldownReductionTimed takes unit u, real value, real duration returns nothing
call CDRUtils.addTimed(u, value, duration, 0)
endfunction
function UnitAddCooldownReductionFlatTimed takes unit u, real value, real duration returns nothing
call CDRUtils.addTimed(u, value, duration, 1)
endfunction
function UnitAddCooldownOffsetTimed takes unit u, real value, real duration returns nothing
call CDRUtils.addTimed(u, value, duration, 2)
endfunction
function GetUnitCooldownReductionEx takes unit u returns string
return R2SW(CDRUtils.get(u, 0)*100, 1, 2)
endfunction
function GetUnitCooldownReductionFlatEx takes unit u returns string
return R2SW(CDRUtils.get(u, 1)*100, 1, 2)
endfunction
function GetUnitCooldownOffsetEx takes unit u returns string
return R2SW(CDRUtils.get(u, 2), 1, 2)
endfunction
function GetAbilityTable takes nothing returns hashtable
return CDR.hashtable
endfunction
endlibrary
library WaterElemental requires SpellEffectEvent, PluginSpellEffect, NewBonus, Indexer
/* -------------------- Water Elemental v1.1 by Chopinski ------------------- */
// Credits:
// Blizzard - Icon
// Bribe - SpellEffectEvent
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The raw code of the ability
private constant integer ABILITY = 'A000'
// The raw code of the Water Elemental unit
public constant integer ELEMENTAL = 'h001'
// The summon effect
private constant string MODEL = "WaterBurst.mdl"
// The summon effect scale
private constant real SCALE = 1.
endglobals
// The unit damage
private function GetDamage takes unit source, integer level returns integer
return 30 + R2I((BlzGetUnitBaseDamage(source, 0) + GetUnitBonus(source, BONUS_DAMAGE))*0.3)
endfunction
// The unit health
private function GetHealth takes unit source, integer level returns integer
return 600 + R2I(BlzGetUnitMaxHP(source)*0.4)
endfunction
// The unit armor
private function GetArmor takes unit source, integer level returns real
return 1. + GetUnitBonus(source, BONUS_ARMOR)
endfunction
// The unit duration
private function GetDuration takes unit source, integer level returns real
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, ABILITY), ABILITY_RLF_DURATION_HERO, level - 1)
endfunction
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
struct Elemental
private static thistype array struct
private unit unit
private group group
method operator size takes nothing returns integer
return BlzGroupGetSize(group)
endmethod
method destroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i == size
set struct[GetUnitUserData(BlzGroupUnitAt(group, i))] = 0
set i = i + 1
endloop
call DestroyGroup(group)
call deallocate()
set unit = null
set group = null
endmethod
method add takes unit u returns nothing
set struct[GetUnitUserData(u)] = this
call GroupAddUnit(group, u)
endmethod
method command takes unit target, real x, real y, string order returns nothing
local integer i = 0
if target == null then
if order == "stop" or order == "holdposition" then
call GroupImmediateOrder(group, order)
elseif order == "attackground" or order == "smart" or order == "move" or order == "attack" then
loop
exitwhen i == size
call IssuePointOrder(BlzGroupUnitAt(group, i), order, x + 300*Cos(i*2*bj_PI/size), y + 300*Sin(i*2*bj_PI/size))
set i = i + 1
endloop
endif
else
if order == "smart" or order == "move" or order == "attack" then
call GroupTargetOrder(group, order, target)
endif
endif
endmethod
static method owner takes integer id returns unit
local thistype this
if struct[id] != 0 then
set this = struct[id]
return unit
else
return null
endif
endmethod
private static method onOrder takes nothing returns nothing
local unit source = GetOrderedUnit()
local integer id
local thistype this
if GetUnitTypeId(source) == ELEMENTAL then
set id = GetUnitUserData(source)
if struct[id] != 0 then
set this = struct[id]
if GetOrderTargetUnit() == unit then
if not IsUnitInGroup(source, group) then
call GroupAddUnit(group, source)
endif
else
if IsUnitSelected(source, GetOwningPlayer(source)) and IsUnitInGroup(source, group) then
call GroupRemoveUnit(group, source)
endif
endif
endif
endif
set source = null
endmethod
private static method onDeath takes nothing returns nothing
local unit source = GetTriggerUnit()
local integer id
local thistype this
if GetUnitTypeId(source) == ELEMENTAL then
set id = GetUnitUserData(source)
if struct[id] != 0 then
set this = struct[id]
call GroupRemoveUnit(group, source)
set struct[id] = 0
endif
endif
endmethod
static method create takes unit source returns thistype
local thistype this = thistype.allocate()
set unit = source
set group = CreateGroup()
return this
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
endmethod
endstruct
private struct Master
private static thistype array struct
Elemental elementals
method destroy takes nothing returns nothing
call elementals.destroy()
call deallocate()
endmethod
private static method onDeindex takes nothing returns nothing
local integer id = GetUnitUserData(GetIndexUnit())
local thistype this
if struct[id] != 0 then
set this = struct[id]
call destroy()
set struct[id] = 0
endif
endmethod
private static method onOrder takes nothing returns nothing
local unit source = GetOrderedUnit()
local integer id = GetUnitUserData(source)
local thistype this
if GetUnitAbilityLevel(source, ABILITY) > 0 and struct[id] != 0 then
set this = struct[id]
call elementals.command(GetOrderTargetUnit(), GetOrderPointX(), GetOrderPointY(), OrderId2String(GetIssuedOrderId()))
endif
set source = null
endmethod
private static method onCast takes nothing returns nothing
local thistype this
local real angle = GetUnitFacing(Spell.source.unit)
local unit u = CreateUnit(Spell.source.player, ELEMENTAL, Spell.source.x + 250*Cos(Deg2Rad(angle)), Spell.source.y + 250*Sin(Deg2Rad(angle)), angle)
call DestroyEffect(AddSpecialEffectEx(MODEL, GetUnitX(u), GetUnitY(u), 0, SCALE))
if struct[Spell.source.id] != 0 then
set this = struct[Spell.source.id]
else
set this = thistype.allocate()
set struct[Spell.source.id] = this
set elementals = Elemental.create(Spell.source.unit)
endif
call BlzSetUnitBaseDamage(u, GetDamage(Spell.source.unit, Spell.level), 0)
call BlzSetUnitMaxHP(u, GetHealth(Spell.source.unit, Spell.level))
call SetUnitLifePercentBJ(u, 100)
call BlzSetUnitArmor(u, GetArmor(Spell.source.unit, Spell.level))
call SetUnitAnimation(u, "Birth")
call UnitApplyTimedLife(u, 'BTLF', GetDuration(Spell.source.unit, Spell.level))
call elementals.add(u)
set u = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY, function thistype.onCast)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onOrder)
call RegisterUnitDeindexEvent(function thistype.onDeindex)
endmethod
endstruct
endlibrary
library CrushingWave requires SpellEffectEvent, PluginSpellEffect, Missiles, Utilities, CrowdControl optional WaterElemental
/* --------------------- Crushing Wave v1.1 by Chopinski -------------------- */
// Credits:
// Blizzard - Icon
// Bribe - SpellEffectEvent
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The raw code of the ability
private constant integer ABILITY = 'A001'
// The Wave model
private constant string MODEL = "LivingTide.mdl"
// The Wave speed
private constant real SPEED = 1250
// The wave model scale
private constant real SCALE = 0.8
endglobals
// The wave damage
private function GetDamage takes unit source, integer level returns real
return 50. + 50.*level
endfunction
// The Wave collision
private function GetCollision takes unit source, integer level returns real
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, ABILITY), ABILITY_RLF_AREA_OF_EFFECT, level - 1)
endfunction
// The water elemental search range
private function GetAoE takes unit source, integer level returns real
return 1000. + 0.*level
endfunction
// The wave travel distance
private function GetTravelDistance takes unit source, integer level returns real
return 1000. + 0.*level
endfunction
// The Wave slow amount
private function GetSlowAmount takes unit source, integer level returns real
return 0.1 + 0.1*level
endfunction
// The Slow duration
private function GetSlowDuration takes unit source, integer level returns real
return 1. + 0.25*level
endfunction
// The damae filter
private function UnitFilter takes player owner, unit target returns boolean
return UnitAlive(target) and IsUnitEnemy(target, owner) and not IsUnitType(target, UNIT_TYPE_STRUCTURE)
endfunction
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private struct Wave extends Missiles
unit unit
real slow
real timeout
method onPeriod takes nothing returns boolean
if unit != null then
call SetUnitX(unit, x)
call SetUnitY(unit, y)
endif
return false
endmethod
method onHit takes unit u returns boolean
if UnitFilter(owner, u) then
if UnitDamageTarget(source, u, damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null) then
call SlowUnit(u, slow, timeout, null, null, false)
endif
endif
return false
endmethod
method onRemove takes nothing returns nothing
if unit != null then
call PauseUnit(unit, false)
call SetUnitAnimation(unit, "Stand")
call SetUnitInvulnerable(unit, false)
endif
set unit = null
endmethod
endstruct
private struct CrushingWave extends array
private static method launch takes real x, real y, real z, real tx, real ty, real tz, unit source, player owner, integer level, unit elemental returns nothing
local Wave wave = Wave.create(x, y, z, tx, ty, tz)
set wave.model = MODEL
set wave.scale = SCALE
set wave.speed = SPEED
set wave.source = source
set wave.owner = owner
set wave.unit = elemental
set wave.damage = GetDamage(source, level)
set wave.collision = GetCollision(source, level)
set wave.slow = GetSlowAmount(source, level)
set wave.timeout = GetSlowDuration(source, level)
if elemental != null then
call BlzSetUnitFacingEx(elemental, AngleBetweenCoordinates(x, y, tx, ty)*bj_RADTODEG)
call PauseUnit(elemental, true)
call SetUnitAnimationByIndex(elemental, 8)
call SetUnitInvulnerable(elemental, true)
endif
call wave.launch()
endmethod
private static method onCast takes nothing returns nothing
local real angle = AngleBetweenCoordinates(Spell.source.x, Spell.source.y, Spell.x, Spell.y)
local real offset = GetTravelDistance(Spell.source.unit, Spell.level)
local group g
local unit u
call launch(Spell.source.x, Spell.source.y, 0, Spell.source.x + offset*Cos(angle), Spell.source.y + offset*Sin(angle), 0, Spell.source.unit, Spell.source.player, Spell.level, null)
static if LIBRARY_WaterElemental then
set g = CreateGroup()
call GroupEnumUnitsInRange(g, Spell.source.x, Spell.source.y, GetAoE(Spell.source.unit, Spell.level), null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if UnitAlive(u) and GetUnitTypeId(u) == WaterElemental_ELEMENTAL then
if Elemental.owner(GetUnitUserData(u)) == Spell.source.unit then
call launch(GetUnitX(u), GetUnitY(u), 0, Spell.x, Spell.y, 0, Spell.source.unit, Spell.source.player, Spell.level, u)
endif
endif
call GroupRemoveUnit(g, u)
endloop
call DestroyGroup(g)
endif
set u = null
set g = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY, function thistype.onCast)
endmethod
endstruct
endlibrary
library WaterShield requires RegisterPlayerUnitEvent, SpellEffectEvent, PluginSpellEffect, DamageInterface, Missiles, Utilities, TimerUtils
/* --------------------- Water Shield v1.0 by Chopinski --------------------- */
// Credits:
// Darkfang - Icon
// Bribe - SpellEffectEvent
// Vexorian - TimerUtils
// Magtheridon96 - RegisterPlayerUnitEvent
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The raw code of the ability
private constant integer ABILITY = 'A002'
// The shield model
private constant string MODEL = "WaterShield.mdl"
// The shield attachement point
private constant string ATTACH = "origin"
// The explosion model
private constant string EXPLOSION_MODEL = "LivingTide.mdl"
// The scale of the explosion model
private constant real EXPLOSION_SCALE = 0.6
// The water bolt model
private constant string BOLT_MODEL = "Abilities\\Weapons\\WaterElementalMissile\\WaterElementalMissile.mdl"
// The water bolt scal
private constant real BOLT_SCALE = 1.
// The water bolt speed
private constant real BOLT_SPEED = 1000.
endglobals
// The shield amount
private function GetAmount takes unit source, integer level returns real
return 100.*level + (0.5 + 0.5*level)*GetHeroInt(source, true)
endfunction
// The water bolt damage
private function GetBoltDamage takes unit source, integer level returns real
return 25. + 25.*level
endfunction
// The range at which units can be selected by water bolt
private function GetAoE takes unit source, integer level returns real
return 400. + 0.*level
endfunction
// The aoe of the explosion when there is a remaining shield amount
private function GetExplosionAoE takes unit source, integer level returns real
return 400. + 0.*level
endfunction
// The angle in degrees at which units can be selected
private function GetAngle takes unit source, integer level returns real
return 90. + 0.*level
endfunction
// The Shield duration
private function GetDuration takes unit source, integer level returns real
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, ABILITY), ABILITY_RLF_DURATION_HERO, level - 1)
endfunction
// The unit filter
private function UnitFilter takes player owner, unit target returns boolean
return IsUnitEnemy(target, owner) and UnitAlive(target) and not IsUnitType(target, UNIT_TYPE_STRUCTURE)
endfunction
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private struct WaterBolt extends Missiles
method onFinish takes nothing returns boolean
if UnitAlive(target) then
call UnitDamageTarget(source, target, damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
endif
return true
endmethod
endstruct
private struct WaterShield
static thistype array defense
static thistype array offense
static effect array effect
timer timer
unit source
unit target
player player
group group
integer id
integer level
real amount
real angle
real aoe
boolean defensive
method destroy takes nothing returns nothing
if defensive then
set defense[id] = 0
if offense[id] == 0 then
call DestroyEffect(effect[id])
set effect[id] = null
endif
else
set offense[id] = 0
if defense[id] == 0 then
call DestroyEffect(effect[id])
set effect[id] = null
endif
endif
call DestroyGroup(group)
call ReleaseTimer(timer)
call deallocate()
set timer = null
set group = null
set source = null
set target = null
set player = null
endmethod
static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
local unit u
if defensive and amount > 0 then
call GroupEnumUnitsInRange(group, GetUnitX(target), GetUnitY(target), aoe, null)
loop
set u = FirstOfGroup(group)
exitwhen u == null
if UnitFilter(player, u) then
call UnitDamageTarget(source, u, amount, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
endif
call GroupRemoveUnit(group, u)
endloop
call DestroyEffect(AddSpecialEffectEx(EXPLOSION_MODEL, GetUnitX(target), GetUnitY(target), 0, EXPLOSION_SCALE))
endif
call destroy()
endmethod
static method onDamage takes nothing returns nothing
local real damage = GetEventDamage()
local thistype this
if damage > 0 and defense[Damage.target.id] != 0 then
set this = defense[Damage.target.id]
if damage <= amount then
set amount = amount - damage
call BlzSetEventDamage(0)
else
set damage = damage - amount
set amount = 0
call BlzSetEventDamage(damage)
call destroy()
endif
endif
endmethod
private static method onAttack takes nothing returns nothing
local thistype this
local WaterBolt bolt
local unit u
if Damage.isEnemy and offense[Damage.target.id] != 0 then
set this = offense[Damage.target.id]
call GroupEnumUnitsInRange(group, Damage.target.x, Damage.target.y, aoe, null)
call GroupRemoveUnit(group, Damage.target.unit)
loop
set u = FirstOfGroup(group)
exitwhen u == null
if UnitFilter(player, u) and IsUnitInCone(u, Damage.target.x, Damage.target.y, aoe, AngleBetweenCoordinates(Damage.source.x, Damage.source.y, Damage.target.x, Damage.target.y)*bj_RADTODEG, angle) then
set bolt = WaterBolt.create(Damage.target.x, Damage.target.y, 50, GetUnitX(u), GetUnitY(u), 50)
set bolt.model = BOLT_MODEL
set bolt.speed = BOLT_SPEED
set bolt.scale = BOLT_SCALE
set bolt.source = source
set bolt.target = u
set bolt.damage = amount
call bolt.launch()
endif
call GroupRemoveUnit(group, u)
endloop
endif
endmethod
private static method onDeath takes nothing returns nothing
local integer id = GetUnitUserData(GetTriggerUnit())
local thistype this
if defense[id] != 0 then
set this = defense[id]
call destroy()
endif
if offense[id] != 0 then
set this = offense[id]
call destroy()
endif
endmethod
static method onCast takes nothing returns nothing
local thistype this
if effect[Spell.target.id] == null then
set effect[Spell.target.id] = AddSpecialEffectTarget(MODEL, Spell.target.unit, ATTACH)
endif
if IsUnitEnemy(Spell.target.unit, Spell.source.player) then
if offense[Spell.target.id] != 0 then
set this = offense[Spell.target.id]
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set id = Spell.target.id
set target = Spell.target.unit
set group = CreateGroup()
set defensive = false
set offense[id] = this
endif
set source = Spell.source.unit
set player = Spell.source.player
set level = Spell.level
set amount = GetBoltDamage(source, level)
set angle = GetAngle(source, level)
set aoe = GetAoE(source, level)
else
if defense[Spell.target.id] != 0 then
set this = defense[Spell.target.id]
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set id = Spell.target.id
set target = Spell.target.unit
set group = CreateGroup()
set defensive = true
set amount = 0
set defense[id] = this
endif
set source = Spell.source.unit
set player = Spell.source.player
set level = Spell.level
set amount = amount + GetAmount(source, level)
set aoe = GetExplosionAoE(source, level)
endif
call TimerStart(timer, GetDuration(source, level), false, function thistype.onExpire)
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY, function thistype.onCast)
call RegisterAnyDamageEvent(function thistype.onDamage)
call RegisterAttackDamageEvent(function thistype.onAttack)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
endmethod
endstruct
endlibrary
library BrillanceAura requires RegisterPlayerUnitEvent, TimerUtils
/* -------------------- Brilliance Aure v1.0 by Chopinski ------------------- */
// Credits
// Vexorian - TimerUtils
// Magtheridon96 - RegisterPlayerUnitEvent
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The raw code of the ability
private constant integer ABILITY = 'A003'
// If true the bonus regen will stack with each cast
private constant boolean STACK = false
endglobals
// The bonus mana regen when an ability is cast
private function GetBonusManaRegen takes unit source, integer level returns real
return 1.5 * level
endfunction
// The duration of the bonus regen
private function GetDuration takes unit source, integer level returns real
return 2.5 * level
endfunction
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private struct BrillianceAura
static thistype array struct
timer timer
unit unit
ability ability
integer id
integer levels
real bonus
abilityreallevelfield field
static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
local integer i = 0
loop
exitwhen i == levels
call BlzSetAbilityRealLevelField(ability, field, i, BlzGetAbilityRealLevelField(ability, field, i) - bonus)
call IncUnitAbilityLevel(unit, ABILITY)
call DecUnitAbilityLevel(unit, ABILITY)
set i = i + 1
endloop
call ReleaseTimer(timer)
call deallocate()
set struct[id] = 0
set bonus = 0
set field = null
set timer = null
set unit = null
set ability = null
endmethod
static method onCast takes nothing returns nothing
local unit source = GetTriggerUnit()
local integer level = GetUnitAbilityLevel(source, ABILITY)
local integer i = 0
local thistype this
if level > 0 then
static if STACK then
set this = thistype.allocate()
set timer = NewTimerEx(this)
set id = GetUnitUserData(source)
set unit = source
set field = ABILITY_RLF_MANA_REGENERATION_INCREASE
set ability = BlzGetUnitAbility(source, ABILITY)
set levels = BlzGetAbilityIntegerField(ability, ABILITY_IF_LEVELS)
set bonus = GetBonusManaRegen(source, level)
loop
exitwhen i == levels
call BlzSetAbilityRealLevelField(ability, field, i, BlzGetAbilityRealLevelField(ability, field, i) + bonus)
call IncUnitAbilityLevel(source, ABILITY)
call DecUnitAbilityLevel(source, ABILITY)
set i = i + 1
endloop
else
if struct[GetUnitUserData(source)] != 0 then
set this = struct[GetUnitUserData(source)]
else
set this = thistype.allocate()
set timer = NewTimerEx(this)
set id = GetUnitUserData(source)
set unit = source
set field = ABILITY_RLF_MANA_REGENERATION_INCREASE
set ability = BlzGetUnitAbility(source, ABILITY)
set levels = BlzGetAbilityIntegerField(ability, ABILITY_IF_LEVELS)
set bonus = 0
set struct[id] = this
endif
if bonus == 0 then
set bonus = GetBonusManaRegen(source, level)
loop
exitwhen i == levels
call BlzSetAbilityRealLevelField(ability, field, i, BlzGetAbilityRealLevelField(ability, field, i) + bonus)
call IncUnitAbilityLevel(source, ABILITY)
call DecUnitAbilityLevel(source, ABILITY)
set i = i + 1
endloop
endif
endif
call TimerStart(timer, GetDuration(source, level), false, function thistype.onExpire)
endif
set source = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endstruct
endlibrary
library WaterOrb requires RegisterPlayerUnitEvent, Utilities, NewBonus, DamageInterface
/* ----------------------- Water Orb v1.0 by Chopinski ---------------------- */
// Credits:
// Darkfang - Icon
// Magtheridon96 - RegisterPlayerUnitEvent
// General Frank - Model
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The raw code of the level 1 buff
private constant integer BUFF_1 = 'B002'
// The raw code of the level 2 buff
private constant integer BUFF_2 = 'B003'
// The raw code of the level 3 buff
private constant integer BUFF_3 = 'B004'
// The raw code of the level 4 buff
private constant integer BUFF_4 = 'B005'
// The orb model
private constant string MODEL = "OrbWaterX.mdl"
// The orb model scale
private constant real SCALE = 1.
// The pickup effect model
private constant string EFFECT = "Abilities\\Spells\\Items\\AIma\\AImaTarget.mdl"
// The pickup effect model attach point
private constant string ATTACH = "origin"
// The update period
private constant real PERIOD = 0.25
endglobals
// The orb duration
private function GetDuratoin takes integer buffid returns real
if buffid == BUFF_1 then
return 20.
elseif buffid == BUFF_2 then
return 20.
elseif buffid == BUFF_3 then
return 20.
else
return 20.
endif
endfunction
// The max mana bonus
private function GetManaBonus takes integer buffid returns real
if buffid == BUFF_1 then
return 20.
elseif buffid == BUFF_2 then
return 30.
elseif buffid == BUFF_3 then
return 40.
else
return 50.
endif
endfunction
// The chance to drop an orb
private function GetDropChance takes unit target, integer buffid returns integer
if IsUnitType(target, UNIT_TYPE_HERO) then
return 100
else
if buffid == BUFF_1 then
return 20
elseif buffid == BUFF_2 then
return 20
elseif buffid == BUFF_3 then
return 20
else
return 20
endif
endif
endfunction
//
private function GetPickupRange takes integer buffid returns real
if buffid == BUFF_1 then
return 100.
elseif buffid == BUFF_2 then
return 100.
elseif buffid == BUFF_3 then
return 100.
else
return 100.
endif
endfunction
// The unit drop filter
private function UnitDropFilter takes unit target returns boolean
return not IsUnitType(target, UNIT_TYPE_STRUCTURE)
endfunction
// The unit pickup filter
private function UnitPickupFilter takes player owner, unit target returns boolean
return UnitAlive(target) and IsUnitType(target, UNIT_TYPE_HERO) and IsUnitEnemy(target, owner)
endfunction
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private struct WaterOrb
static timer timer = CreateTimer()
static integer key = -1
static thistype array array
static integer array flag
group group
player player
effect effect
real duration
real bonus
real range
real x
real y
private method remove takes integer i returns integer
call DestroyGroup(group)
call DestroyEffect(effect)
set array[i] = array[key]
set key = key - 1
set group = null
set player = null
set effect = null
if key == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local thistype this
local unit u
loop
exitwhen i > key
set this = array[i]
if duration > 0 then
set duration = duration - PERIOD
call GroupEnumUnitsInRange(group, x, y, range, null)
loop
set u = FirstOfGroup(group)
exitwhen u == null
if UnitPickupFilter(player, u) then
call AddUnitBonus(u, BONUS_MANA, bonus)
call DestroyEffect(AddSpecialEffectTarget(EFFECT, u, ATTACH))
set i = remove(i)
exitwhen true
endif
call GroupRemoveUnit(group, u)
endloop
else
set i = remove(i)
endif
set i = i + 1
endloop
set u = null
endmethod
private static method onDamage takes nothing returns nothing
local real damage = GetEventDamage()
if damage > 0 then
set flag[Damage.target.id] = 0
if damage >= GetWidgetLife(Damage.target.unit) and UnitDropFilter(Damage.target.unit) then
if GetUnitAbilityLevel(Damage.target.unit, BUFF_4) > 0 then
if GetRandomInt(0, 100) <= GetDropChance(Damage.target.unit, BUFF_4) then
set flag[Damage.target.id] = BUFF_4
endif
elseif GetUnitAbilityLevel(Damage.target.unit, BUFF_3) > 0 then
if GetRandomInt(0, 100) <= GetDropChance(Damage.target.unit, BUFF_3) then
set flag[Damage.target.id] = BUFF_3
endif
elseif GetUnitAbilityLevel(Damage.target.unit, BUFF_2) > 0 then
if GetRandomInt(0, 100) <= GetDropChance(Damage.target.unit, BUFF_2) then
set flag[Damage.target.id] = BUFF_2
endif
elseif GetUnitAbilityLevel(Damage.target.unit, BUFF_1) > 0 then
if GetRandomInt(0, 100) <= GetDropChance(Damage.target.unit, BUFF_1) then
set flag[Damage.target.id] = BUFF_1
endif
endif
endif
endif
endmethod
private static method onDeath takes nothing returns nothing
local unit source = GetTriggerUnit()
local integer id = GetUnitUserData(source)
local thistype this
if flag[id] != 0 then
set this = thistype.allocate()
set key = key + 1
set array[key] = this
set x = GetUnitX(source)
set y = GetUnitY(source)
set group = CreateGroup()
set player = GetOwningPlayer(source)
set effect = AddSpecialEffectEx(MODEL, x, y, 0, SCALE)
set duration = GetDuratoin(flag[id])
set range = GetPickupRange(flag[id])
set bonus = GetManaBonus(flag[id])
if key == 0 then
call TimerStart(timer, PERIOD, true, function thistype.onPeriod)
endif
endif
set source = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
call RegisterAnyDamageEvent(function thistype.onDamage)
endmethod
endstruct
endlibrary
library LivingTide requires RegisterPlayerUnitEvent, SpellEffectEvent, PluginSpellEffect, Missiles, Utilities, MouseUtils
/* ---------------------- Living Tide v1.0 by Chopinski --------------------- */
// Credits:
// Blizzard - Icon
// Bribe - SpellEffectEvent
// Vexorian - TimerUtils
// Magtheridon96 - RegisterPlayerUnitEvent
// MyPad - MouseUtils
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The raw code of the ability
private constant integer ABILITY = 'A004'
// The Living Tide model
private constant string MODEL = "LivingTide.mdl"
// The Living Tide scale
private constant real SCALE = 1.
// The Living Tide speed
private constant real SPEED = 550.
// The update period
private constant real PERIOD = 0.03125000
endglobals
// The amount of damage dealt in a second
private function GetDamagePerSecond takes unit source, integer level returns real
return 100. * level
endfunction
// The living tide collision size
private function GetCollision takes unit source, integer level returns real
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, ABILITY), ABILITY_RLF_AREA_OF_EFFECT, level - 1)
endfunction
// The living tide sight range
private function GetVisionRange takes unit source, integer level returns real
return 1000. + 0.*level
endfunction
// The base mana cost per second
private function GetBaseManaCostPerSecond takes unit source, integer level returns integer
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(source, ABILITY), ABILITY_ILF_MANA_COST, level - 1)
endfunction
// The range step to change the amount of mana consumed
private function GetManaCostRangeIncrement takes unit source, integer level returns real
return 100.
endfunction
// The mana cost amount per range increment
private function GetManaCostPerIncrement takes unit source, integer level returns real
return 5.
endfunction
// The unit filter for damage
private function UnitFilter takes player owner, unit target returns boolean
return UnitAlive(target) and IsUnitEnemy(target, owner) and not IsUnitType(target, UNIT_TYPE_STRUCTURE)
endfunction
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private struct Tide extends Missiles
method onHit takes unit u returns boolean
if UnitFilter(owner, u) then
if UnitDamageTarget(source, u, damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null) then
call flush(u)
endif
endif
return false
endmethod
method onFinish takes nothing returns boolean
call pause(true)
return false
endmethod
endstruct
private struct LivingTide
static timer timer = CreateTimer()
static integer key = -1
static thistype array array
static thistype array struct
unit unit
player player
integer id
integer level
integer mana
real step
real range
Tide tide
method remove takes integer i returns integer
call tide.terminate()
set array[i] = array[key]
set key = key - 1
set unit = null
set player = null
set tide = 0
if key == -1 then
call PauseTimer(timer)
endif
call deallocate()
return i - 1
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
local real cost
local real x
local real y
local thistype this
loop
exitwhen i > key
set this = array[i]
if struct[id] != 0 then
set x = GetUnitX(unit)
set y = GetUnitY(unit)
set cost = (mana + step*(DistanceBetweenCoordinates(x, y, tide.x, tide.y)/range)) * PERIOD
if cost > GetUnitState(unit, UNIT_STATE_MANA) then
call IssueImmediateOrder(unit, "stop")
set struct[id] = 0
set i = remove(i)
else
call AddUnitMana(unit, -cost)
call tide.deflect(GetPlayerMouseX(player), GetPlayerMouseY(player), 0)
call BlzSetUnitFacingEx(unit, AngleBetweenCoordinates(x, y, tide.x, tide.y)*bj_RADTODEG)
if tide.paused then
call tide.pause(false)
endif
endif
else
set i = remove(i)
endif
set i = i + 1
endloop
endmethod
private static method onEnd takes nothing returns nothing
if GetSpellAbilityId() == ABILITY then
set struct[GetUnitUserData(GetTriggerUnit())] = 0
endif
endmethod
private static method onCast takes nothing returns nothing
local thistype this
if struct[Spell.source.id] == 0 then
set this = thistype.allocate()
set id = Spell.source.id
set unit = Spell.source.unit
set player = Spell.source.player
set level = Spell.level
set mana = GetBaseManaCostPerSecond(unit, level)
set range = GetManaCostRangeIncrement(unit, level)
set step = GetManaCostPerIncrement(unit, level)
set key = key + 1
set array[key] = this
set struct[id] = this
set tide = Tide.create(Spell.x, Spell.y, 0, Spell.source.x, Spell.source.y, 0)
set tide.model = MODEL
set tide.scale = SCALE
set tide.speed = SPEED
set tide.source = unit
set tide.owner = player
set tide.vision = GetVisionRange(unit, level)
set tide.damage = GetDamagePerSecond(unit, level) / (1/Missiles_PERIOD)
set tide.collision = GetCollision(unit, level)
call tide.launch()
if key == 0 then
call TimerStart(timer, PERIOD, true, function thistype.onPeriod)
endif
endif
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY, function thistype.onCast)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_ENDCAST, function thistype.onEnd)
endmethod
endstruct
endlibrary
library BadWeather requires RegisterPlayerUnitEvent, SpellEffectEvent, PluginSpellEffect, TimerUtils, Utilities, DamageInterface
/* ---------------------- Bad Weather v1.0 by Chopinski --------------------- */
// Credits:
// Bribe - SpellEffectEvent
// Magtheridon96 - RegisterPlayerUnitEvent
// Vexorian - TimerUtils
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The raw code of the Ability
private constant integer ABILITY = 'A005'
// The raw code of the debuff Ability
private constant integer DEBUFF = 'A007'
// The raw code of the debuff buff
private constant integer BUFF = 'B001'
// The rain model
private constant string MODEL = "Rain.mdl"
// The rain model scale
private constant real SCALE = 2.5
// The raw code of the Jaina unit in the editor
private constant integer JAINA_ID = 'H000'
// The GAIN_AT_LEVEL is greater than 0
// Jaina will gain Bad Weather at this level
private constant integer GAIN_AT_LEVEL = 20
endglobals
// The rain duration
private function GetDuratoin takes unit source, integer level returns real
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(source, ABILITY), ABILITY_RLF_DURATION_HERO, level - 1)
endfunction
// The bonus damage dealt (use different buffs per level in the debuff ability)
private function GetDamageBonus takes integer buffid returns real
if buffid == BUFF then
return 0.2
else
return 0.2
endif
endfunction
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private struct BadWeather
timer timer
unit unit
effect effect
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call UnitRemoveAbility(unit, DEBUFF)
call DestroyEffect(effect)
call DummyRecycle(unit)
call ReleaseTimer(timer)
call deallocate()
set timer = null
set unit = null
set effect = null
endmethod
private static method onDamage takes nothing returns nothing
if GetUnitAbilityLevel(Damage.target.unit, BUFF) > 0 and Damage.isEnemy then
call BlzSetEventDamage(GetEventDamage()*(1 + GetDamageBonus(BUFF)))
endif
endmethod
private static method onCast takes nothing returns nothing
local thistype this = thistype.allocate()
set timer = NewTimerEx(this)
set unit = DummyRetrieve(Spell.source.player, Spell.x, Spell.y, 0, 0)
set effect = AddSpecialEffectEx(MODEL, Spell.x, Spell.y, 0, SCALE)
call UnitAddAbility(unit, DEBUFF)
call TimerStart(timer, GetDuratoin(Spell.source.unit, Spell.level), false, function thistype.onExpire)
endmethod
private static method onLevelUp takes nothing returns nothing
local unit u = GetTriggerUnit()
if GAIN_AT_LEVEL > 0 then
if GetUnitTypeId(u) == JAINA_ID and GetHeroLevel(u) == GAIN_AT_LEVEL then
call UnitAddAbility(u, ABILITY)
call UnitMakeAbilityPermanent(u, true, ABILITY)
endif
endif
set u = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_LEVEL, function thistype.onLevelUp)
call RegisterSpellEffectEvent(ABILITY, function thistype.onCast)
call RegisterSpellDamageEvent(function thistype.onDamage)
endmethod
endstruct
endlibrary
scope Revive
private struct Revive
static method onDeath takes nothing returns nothing
local unit d = GetTriggerUnit()
local real x = GetUnitX(d)
local real y = GetUnitY(d)
if GetOwningPlayer(d) == Player(0) and IsUnitType(d, UNIT_TYPE_HERO) then
call ReviveHero(d, x, y, true)
endif
set d = null
endmethod
static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
endmethod
endstruct
endscope
scope Spawn
private struct Spawns
static constant real centerX = GetRectCenterX(gg_rct_Attack)
static constant real centerY = GetRectCenterY(gg_rct_Attack)
private static method Spawn takes real x, real y, integer melee, integer ranged returns nothing
local integer i = 0
local unit u
loop
exitwhen i > 3
if i < 3 then
set u = CreateUnit(Player(1), melee, x, y, 0)
else
set u = CreateUnit(Player(1), ranged, x, y, 0)
endif
call IssuePointOrderById(u, 851983, centerX, centerY)
set i = i + 1
endloop
set u = null
endmethod
private static method onPeriod takes nothing returns nothing
local integer i = 0
loop
exitwhen i > 3
if i == 0 then
call Spawn(GetRectCenterX(gg_rct_Human), GetRectCenterY(gg_rct_Human), 'hfoo', 'hrif')
elseif i == 1 then
call Spawn(GetRectCenterX(gg_rct_NightElf), GetRectCenterY(gg_rct_NightElf), 'esen', 'earc')
elseif i == 2 then
call Spawn(GetRectCenterX(gg_rct_Undead), GetRectCenterY(gg_rct_Undead), 'ugho', 'ucry')
elseif i == 3 then
call Spawn(GetRectCenterX(gg_rct_Orc), GetRectCenterY(gg_rct_Orc), 'ogru', 'ohun')
endif
set i = i + 1
endloop
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEventPeriodic(t, 45.00)
call TriggerAddAction(t, function thistype.onPeriod)
endmethod
endstruct
endscope
scope Camera initializer Init
private function AdjustCamera takes nothing returns nothing
local real dist = GetCameraField(CAMERA_FIELD_TARGET_DISTANCE)
local oskeytype pKey = BlzGetTriggerPlayerKey()
if pKey == OSKEY_HOME then
call SetCameraFieldForPlayer(Player(0), CAMERA_FIELD_TARGET_DISTANCE, dist + 25, 0.00)
call ClearTextMessages()
call DisplayTextToPlayer(Player(0), 0, 0, "Camera Distance: " + I2S(R2I(dist + 25)))
elseif pKey == OSKEY_END then
call SetCameraFieldForPlayer(Player(0), CAMERA_FIELD_TARGET_DISTANCE, dist - 25, 0.00)
call ClearTextMessages()
call DisplayTextToPlayer(Player(0), 0, 0, "Camera Distance: " + I2S(R2I(dist - 25)))
endif
set pKey = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), OSKEY_HOME, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), OSKEY_END, 0, false)
call TriggerAddCondition(t, Condition(function AdjustCamera))
//call Cheat("iseedeadpeople")
endfunction
endscope
scope OnDamage
private struct OnDamage
static method onDamage takes nothing returns nothing
local unit source = GetEventDamageSource()
local unit target
local real damage
local string text
local damagetype damage_type
local attacktype attack_type
if IsUnitType(source, UNIT_TYPE_HERO) then
set target = BlzGetEventDamageTarget()
set damage = GetEventDamage()
set text = R2I2S(damage)
if damage > 0 then
set damage_type = BlzGetEventDamageType()
set attack_type = BlzGetEventAttackType()
if damage_type == DAMAGE_TYPE_NORMAL then
call ArcingTextTag.create("|cffff0000" + text + "|r", target)
elseif attack_type == ATTACK_TYPE_NORMAL then
call ArcingTextTag.create("|cff00ffff" + text + "|r", target)
elseif damage_type == DAMAGE_TYPE_ENHANCED then
call ArcingTextTag.create("|cff00ff00" + text + "|r", target)
elseif damage_type == DAMAGE_TYPE_UNIVERSAL then
call ArcingTextTag.create(text, target)
else
call ArcingTextTag.create("|cffe4fd00" + text + "|r", target)
endif
elseif damage < 0 then
call ArcingTextTag.create("|cff00ff00 +" + text + "|r", target)
endif
endif
set source = null
set target = null
set damage_type = null
set attack_type = null
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(t, Condition(function thistype.onDamage))
endmethod
endstruct
endscope