//***************************************************************************
//***************************************************************************
//***************************************************************************
// L O T U S I C E
// By: Elphis (Nyuu)
// Version: 1.0
//
// Sepll Description:
// ` - Using the power of frost, ice beam summons on the ground at the same time creating freezing weather,
// after the ice beam achieve maximum strength, it immediately ice scrapers on the ground, any enemies in range
// 300, it will pierce, and push enemies out of range, and every 0.2 seconds, it will emit a stream of ejected ice,
// freezing enemies, and those who freezes in 500 range, it will pull enemy into the deep of the ice place.
//
// Damage level 1: 1.5
// Damage level 2: 3
// Damage level 3: 4.5
// Damage level 4: 6
// - Installation:
// - Import/copy Lotus Ice code to your map
// - Import/copy the custom ability and unit to your map and change the SPELL_ID, DUMMY_CASTER, DUMMY_DEG_1, DUMMY_DEG_2, DUMMY_DEG_3 and DUMMY_MISSLE if needed
// - You may view the raw ID of the objects by pressing CTRL+D in the object editor
// - You may play with the configurables below
//
//
//***************************************************************************
//***************************************************************************
//***************************************************************************
library LotusIce
globals
private constant real PERIODIC = .031250000
//Spell rawcode, change if needed
private constant integer SPELL_ID = 'A000'
//Dummy 1 rawcode, change if needed
private constant integer DUMMY_DEG_1 = 'e000'
//Dummy 2 rawcode, change if needed
private constant integer DUMMY_DEG_2 = 'e001'
//Dummy 3 rawcode, change if needed
private constant integer DUMMY_DEG_3 = 'e002'
//Dummy missle rawcode, change if needed
private constant integer DUMMY_MISSLE = 'e003'
//Dummy caster rawcode, change if needed
private constant integer CASTER_DUMMY = 'e004'
//Buff rawcode, change if needed
private constant integer BUFF_ID = 'B000'
//Weather type when spell is active
private constant integer WEATHER_TYPE = 'SNhs'
//Total ice count
private constant integer DUMMY_COUNT = 10
//Frost effect count random number, incease => laggy, decrease => ice fairy
private constant integer EFFECT_NUMBER = 2
//Total wave of frost
private constant integer FROST_COUNT = 4
//Damage base of spell, increase => instantly dead, decrease => you dead
private constant real DAMAGE_BASE = 1.5
//Push unit radius
private constant real KNOCK_RADIUS = 300.
//Damage radius, increase => incredible spell, decrease => useless spell
private constant real DMG_RADIUS = 100.
//Pull unit when the enemies has freezed
private constant real PULL_RANGE = 500.
//Push speed, increase => fast push, decrease => slow push
private constant real ENEMIES_KNOCK = 5.
//Pull unit speed
private constant real ENEMIES_PULL = 0.5
//Frost missle speed
private constant real MISSLE_SPEED = 20.
//Main ice scale
private constant real ICE_SCALE_1 = 2.
//Second ice scale
private constant real ICE_SCALE_2 = 1.
//Third ice scale
private constant real ICE_SCALE_3 = 1.
//Scale increase per periodic
private constant real SCALE_PER_PERIOD= .07
private constant real ICE_AREA_1 = 150.
private constant real ICE_AREA_2 = 200.
private constant real RANGE_MISSLE_1 = 600.
private constant real RANGE_MISSLE_2 = 700.
//Range increase per wave of frost
private constant real RANGE_PER_PERIOD= 150.
//Freeze radius when the wave of frost is active
private constant real FREEZE_RADIUS = 150.
//Frost wave intevar
private constant real FROST_INTEVAR = 0.1
//Damage intevar
private constant real DAMAGE_INTEVAR = 0.5
//Lotus ice spell duration
private constant real LOTUS_DURATION = 3.
//Frost of wave repeat time
private constant real FROST_REPEAT = 0.8
//Frost effect
private constant string ICE_EFFECT = "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl"
//Order id of dummy spell
private constant string ORDER_ID = "thunderbolt"
//Create a dummy on init function, so this spell never create dummy again
private constant boolean DO_DUMMY_INIT = true
//******************************DAMAGE DATA SETTINGS******************************
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_DEATH
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_CLAW_HEAVY_SLICE
//********************************************************************************
//***************************Non - Configurable*****************************
/* */
/**/private integer MUI = -1 /**/
/* */
/**/private constant timer TIMER = CreateTimer() /**/
/* */
/**/private constant timer TIMER_2 = CreateTimer() /**/
/* */
/**/private integer array StructData /**/
/* */
/**/private integer PMUI = -1 /**/
/* */
/**/private integer array PStructData /**/
/* */
/**/private integer TMUI = -1 /**/
/* */
/**/private integer array TStructData /**/
/* */
/**/private group G = CreateGroup() /**/
/* */
/**/private unit Dummy /**/
/* */
/**/private real Main_Time = 0. /**/
/* */
/**/private rect RECT = Rect(0.,0.,0.,0.) /**/
/* */
//***************************************************************************
/**/private constant real FACING = ICE_AREA_1+ICE_AREA_2/**/
/**/private constant real MAX_COUNT = DUMMY_COUNT*2 /**/
//***************************************************************************
endglobals
//Damage settings********************************************
constant function damageSetting takes integer lvl returns real
return DAMAGE_BASE*lvl
endfunction
//************************************************************
//Duration settings*******************************************
constant function durationSetting takes integer lvl returns real
return LOTUS_DURATION+lvl
endfunction
//************************************************************
//Conditions function*****************************************
constant function conditionFunc takes player caster_owner,unit other returns boolean
/**/ //Assure a better death check//
/**/return IsUnitEnemy(other,caster_owner) and /**/GetUnitTypeId(other) != 0/**/and not IsUnitType(other,UNIT_TYPE_DEAD)
endfunction
//************************************************************
private struct LotusIce
unit dummy
weathereffect weather
real vinc
real value_inc
real frost_rep
real frost_int
real frost_inc
real ag
real gx
real gy
real lotus_dur
boolean frost_active = false
boolean spell_active = true
integer frost_count = FROST_COUNT
integer fade
integer value_fade = 0
player playe
static method onPeriodic takes nothing returns nothing
local integer i = 0
local integer l = 0
local real a
local real x
local real y
local unit f = null
local thistype this
loop
exitwhen i > MUI
set this = StructData[i]
if spell_active then
if value_inc < ICE_SCALE_1 then
set value_inc = value_inc + vinc
set value_fade = value_fade + fade
call SetUnitScale(dummy,value_inc,0.,0.)
call SetUnitVertexColor(dummy,255,255,255,value_fade)
else
if lotus_dur > 0. then
set lotus_dur = lotus_dur - PERIODIC
set Main_Time = lotus_dur
if frost_rep < FROST_REPEAT and frost_count == FROST_COUNT then
set frost_rep = frost_rep + PERIODIC
else
set frost_rep = 0.
set frost_active = true
endif
if frost_active then
if frost_int < FROST_INTEVAR then
set frost_int = frost_int + PERIODIC
else
set frost_int = 0.
if frost_count > 0 then
set frost_inc = frost_inc + RANGE_PER_PERIOD
set frost_count = frost_count - 1
static if not DO_DUMMY_INIT then
set Dummy = CreateUnit(Player(15),CASTER_DUMMY,0.,0.,0.)
endif
loop
exitwhen i > DUMMY_COUNT
set a = .0174533*i*ag
set x = gx + frost_inc * Cos(a)
set y = gy + frost_inc * Sin(a)
call DestroyEffect(AddSpecialEffect(ICE_EFFECT,x,y))
call GroupEnumUnitsInRange(G,x,y,FREEZE_RADIUS,null)
loop
set f = FirstOfGroup(G)
exitwhen f == null
if conditionFunc(playe,f) then
call SetUnitX(Dummy,GetUnitX(f))
call SetUnitY(Dummy,GetUnitY(f))
call IssueTargetOrder(Dummy,ORDER_ID,f)
endif
call GroupRemoveUnit(G,f)
endloop
set i = i + 1
endloop
static if not DO_DUMMY_INIT then
call RemoveUnit(Dummy)
endif
else
set frost_inc = 0.
set frost_count = FROST_COUNT
set frost_active = false
endif
endif
endif
else
set spell_active = false
endif
endif
elseif value_inc > 0. then
set value_inc = value_inc - vinc
set value_fade = value_fade - fade
call SetUnitScale(dummy,value_inc,0.,0.)
call SetUnitVertexColor(dummy,255,255,255,value_fade)
else
set StructData[i] = StructData[MUI]
set StructData[MUI] = -2
set MUI = MUI - 1
if MUI == -1 then
call PauseTimer(TIMER)
endif
call RemoveUnit(dummy)
call RemoveWeatherEffect(weather)
set weather = null
set dummy = null
set playe = null
call destroy()
endif
set i = i + 1
endloop
endmethod
static method onCast takes nothing returns boolean
local thistype this
local integer i
local integer l
local integer alvl
local integer unitid
local real dx
local real dy
local real angle
local real cs
local real sc
local real rg
local real icea
local real cos
local real sin
local unit caster
if GetSpellAbilityId() != SPELL_ID then
set caster = null
return false
endif
set this = allocate()
set MUI = MUI + 1
set StructData[MUI] = this
set playe = GetTriggerPlayer()
set caster = GetTriggerUnit()
set gx = GetSpellTargetX()
set gy = GetSpellTargetY()
call SetRect(RECT,gx-FACING,gy-FACING,gx+FACING,gy+FACING)
set weather = AddWeatherEffect(RECT,WEATHER_TYPE)
call EnableWeatherEffect( weather, true )
set alvl = GetUnitAbilityLevel(caster,SPELL_ID)
set lotus_dur = durationSetting(alvl)
set ag = 360./DUMMY_COUNT
set i = 0
set fade = R2I(255./RANGE_MISSLE_2*MISSLE_SPEED)
set dummy = CreateUnit(Player(15),DUMMY_DEG_1,gx,gy,0.)
call SetUnitScale(dummy,0.,0.,0.)
call SetUnitVertexColor(dummy,255,255,255,0)
loop
exitwhen i > MAX_COUNT
if i < DUMMY_COUNT then
set cs = .0174533*i*ag
set cos = Cos(cs)
set sin = Sin(cs)
set rg = RANGE_MISSLE_1
set frost_int = gx + FACING * cos
set frost_inc = gy + FACING * sin
set value_inc = gx + rg * cos
set frost_rep = gy + rg * sin
set unitid = DUMMY_DEG_2
set icea = ICE_AREA_1
set dx = gx + icea * cos
set dy = gy + icea * sin
set sc = ICE_SCALE_2
else
set rg = RANGE_MISSLE_2
set l = i - DUMMY_COUNT
set cs = .0174533*l*ag
set cos = Cos(cs)
set sin = Sin(cs)
set frost_int = gx + FACING * cos
set frost_inc = gy + FACING * sin
set value_inc = gx + rg * cos
set frost_rep = gy + rg * sin
set unitid = DUMMY_DEG_3
set rg = RANGE_MISSLE_2
set icea = ICE_AREA_2
set dx = gx + icea * cos
set dy = gy + icea * sin
set sc = ICE_SCALE_3
endif
set angle = 57.29583 * Atan2(frost_inc - dy, frost_int - dx)
set vinc = 57.29583 * Atan2(gy - frost_rep, gx - value_inc)
call LotusIce_LotusIcePlugin.add(CreateUnit(Player(15),DUMMY_MISSLE,value_inc,frost_rep,vinc),unitid,dx,dy,angle,vinc,rg,icea,sc,gx,gy,i,damageSetting(alvl),playe,caster,dummy)
set i = i + 1
endloop
set value_inc = 0.
set frost_rep = 0.
set frost_int = 0.
set frost_inc = 0.
set vinc = ICE_SCALE_1/RANGE_MISSLE_2*MISSLE_SPEED
if MUI == 0 then
call TimerStart(TIMER,PERIODIC,true,function thistype.onPeriodic)
endif
set caster = null
return false
endmethod
static method onInit 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,function thistype.onCast)
static if DO_DUMMY_INIT then
set Dummy = CreateUnit(Player(15),CASTER_DUMMY,0.,0.,0.)
endif
endmethod
endstruct
public struct LotusIcePlugin
unit dummy
unit caster
unit mdummy
integer dummyid
integer count
boolean spell_active = true
player playe
real scale = 0.
real dmg
real tx
real ty
real dx
real dy
real df
real cos
real sin
real maxsc
real icearea
real distance
real dmg_int = 0.
static method onPeriodic takes nothing returns nothing
local integer i = 0
local real a
local real x
local real y
local boolean pull
local boolean dmg_active = false
local unit f = null
local thistype this
loop
exitwhen i > PMUI
set this = PStructData[i]
if spell_active then
if distance > icearea then
set distance = distance - MISSLE_SPEED
set x = GetUnitX(dummy) + MISSLE_SPEED * cos
set y = GetUnitY(dummy) + MISSLE_SPEED * sin
call SetUnitX(dummy,x)
call SetUnitY(dummy,y)
elseif scale < maxsc then
if GetUnitTypeId(dummy) > 0 then
if GetRandomInt(0,100) <= EFFECT_NUMBER then
call DestroyEffect(AddSpecialEffect(ICE_EFFECT,dx,dy))
endif
call RemoveUnit(dummy)
set dummy = CreateUnit(Player(15),dummyid,dx,dy,df)
call SetUnitScale(dummy,0.,0.,0.)
endif
set scale = scale + SCALE_PER_PERIOD
call SetUnitScale(dummy,scale,0.,0.)
else
if dmg_int < DAMAGE_INTEVAR then
set dmg_int = dmg_int + PERIODIC
else
set dmg_int = 0.
set dmg_active = true
endif
if GetUnitAbilityLevel(f,BUFF_ID) == 0 then
call GroupEnumUnitsInRange(G,dx,dy,KNOCK_RADIUS,null)
set pull = false
else
call GroupEnumUnitsInRange(G,dx,dy,PULL_RANGE,null)
set pull = true
endif
loop
set f = FirstOfGroup(G)
exitwhen f == null
if conditionFunc(playe,f) then
set x = GetUnitX(f)
set y = GetUnitY(f)
if GetUnitAbilityLevel(f,BUFF_ID) == 0 then
set df = 57.29583 * Atan2(y - dy,x - dx)
set a = .0174533*df
set x = x + ENEMIES_KNOCK * Cos(a)
set y = y + ENEMIES_KNOCK * Sin(a)
else
set df = 57.29583 * Atan2(dy - y,dx - x)
set a = .0174533*df
set x = x + ENEMIES_PULL * Cos(a)
set y = y + ENEMIES_PULL * Sin(a)
endif
call SetUnitX(f,x)
call SetUnitY(f,y)
endif
call GroupRemoveUnit(G,f)
endloop
if dmg_active then
call GroupEnumUnitsInRange(G,dx,dy,DMG_RADIUS,null)
loop
set f = FirstOfGroup(G)
exitwhen f == null
if conditionFunc(playe,f) then
call UnitDamageTarget(caster,f,dmg,true,false,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE)
endif
call GroupRemoveUnit(G,f)
endloop
endif
if GetUnitTypeId(mdummy) == 0 then
set spell_active = false
endif
endif
elseif scale > 0. then
set scale = scale - SCALE_PER_PERIOD
call SetUnitScale(dummy,scale,0.,0.)
else
set PStructData[i] = PStructData[PMUI]
set PStructData[PMUI] = -2
set PMUI = PMUI - 1
if PMUI == -1 then
call PauseTimer(TIMER_2)
endif
call RemoveUnit(dummy)
set dummy = null
set caster = null
set playe = null
call destroy()
endif
set i = i + 1
endloop
endmethod
static method add takes unit u,integer unitid,real x,real y,real f,real f1,real rg,real icea,real sc,real t,real tt,integer c,real damage,player p,unit ct,unit maind returns nothing
local thistype this = allocate()
set PMUI = PMUI + 1
set PStructData[PMUI] = this
set maxsc = sc
set dummy = u
set dummyid = unitid
set dx = x
set dy = y
set df = f
set cos = Cos(.0174533*f1)
set sin = Sin(.0174533*f1)
set icearea = icea
set distance = rg
set count = c
set tx = t
set ty = tt
set dmg = damage
set playe = p
set caster = ct
set mdummy = maind
if PMUI == 0 then
call TimerStart(TIMER_2,PERIODIC,true,function thistype.onPeriodic)
endif
endmethod
endstruct
endlibrary