Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=1
library TNTI
private interface Ext
static integer Total = 0
static integer Current = 0
static constant real Intervall = .01
static timer TIM = null
real runtime = .01
method onBreak takes nothing returns boolean defaults true
method onLoop takes nothing returns nothing defaults nothing
endinterface
struct Indexable extends Ext
private static Ext array Index
private real timing = .0
/*stub method onBreak takes nothing returns boolean
call BJDebugMsg(SCOPE_PREFIX+": |c00FF0000onBreak() from struct with id: "+I2S(.getType())+" is not defined !")
return true
endmethod
stub method onLoop takes nothing returns nothing
call BJDebugMsg(SCOPE_PREFIX+": |c00FF0000onLoop() from struct with id: "+I2S(.getType())+" is not defined !")
endmethod*/
private method onDestroy takes nothing returns nothing
set Ext.Total = Ext.Total -1
set thistype.Index[Ext.Current] = thistype.Index[Ext.Total]
set Ext.Current = Ext.Current-1
if Ext.Total == 0 then
call PauseTimer(Ext.TIM)
endif
endmethod
private static method Loop takes nothing returns nothing
local Ext this
set Ext.Current = 0
loop
exitwhen Ext.Current == Ext.Total
set this = thistype.Index[Ext.Current]
set .timing = .timing + thistype.Intervall
if .timing >= .runtime then
if .onBreak() then
call .destroy()
else
call .onLoop()
set .timing = 0
endif
endif
set Ext.Current = Ext.Current+1
endloop
endmethod
static method create takes nothing returns thistype
local Ext this = thistype.allocate()
set thistype.Index[Ext.Total] = this
set Ext.Total = Ext.Total +1
if Ext.Total == 1 then
call TimerStart(Ext.TIM,Ext.Intervall,true, function thistype.Loop)
endif
return this
endmethod
private static method onInit takes nothing returns nothing
set Ext.TIM = CreateTimer()
endmethod
endstruct
endlibrary
//TESH.scrollpos=24
//TESH.alwaysfold=1
library TNTK requires TNTI
globals
private constant real OFFSET = 64.
private group MOTION_GRP
private real MAX
private real MAY
private real MIX
private real MIY
endglobals
struct TNTKnock extends Indexable
unit knocker = null
unit target = null
integer data = 0x0
boolean collision = false
private real runtime = 0.02
readonly real velx = .0
readonly real vely = .0
readonly boolean inuse = false
readonly real x = .0
readonly real y = .0
readonly real distance = 10.
readonly real radiants = .0
readonly real time = .0
readonly real speed = .0
static method IsInMotion takes unit u returns boolean
return IsUnitInGroup(u,MOTION_GRP)
endmethod
method IsInMap takes nothing returns boolean
return .x <= MAX and .x >= MIX and .y <= MAY and .y >= MIY
endmethod
stub method onKnock takes nothing returns nothing
if .collision then
call SetUnitPosition(.knocker,.x,.y)
else
call SetUnitX(.knocker,.x)
call SetUnitY(.knocker,.y)
endif
endmethod
method onBreak takes nothing returns boolean
return not .IsInMap() or .distance <= .speed+1. /*
*/ or ( .target != null and IsUnitType(.target ,UNIT_TYPE_DEAD)) /*
*/ or ( .knocker != null and IsUnitType(.knocker,UNIT_TYPE_DEAD))
endmethod
method onLoop takes nothing returns nothing
if .inuse then
if .target == null then
set .x = .x + velx
set .y = .y + vely
set .time = .time - .runtime
set .distance = .distance - .speed
else
set .velx = GetWidgetX(.target) - GetWidgetX(.knocker)
set .vely = GetWidgetY(.target) - GetWidgetY(.knocker)
set .radiants = Atan2(.vely,.velx)
set .distance = SquareRoot(.velx*.velx+.vely*.vely) - .speed
set .x = .x + Cos(.radiants) * .speed
set .y = .y + Sin(.radiants) * .speed
set .time = .time + .runtime
endif
call .onKnock()
endif
endmethod
method onDestroy takes nothing returns nothing
call GroupRemoveUnit(MOTION_GRP,.knocker)
set .knocker = null
set .target = null
set .inuse = false
endmethod
method ChangeSpeed takes real newspeed returns nothing
set velx = Cos(.radiants) * newspeed
set vely = Sin(.radiants) * newspeed
set .speed = newspeed
set .time = (.distance*.runtime)/newspeed
endmethod
method ChangeDirection takes real newrad returns nothing
set velx = Cos(newrad) * .speed
set vely = Sin(newrad) * .speed
set .radiants = newrad
endmethod
method Stop takes nothing returns nothing
set .inuse = true
set .distance = -1.
endmethod
method StartLinear takes unit u, real sx, real sy, real rad, real dis, real speed returns nothing
if speed > 1 and not .inuse then
set .knocker = u
set .target = null
set .x = sx
set .y = sy
set .distance = dis
set .radiants = rad
set .time = (dis*.runtime) / speed
set .speed = speed
set .velx = Cos(rad)*speed
set .vely = Sin(rad)*speed
set .inuse = true
call GroupAddUnit(MOTION_GRP,u)
endif
endmethod
method StartLinearTimed takes unit u, real sx, real sy, real rad, real dis, real time returns nothing
if time > .runtime and not .inuse then
set .knocker = u
set .target = null
set .x = sx
set .y = sy
set .distance = dis
set .radiants = rad
set .time = time
set .speed = (dis*.runtime) / time
set velx = Cos(rad) * .speed
set vely = Sin(rad) * .speed
set .inuse = true
call GroupAddUnit(MOTION_GRP,u)
endif
endmethod
method StartLinearTimedLoc takes unit u, location from, location to, real time, boolean noleak returns nothing
local real x = GetLocationX(to) - GetLocationX(from)
local real y = GetLocationY(to) - GetLocationY(from)
local real rad = Atan2(y,x)
local real dis = SquareRoot(x*x+y*y)
call .StartLinearTimed(u,GetLocationX(from),GetLocationY(from),rad,dis,time)
if noleak then
call RemoveLocation(from)
call RemoveLocation(to)
endif
endmethod
method StartHomingTimed takes unit u, unit targ, real sx, real sy, real speed returns nothing
if IsUnitType(targ,UNIT_TYPE_DEAD) != true and targ != null and speed > 0. then
set .knocker = u
set .target = targ
set .x = sx
set .y = sy
set .speed = speed
set .time = 0.
set .distance = speed+3.
set .inuse = true
call GroupAddUnit(MOTION_GRP,u)
endif
endmethod
private static method onInit takes nothing returns nothing
set MAX = GetRectMaxX(bj_mapInitialPlayableArea) - OFFSET
set MAY = GetRectMaxY(bj_mapInitialPlayableArea) - OFFSET
set MIX = GetRectMinX(bj_mapInitialPlayableArea) + OFFSET
set MIY = GetRectMinY(bj_mapInitialPlayableArea) + OFFSET
set MOTION_GRP = CreateGroup()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=1
library MirrorWard initializer Init uses TNTI,TNTK
globals
private constant integer SID = 'MrWr'
//The rawcode of the Spell
private constant integer DID = 'mwdu'
//The rawcode of the Ward
private constant integer RING_ELEMENTS = 20
//The amount of special effects which form the circle
private constant string RING_SFX = "Abilities\\Spells\\Human\\MagicSentry\\MagicSentryCaster.mdl"
//The model path of the special effect for the circle
private constant string DAMAGE_SFX = "Abilities\\Spells\\Human\\ManaFlare\\ManaFlareMissile.mdl"
//The model path of the special effect which will showup upon damaged enemies
private constant string END_SFX = "Units\\NightElf\\Wisp\\WispExplode.mdl"
//The model path of the special effect which appears when the ward is destroyed
private constant string DAMAGE_BONE= "overhead"
//The bone name where the DAMAGE_SFX will appear
private constant boolean FLASH_SFX = false
//Turn this on TRUE and the RING_SFX will created peridically (not very efficient)
//Turn this on FALSE and the RING_SFX´s will only be created when the ward spawns
//and will be removed when the ward dies
private constant real EFFECT_INTERVALL = 0.2
//The recreation intervall for the RING_SFX. You don´t need this if you turnded
//FLASH_SFX on false
private constant real DAMAGE_INTERVALL = 0.4
//The intervall in which the enemies inside the circle get damad
private constant real MOVE_SPEED = 17.5
//The movespeed of the enemy unit when it´s knocked back to the center
private constant boolean COLLISION = true
//Determines if the enemy units have collision turned on or off when the are
//knocked back to the center
//Damage Settings - Should be selfexplaining
private constant attacktype ATTACK_TYPE = null
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_UNIVERSAL
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
private group TEMP_GROUP = CreateGroup()
//An enumaration group to detect enemies
private filterfunc ENUM_FILTER
//Enumaration filter for the enemies
endglobals
//The Area of Effct of the ward
private constant function GetAoERange takes real level returns real
return level * 0 + 400
endfunction
//The amount of damage dealt to the enemies per second
private constant function GetDamage takes real level returns real
return level * 5 + 2
endfunction
//How long should the ward stay ?
private constant function GetDuration takes real level returns real
return level * 10 + 5
endfunction
private struct Spell extends Indexable
static thistype temp
real runtime = 0.03
unit ward
player owner
effect array fx [RING_ELEMENTS]
real sfx_intervall = 0.0
real dmg_intervall = 0.0
real damage
real range
real x
real y
method onDestroy takes nothing returns nothing
local integer i = 0
static if not FLASH_SFX then
loop
exitwhen i == RING_ELEMENTS
call DestroyEffect(.fx[i])
set i = i +1
endloop
endif
call DestroyEffect(AddSpecialEffect(END_SFX,.x,.y))
endmethod
//The spell ends when the ward is dead or is being removed from the game
method onBreak takes nothing returns boolean
return IsUnitType(.ward,UNIT_TYPE_DEAD) or .ward == null
endmethod
//Will draw the circle effect. The way it works depends on FLASH_SFX
method DrawRing takes nothing returns nothing
local real step = (2*bj_PI)/RING_ELEMENTS
local real rad = 0.0
local integer i = 0
loop
static if FLASH_SFX then
exitwhen rad >= 2*bj_PI
call DestroyEffect(AddSpecialEffect(RING_SFX,.x+.range*Cos(rad),.y+.range*Sin(rad)))
else
exitwhen i == RING_ELEMENTS
set .fx[i] = AddSpecialEffect(RING_SFX,.x+.range*Cos(rad),.y+.range*Sin(rad))
set i = i+1
endif
set rad = rad + step
endloop
endmethod
//Does some timing stuff and the enumarations. And may updates the circle
method onLoop takes nothing returns nothing
static if FLASH_SFX then
if .sfx_intervall <= 0. then
call .DrawRing()
set .sfx_intervall = EFFECT_INTERVALL
else
set .sfx_intervall = .sfx_intervall - .runtime
endif
endif
if .dmg_intervall <= 0. then
set .dmg_intervall = DAMAGE_INTERVALL
else
set .dmg_intervall = .dmg_intervall - .runtime
endif
set thistype.temp = this
call GroupEnumUnitsInRange(TEMP_GROUP,.x,.y,.range*1.15, ENUM_FILTER)
//NOTE: .range*1.15 will generate a buffer zone.
endmethod
//Creator method
static method create takes unit c,real x, real y returns thistype
local thistype this = thistype.allocate()
local integer lv = GetUnitAbilityLevel(c,SID)
set .owner = GetOwningPlayer(c)
set .ward = CreateUnit(.owner,DID,x,y,0)
set .damage = GetDamage(lv) * DAMAGE_INTERVALL
set .range = GetAoERange(lv)
set .x = x
set .y = y
call UnitApplyTimedLife(.ward,'BTLF',GetDuration(lv))
static if not FLASH_SFX then
call .DrawRing()
endif
return this
endmethod
endstruct
//Enumaration function to detect the enemies
private function EnumFilterFunc takes nothing returns boolean
local unit u = GetFilterUnit()
local Spell this = Spell.temp
local TNTKnock knock
local real x = GetWidgetX(u) - this.x
local real y = GetWidgetY(u) - this.y
local real d = SquareRoot(x*x+y*y)
//If the unit is a valid target
if IsUnitEnemy(u,this.owner) and not( IsUnitType(u,UNIT_TYPE_DEAD) or IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE) or IsUnitType(u,UNIT_TYPE_STRUCTURE) or IsUnitType(u,UNIT_TYPE_ANCIENT) ) then
//and it´s time to deal damage
if this.dmg_intervall <= 0. then
call UnitDamageTarget(this.ward,u,this.damage,false,false,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE)
call DestroyEffect(AddSpecialEffectTarget(DAMAGE_SFX,u,DAMAGE_BONE))
endif
//If the unit is about to leave the circle
if d > this.range*0.85 and not TNTKnock.IsInMotion(u) then
//NOTE: .range*0.85 will work like a buffer zone.
set knock = TNTKnock.create()
call knock.StartLinear(u,x+this.x,y+this.y,Atan2(y,x)+bj_PI,d,MOVE_SPEED)
set knock.collision = COLLISION
endif
endif
set u = null
return false
endfunction
//Will start the spell
private function onCast takes nothing returns nothing
call Spell.create(GetTriggerUnit(),GetSpellTargetX(),GetSpellTargetY())
endfunction
//Will check for the correct rawcode
private function onCheck takes nothing returns boolean
return GetSpellAbilityId() == SID
endfunction
//Initializer
private function Init takes nothing returns nothing
local trigger trig = CreateTrigger()
set ENUM_FILTER = Filter( function EnumFilterFunc)
//Preloading cosmetics
call Preload(RING_SFX)
call Preload(DAMAGE_SFX)
call Preload(END_SFX)
call PreloadStart()
//Trigger register stuff
call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(trig, Filter( function onCheck))
call TriggerAddAction(trig, function onCast)
set trig = null
endfunction
endlibrary