Name | Type | is_array | initial_value |
//TESH.scrollpos=34
//TESH.alwaysfold=0
library TimedLoop
//********************************************************
//* TimedLoop
//* ---------
//*
//* Requires jasshelper 0.9.G.1 or greater.
//*
//* A library + module that are meant to make those
//* array + timer loops easy, yet still faster than
//* other alternatives meant to be easy (In other words
//* no TriggerEvaluate is involved).
//*
//* The OOPness is interesting.
//*
//* Before implementing TimedLoop
//* your struct needs an onTimedLoop method that takes
//* nothing and returns boolean, if the method
//* returns false, the instance will get removed
//* from the loop and destroyed, else it will continue,
//* think of it as if the call asks the method a
//* question: "Should I continue the loop afterwards?"
//*
//* Alternatively, if you are not convinced, you may
//* use the TimedLoop_CONTINUE and TimedLoop_STOP
//* constants in the method's returns.
//*
//* After implementing TimedLoop, you can call
//* the startTimedLoop method to add the periodic event
//* to that instance, only call it once per instance.
//*
//* I recommend to call implement just bellow the
//* declaration of the onLoop method, else it will
//* actually use TriggerEvaluate, which is lame. Remind
//* me to implement a topsort in jasshelper.
//*
//* If you feel the need to destroy the struct outside
//* the loop, well, you'll have to add a flag to it so
//* you send a message to onLoop to make it return false.
//* A more complicated module to allow that easily would
//* come later.
//*
//********************************************************
//========================================================
// config:
globals
public constant real PERIOD = 0.025
// A lower value and everything using the module will
// look better, yet performance will drop.
endglobals
//========================================================
// implementation:
//
globals
public constant boolean STOP = false
public constant boolean CONTINUE = true
endglobals
//===========================
module TimedLoop
// god bless private module members.
//
private static thistype array V // The array
private static integer N = 0 // The count
private static timer T = null // the timer, one per
// struct that implements this
private static method onExpire takes nothing returns nothing
local integer n = 0
local thistype this // yay for odd-sounding syntax constructs
local integer i = 0
loop
exitwhen (i== thistype.N)
set this = .V[i]
if ( this.onTimedLoop() == CONTINUE ) then
set .V[n] = this
set n=n+1
else
call this.destroy()
endif
set i=i+1
endloop
set thistype.N = n
if (n== 0) then
call PauseTimer(.T)
endif
endmethod
public method startTimedLoop takes nothing returns nothing
set .V[.N] = this
set .N=.N + 1
if (.N == 1) then
if (.T == null) then
set .T = CreateTimer()
endif
call TimerStart(.T, PERIOD, true, function thistype.onExpire)
endif
endmethod
endmodule
endlibrary
//TESH.scrollpos=20
//TESH.alwaysfold=0
// Revive dead units
scope Revive initializer init
globals
private constant real time = 3.
private group G = CreateGroup()
private string FX = "Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl"
endglobals
private struct data
unit u
real x
real y
real f
static integer index = 0
static method Add takes nothing returns boolean
local data D = data.allocate()
set D.u = GetFilterUnit()
set D.x = GetUnitX(D.u)
set D.y = GetUnitY(D.u)
set D.f = GetUnitFacing(D.u)
set data.index = integer(D)
return true
endmethod
static method GetData takes unit u returns data
local integer i = 1
loop
exitwhen i > data.index
if u == data(i).u then
return data(i)
endif
set i = i + 1
endloop
return data(0)
endmethod
endstruct
private function Actions takes nothing returns nothing
local data D = data.GetData(GetTriggerUnit())
local player p = GetOwningPlayer(D.u)
local integer id = GetUnitTypeId(D.u)
if GetPlayerId(p) < 12 then
call TriggerSleepAction(3.)
else
call TriggerSleepAction(40.)
endif
call RemoveUnit(D.u)
call DestroyEffect(AddSpecialEffect(FX, D.x, D.y))
set D.u = CreateUnit(p, id, D.x, D.y, D.f)
endfunction
//===========================================================================
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddAction(t, function Actions)
set t = null
call GroupEnumUnitsInRect(G, GetWorldBounds(), Condition(function data.Add))
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
//***************************************************************************************************************
//* *
//* Runes Spell (vJASSified). *
//* By Moyack. *
//* V.2.3. *
//* *
//***************************************************************************************************************
//*
library Runes initializer init requires TimedLoop
//***************************************************************************************************************
//* The constant data where you can modify the ability properties
//*
globals
private constant integer SpellID = 'A000' // Returns the spell ID. Spell based on Serpent Ward
private constant integer RuneID = 'o000' // Returns the dummy summoned unit ID.
private constant attacktype AttackT = ATTACK_TYPE_SIEGE // Sets the Attack type deal to the units
private constant damagetype DamageT = DAMAGE_TYPE_NORMAL // Sets the Damage type deal to the units
endglobals
private constant function Range takes integer lvl returns real
return 120. + 50. * (lvl - 1) // Returns the range where the runes will detect units
endfunction
private constant function Radius takes integer lvl returns real
return 2 * Range(lvl) // Returns the radius where the runes will be placed
endfunction
private constant function Amount takes integer lvl returns integer
return 4 + 1 * (lvl - 1) // Returns the number of runes in the at the perimeter
endfunction
private constant function Damage takes integer lvl returns real
return 350. + 50. * (lvl - 1) // Returns the damage dealt to units near to the runes
endfunction
private constant function Duration takes integer lvl returns real
return 40. + 5. * (lvl - 1) // Returns the runes timed life
endfunction
//***************************************************************************************************************
//* end constant data...
//*
private function GetFX takes integer id returns string
return GetAbilityEffectById(SpellID, EFFECT_TYPE_SPECIAL, id)
endfunction
private struct rune
unit caster
player player
effect effect
real x
real y
real duration
integer level
static unit dummy
private method destroy takes nothing returns nothing
call DestroyEffect(.effect)
if .duration < Duration(.level) then
call DestroyEffect(AddSpecialEffect(GetFX(1), .x, .y))
call DestroyEffect(AddSpecialEffect(GetFX(2), .x, .y))
endif
endmethod
private method onTimedLoop takes nothing returns boolean
local unit u
set .duration = .duration + TimedLoop_PERIOD
call GroupEnumUnitsInRange(bj_lastCreatedGroup, .x, .y, Range(.level), null)
loop
set u = FirstOfGroup(bj_lastCreatedGroup)
exitwhen u == null
if GetUnitState(.caster, UNIT_STATE_LIFE) > 0.405 then
call UnitDamageTarget(.caster, u, Damage(.level), false, false, AttackT, DamageT, WEAPON_TYPE_ROCK_HEAVY_BASH)
return false
else
call SetUnitOwner(.dummy, .player, false)
call UnitDamageTarget(.dummy, u, Damage(.level), false, false, AttackT, DamageT, WEAPON_TYPE_ROCK_HEAVY_BASH)
return false
endif
call GroupRemoveUnit(bj_lastCreatedGroup, u)
endloop
if .duration > Duration(.level) then
return false
endif
return true
endmethod
implement TimedLoop
static method Start takes unit c, real x, real y returns nothing
local thistype R = thistype.allocate()
if IsPlayerAlly(GetLocalPlayer(), GetOwningPlayer(c)) then
set R.effect = AddSpecialEffect(GetFX(0), x, y)
else
set R.effect = AddSpecialEffect("Abilities\\Spells\\NightElf\\TreeofLifeUpgrade\\TreeofLifeUpgradeTargetArt.mdl", x, y) // shows an empty effect
endif
set R.caster = c
set R.player = GetOwningPlayer(c)
set R.x = x
set R.y = y
set R.level = GetUnitAbilityLevel(c, SpellID)
call R.startTimedLoop()
endmethod
endstruct
//***************************************************************************************************************
//* *
//* Runes Casting Functions *
//* *
//***************************************************************************************************************
private function Conditions takes nothing returns boolean
local unit c = GetSummoningUnit()
local unit r = GetSummonedUnit()
local real lx = GetUnitX(r)
local real ly = GetUnitY(r)
local real fc = GetUnitFacing(c) * bj_DEGTORAD
local real a = Amount(GetUnitAbilityLevel(c, SpellID))
local real R = Radius(GetUnitAbilityLevel(c, SpellID))
local real angle = 2 * bj_PI / a
local integer count = 0
local real x
local real y
if GetUnitTypeId(r) == RuneID then
call RemoveUnit(r)
call rune.Start(c, lx, ly)
loop
exitwhen count == a
set x = lx + R * Cos(fc + count * angle)
set y = ly + R * Sin(fc + count * angle)
call rune.Start(c, x, y)
set count = count + 1
endloop
endif
set c = null
set r = null
return false
endfunction
private function SetDummy takes nothing returns nothing
set rune.dummy = CreateUnit(Player(15), RuneID, 0,0,0)
call ShowUnit(rune.dummy, false)
call DestroyTimer(GetExpiredTimer())
endfunction
//===========================================================================
private function init takes nothing returns nothing
local trigger t= CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SUMMON )
call TriggerAddCondition( t, Condition( function Conditions ) )
call Preload(GetFX(0))
call Preload(GetFX(1))
call Preload(GetFX(2))
call TimerStart(CreateTimer(), 0., false, function SetDummy)
set t = null
endfunction
endlibrary