/*
Super Frost Joke by Adiktuz
Description:
The caster cracks a joke which can freeze enemy units around him
Configurables:
-The jokes
-The chances of freezing for each joke
-The duration of the freeze
-The targets of the freeze
-The damage of the freeze
-The AoE of the freeze
How to import:
-Copy and paste this code into your trigger editor
-Copy the two abilities and the buff
-Create a dummy caster if you don't have one or copy the one on this map
-Change the rawcodes to fit the new rawcodes on your map
-Edit the configurables to your liking
-Add your jokes using [function RegisterJokes takes string joke, real chance]
*examples given on InitJokes trigger
IMPORTANT: On the gameplay constants, set the UNIT MIN MOVESPEED to 0.00
Credits:
Jesus4Lyf for Timer32
*/
library SuperFrostJoke initializer Init requires T32
globals
//The rawcode of the Frost joke spell
private constant integer FJ_SPELL_ID = 'A000'
//The rawcode of the frost joke buff placer (the soulburn-based ability)
private constant integer FJ_BUFFPLACER_ID = 'A001'
//The rawcode of the frost joke buff which the buffplacer uses
private constant integer FJ_BUFF_ID = 'B000'
//The rawcode of the dummy unit
private constant integer DUMMY_ID = 'h000'
//Checks if the FJ deals damage, if yes be sure to set the damage amount at the function below the globals
private constant boolean DEALS_DAMAGE = false
//Checks if the FJ deals damage after the duration, if yes be sure to set the damage amount at the function below the globals
private constant boolean DEALS_END_DAMAGE = true
/*
Checks if the duration of the buff will stack if a unit gets hit by SFJ while still
being affected by a previous one, if false, the new cast will overwrite the older one
*/
private constant boolean STACK_TIME = false
//The attack type of the primary damage
private constant attacktype ATPD = ATTACK_TYPE_NORMAL
//The damage type of the primary damage
private constant damagetype DTPD = DAMAGE_TYPE_NORMAL
//The attack type of the secondary damage
private constant attacktype ATSD = ATTACK_TYPE_NORMAL
//The damage type of the secondary damage
private constant damagetype DTSD = DAMAGE_TYPE_NORMAL
//DO NOT EDIT BELOW THIS LINE UP TO THE NEXT COMMENT
private string array FrostJokes //[8190]
private real array FrostChances //[8190]
private integer JokesTotal = 0
private group FJ_Group = CreateGroup()
private boolean array IsJokeShown
private hashtable SFJ_Hash = InitHashtable()
//END of DO NOT EDIT
endglobals
//Set the damage formula using this function
private function GetDamage takes integer level returns real
return 0.00
endfunction
//Set the end damage formula using this function
private function GetEndDamage takes integer level returns real
return 75.00*level
endfunction
//Set the buff duration using this function
private function GetDuration takes integer level returns real
return 5.00
endfunction
//Set the chance formula using this function
private function GetChance takes integer level, integer index returns real
return FrostChances[index]
endfunction
//Set The AoE formula using this function
private function GetAoE takes integer level returns real
return 250.00*level
endfunction
//The frost joke struct which handles most of the system's work
private struct FrostJokeStruct
unit target //the units hit by SFJ
unit caster //the caster of SFJ
integer abillevel //the ability level of SFJ for the caster
real timeleft //the timeleft for the duration of the buff
static thistype data
static unit TempUnit = null
static unit FiltUnit = null
static unit TempCaster = null
static real chance = 0.00
static integer joke
static integer level
static integer playern
static player controller
static integer id
/*
the periodic method for the buff duration, executed by T32
*/
private method periodic takes nothing returns nothing
set this.timeleft = this.timeleft - T32_PERIOD
if this.timeleft <= 0.00 then
call this.stopPeriodic()
call UnitRemoveAbility(this.target, FJ_BUFFPLACER_ID)
call UnitRemoveAbility(this.target, FJ_BUFF_ID)
call FlushChildHashtable(SFJ_Hash, GetHandleId(this.target))
if DEALS_END_DAMAGE then
call UnitDamageTarget(this.caster, this.target, GetEndDamage(this.abillevel), false, false, ATPD, DTPD, null)
endif
call this.destroy()
endif
endmethod
//implements the T32x module
implement T32x
/*
the method run when a unit gets hit by the SFJ
*/
static method create takes unit target, unit caster, integer level returns thistype
set thistype.id = GetHandleId(target)
set data = LoadInteger(SFJ_Hash, thistype.id, 0)
/*
if the unit is currently unaffected by a SFJ, a new instance is created
else we override the current one or increase the time depending
on the global STACK_TIME
*/
if data == 0 then
set data = thistype.allocate()
set data.target = target
set data.caster = caster
set data.abillevel = level
set data.timeleft = GetDuration(level)
set thistype.TempCaster = CreateUnit(GetOwningPlayer(caster), DUMMY_ID,GetUnitX(caster), GetUnitY(caster), 0.00)
call UnitApplyTimedLife(thistype.TempCaster, 'BTLF', .5)
call SetUnitExploded(thistype.TempCaster, true)
call UnitAddAbility(thistype.TempCaster, FJ_BUFFPLACER_ID)
call IssueTargetOrder(thistype.TempCaster, "soulburn", target)
call data.startPeriodic()
call SaveInteger(SFJ_Hash, thistype.id, 0, data)
else
set data.target = target
set data.caster = caster
set data.abillevel = level
if STACK_TIME then
set data.timeleft = data.timeleft + GetDuration(level)
else
set data.timeleft = GetDuration(level)
endif
endif
if DEALS_DAMAGE then
call UnitDamageTarget(caster, target, GetDamage(level), false, false, ATPD, DTPD, null)
endif
return data
endmethod
/*
this method checks if a unit will get affected by the SFJ or not
*/
static method FrostJokeGroupLoop takes nothing returns boolean
set thistype.FiltUnit = GetFilterUnit()
set thistype.controller = GetOwningPlayer(FiltUnit)
set thistype.playern = GetPlayerId(thistype.controller)
if not IsJokeShown[thistype.playern] then
set IsJokeShown[thistype.playern] = true
call DisplayTextToPlayer(thistype.controller, 0, 0, FrostJokes[thistype.joke])
endif
//checks if the unit is alive
if GetWidgetLife(FiltUnit) > .405 and /*
checks if the unit is an enemy
*/ IsPlayerEnemy(thistype.controller, GetOwningPlayer(thistype.TempUnit)) and /*
checks if the unit will be frozen
*/ GetRandomReal(0.00, 100.00) <= thistype.chance then
call FrostJokeStruct.create(FiltUnit, thistype.TempUnit ,thistype.level)
endif
return false
endmethod
/*
this method picks every unit around the caster of SFJ and passes them to the method above
*/
static method FrostJoke takes nothing returns boolean
local integer i = 0
set thistype.TempUnit = GetTriggerUnit()
set thistype.level = GetUnitAbilityLevel(thistype.TempUnit, FJ_SPELL_ID)
set thistype.joke = GetRandomInt(0, JokesTotal)
set thistype.chance = GetChance(thistype.level, thistype.joke)
if GetSpellAbilityId() == FJ_SPELL_ID then
call GroupEnumUnitsInRange(FJ_Group, GetUnitX(thistype.TempUnit), GetUnitY(thistype.TempUnit), GetAoE(thistype.level), Condition(function thistype.FrostJokeGroupLoop))
endif
loop
exitwhen i > 15
set IsJokeShown[i] = false
set i = i + 1
endloop
return false
endmethod
endstruct
//The init method of this library
private function Init takes nothing returns nothing
local integer i = 0
local trigger t = CreateTrigger()
loop
exitwhen i > 15
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set i = i + 1
endloop
call TriggerAddCondition(t, Condition(function FrostJokeStruct.FrostJoke))
set t = null
endfunction
//The function used to register jokes
function RegisterJokes takes string joke, real chance returns nothing
set FrostJokes[JokesTotal] = joke
set FrostChances[JokesTotal] = chance
set JokesTotal = JokesTotal + 1
endfunction
endlibrary