/*
NovaSystem 2.02 By Adiktuz
Credits to Vexorian for dummy.mdx, J4L for T32,
Bribe for Table, SpellEffectEvent and Magtheridon96 for RegisterPlayerUnitEvent
Nestharus for WorldBounds
--------------------------------------------------------------------------------------------
Description:
A simple system that can be used to create:
1)An instant Nova
2)A targeted Nova
3)A time-delayed Nova
4)A Channeled spell which creates novas around you
5)A spell which creates novas around a target area over time
6)A non-channeled spell which creates novas around you
7)And some others
--------------------------------------------------------------------------------------------
How to Import
Copy Nova and the required libraries into your map
Export Dummy.mdx and import it to your map and create a dummy unit if you dont have one
Set the global DUMMY_ID to the rawcode of your dummy unit
--------------------------------------------------------------------------------------------
Editable Globals
DUMMY_ID = the rawcode of the dummy unit
TICK = the timer interval
FLY = the rawcode of Medivh's raven form
--------------------------------------------------------------------------------------------
How to use:
For very simple, 1-time Nova use this function
NovaSystem.simpleCreate(unit caster,real x, real y, real faoe,
real height, damage, real scale, string path, attacktype at, damagetype dt )
For very simple, 1-time Nova with time delay use this function
NovaSystem.simpleCreateDelay(unit caster,real x, real y, real delay, real faoe,
real height, damage, real scale, string path, attacktype at, damagetype dt )
For very simple, 1-time Nova with time delay + target use this function
NovaSystem.simpleCreateDelayTarget(unit caster, unit target, real x, real y, real delay, real faoe,
real height, damage, real scale, string path, attacktype at, damagetype dt )
For normal use, you just need to call the function
NovaSystem.create(parameters)
see the details below for what the parameters mean
Here are the parameters for the .create method arranged in order with details
unit caster - the unit casting the spell
unit target - the target unit of the spell
- if this has a value, the nova will follow the target
real x - the center x of the nova AOE
real y - the center y of the nova AOE
real aoe - the max distance that novas can be created from the center
real faoe - the radius of EACH nova's explosion
real height - the height of the nova special effect
integer npil - lowerbound of nova created per interval
integer npih - higherbound of nova created per interval
*amount of nova created per interval is randomized from npil to npih*
real ni - interval between nova creations, set this to a number higher than TICK
real ntt - the duration of the spell
real damage - the damage amount of each nova
real scalex - the x scale of the nova special effect
boolean channel - determines wheteher if nova spell is channeled
boolean oncast - whether novas will start on cast
-if false -> first set of novas will be created after ni
boolean follow ->determines if the caster will remain as the center of the AOE
*set it to true only for non-channeled no-target novas*
string path - the path to the nova special effect
attacktype at - the damage's attacktype
damagetype dt - the damage's damagetype
boolean circular - whether the AOE is circular or square, TRUE = circular, FALSE = Square
for the simple nova methods, it is set to true by default
integer abil - rawcode of the ability (used for the onXX events)
Note: I did not add a target method to the simpleCreate method because there is no point in that.
--------------------------------------------------------------------------------------------
Registering onXX events:
NovaSystem.registerOnDamage(integer abil, code action)
-> runs when a unit is damaged
NovaSystem.registerOnHit(integer abil, code action)
-> runs when a unit is hit (before filter is done, meaning it will run for ALL units around the nova)
NovaSystem.registerOnNova(integer abil, code action)
-> runs when a nova is created
NovaSystem.registerOnFinish(integer abil, code action)
-> runs when an instance of the Nova struct has ended
You can use NovaSystem.data to get the instance of Nova that triggered the events
Nova struct members that you can use:
real x
real y
unit caster
real aoe
real faoe
integer npih
integer npil
real ni
real ntc
real ntt
real nxi
boolean channel = false
real damage
string path
player owner
real scalex
boolean follow
real height
attacktype at
damagetype dt
boolean circular
integer abil
Sample:
NovaSystem.data.damage will return the damage value stored in that instance
Check the sample triggers for working examples
--------------------------------------------------------------------------------------------
The system automatically cancels a channeled nova when the caster moves, casts a new spell etc...
To cancel a channeled nova using other events, just use:
call NovaSystem.ForceCancel(unit caster)
*/
library Nova requires T32, Table, RegisterPlayerUnitEvent, MapBounds
globals
//Dummy ID
private constant integer DUMMY_ID = 'e000'
//TimerInterval
private constant real TICK = .03
//Rawcode of Medivh's raven form
private constant integer FLY = 'Amrf'
//Do not Edit
private group NOVA_GROUP = CreateGroup()
private Table NovaTable
private Table onDamageTable
private Table onNovaTable
private Table onFinishTable
private Table onHitTable
endglobals
module NSInit
static method onInit takes nothing returns nothing
set NovaTable = Table.create()
set onDamageTable = Table.create()
set onNovaTable = Table.create()
set onHitTable = Table.create()
set onFinishTable = Table.create()
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST, function thistype.Cancel)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.Cancel)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.Cancel)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.Cancel)
endmethod
endmodule
struct NovaSystem
real x
real y
unit caster
unit target
real aoe
real faoe
integer npih
integer npil
real ni
real ntc
real ntt
real nxi
boolean channel = false
real damage
string path
player owner
real scalex
boolean follow
real height
attacktype at
damagetype dt
boolean circular
integer abil
static real xx
static real yy
static thistype data
static thistype datu
static unit filter
static method registerOnDamage takes integer abil, code action returns nothing
if not onDamageTable.handle.has(abil) then
set onDamageTable.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(onDamageTable.trigger[abil], Filter(action))
endmethod
static method registerOnNova takes integer abil, code action returns nothing
if not onNovaTable.handle.has(abil) then
set onNovaTable.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(onNovaTable.trigger[abil], Filter(action))
endmethod
static method registerOnHit takes integer abil, code action returns nothing
if not onHitTable.handle.has(abil) then
set onHitTable.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(onHitTable.trigger[abil], Filter(action))
endmethod
static method registerOnFinish takes integer abil, code action returns nothing
if not onFinishTable.handle.has(abil) then
set onFinishTable.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(onFinishTable.trigger[abil], Filter(action))
endmethod
stub method OnHitFilter takes unit u returns boolean
return (IsUnitEnemy(u, this.owner) and GetWidgetLife(u) >= .405 and (IsUnitType(u, UNIT_TYPE_DEAD) != true))
endmethod
//The group loop that is run when a nova is created
static method Looper takes nothing returns boolean
set filter = GetFilterUnit()
if onHitTable.handle.has(data.abil) then
call TriggerEvaluate(onHitTable.trigger[data.abil])
endif
if data.OnHitFilter(filter) then
call UnitDamageTarget(data.caster, filter, data.damage, false, false, data.at, data.dt, null)
if onDamageTable.handle.has(data.abil) then
call TriggerEvaluate(onDamageTable.trigger[data.abil])
endif
endif
return false
endmethod
//For canceling a channeled nova using other triggers
static method ForceCancel takes unit u returns nothing
set datu = NovaTable[GetHandleId(u)]
if datu != 0 then
set datu.ntt = 0.00
endif
endmethod
//For canceling a channeled nova using the systems default events
static method Cancel takes nothing returns nothing
set datu = NovaTable[GetHandleId(GetTriggerUnit())]
if datu != 0 then
set datu.ntt = 0.00
endif
endmethod
method CreateNova takes nothing returns nothing
local unit efx = CreateUnit(Player(15), DUMMY_ID, xx, yy, 0.00)
if UnitAddAbility(efx, FLY) then
call UnitRemoveAbility(efx, FLY)
endif
call SetUnitScale(efx, this.scalex, 0, 0)
call SetUnitFlyHeight(efx, this.height, 0.00)
call DestroyEffect(AddSpecialEffectTarget(this.path, efx, "origin"))
call UnitApplyTimedLife(efx, 'BTLF', 1.00)
if onNovaTable.handle.has(data.abil) then
call TriggerEvaluate(onNovaTable.trigger[data.abil])
endif
call GroupEnumUnitsInRange(NOVA_GROUP, xx, yy, this.faoe, Condition(function NovaSystem.Looper))
set efx = null
endmethod
//Ensures that the X and Y are within map bounds
method GetPoint takes nothing returns nothing
local real angle = 0.0
local real range = GetRandomReal(0.0,this.aoe)
if this.circular then
set angle = GetRandomReal(0.0, 6.2832)
set xx = GetBoundedX(this.x + Cos(angle)*range)
set yy = GetBoundedY(this.y + Sin(angle)*range)
else
set xx = GetBoundedX(GetRandomReal(this.x - this.aoe, this.x + this.aoe))
set yy = GetBoundedY(GetRandomReal(this.y - this.aoe, this.y + this.aoe))
endif
endmethod
private method periodic takes nothing returns nothing
local integer a = 1
local integer b = 0
set data = this
set data.ntc = data.ntc + TICK
if data.ntc >= data.nxi then
set data.nxi = data.nxi + data.ni
set b = GetRandomInt(data.npil, data.npih)
loop
exitwhen a > b
if data.follow then
set data.x = GetUnitX(data.caster)
set data.y = GetUnitY(data.caster)
elseif data.target != null then
set data.x = GetUnitX(data.target)
set data.y = GetUnitY(data.target)
endif
call data.GetPoint()
call data.CreateNova()
set a = a + 1
endloop
endif
if data.ntc >= data.ntt then
call data.stopPeriodic()
if onFinishTable.handle.has(data.abil) then
call TriggerEvaluate(onFinishTable.trigger[data.abil])
endif
if data.channel then
call NovaTable.remove(GetHandleId(data.caster))
endif
call data.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, unit target, real x, real y, real aoe, real faoe, real height, integer npil,/*
*/integer npih, real ni, real ntt,real damage, real scale, boolean channel, boolean oncast,/*
*/boolean follow, string path, attacktype at, damagetype dt, boolean circular, integer abil returns thistype
local integer a = 1
local integer b = GetRandomInt(npil, npih)
set data = .allocate()
set data.caster = caster
set data.owner = GetOwningPlayer(caster)
set data.target = target
//Ensures that the initial x,y values are within map bounds
set data.x = GetBoundedX(x)
set data.y = GetBoundedY(y)
set data.follow = follow
set data.height = height
set data.aoe = aoe
set data.damage = damage
set data.channel = channel
set data.path = path
set data.npil = npil
set data.npih = npih
set data.ni = ni
set data.nxi= ni
set data.ntt = ntt
set data.scalex = scale
set data.faoe = faoe
set data.ntc = 0.00
set data.at = at
set data.dt = dt
set data.circular = circular
set data.abil = abil
if channel then
set NovaTable[GetHandleId(caster)] = data
endif
if oncast then
loop
exitwhen a > b
call data.GetPoint()
call data.CreateNova()
set a = a + 1
endloop
endif
call data.startPeriodic()
return data
endmethod
static method simpleCreate takes unit caster,unit target,real x, real y, real faoe, real height,/*
*/ real damage, real scale, string path, attacktype at, damagetype dt,integer abil returns thistype
return thistype.create(caster,null, x, y, 0.0, faoe, height, 1, 1, 0.0, 0.0,damage, scale, false, false, false, path, at, dt, TRUE,abil)
endmethod
static method simpleCreateDelay takes unit caster,real x, real y, real delay, real faoe, real height,/*
*/ real damage, real scale, string path, attacktype at, damagetype dt,integer abil returns thistype
return thistype.create(caster,null, x, y, 0.0, faoe, height, 1, 1, delay, delay,damage, scale, false, false, false, path, at, dt, TRUE,abil)
endmethod
static method simpleCreateDelayTarget takes unit caster, unit target,real x, real y, real delay, real faoe, real height,/*
*/ real damage, real scale, string path, attacktype at, damagetype dt,integer abil returns thistype
return thistype.create(caster,target, x, y, 0.0, faoe, height, 1, 1, delay, delay,damage, scale, false, false, false, path, at, dt, TRUE,abil)
endmethod
implement NSInit
endstruct
endlibrary