scope FrostWyrm //version 1.1
/*---------------------------------------------------------------------------------------------------------
*
* Requires:
*
*-----------------------------------------------------------------------------------------------------------
*
* - CTL [By Nestharus]
* - WorldBounds [By Nestharus]
* - IsDestructableTree [By PitzerMike]
* - SpellEffectEvent [By Bribe]
* - RegisterPlayerUnitEvent [By Magtheridon9]
*
*-----------------------------------------------------------------------------------------------------------
*
* How to import:
*
*-----------------------------------------------------------------------------------------------------------
*
* - Copy Frost wyrm Ability from object editor ---> Abilities
* - Copy Frost wyrm (Freeze) Ability from objest editor ---> Abilities
* - Copy Frost wyrm (Freeze) Buff from object editor ---> Buffs/Effects
* - Copy Frost wyrm - Dummy 1 from objedt editor ---> Units
* - Copy Frost wyrm - Dummy 2 from object editor ---> Units
* - Copy Frost wyrm Trigger from Trigger editor
* - Copy Libraries folder from Trigger editor
*
* - In object editor --> Abilities go to Frost wyrm (freeze) ability and set Buffs to Frost wyrm (Freeze)
*
*-----------------------------------------------------------------------------------------------------------
*
* Changelog:
*
*-----------------------------------------------------------------------------------------------------------
*
* v1.0
* - First release.
* v1.01
* - Remade Tree_Kill function
* - Fixed unit group leak
* - No longer nulling players
* - Changed dummies names
*
*-----------------------------------------------------------------------------------------------------------*/
/***********************************************************************************
* *
* CONFIGURATION *
* *
***********************************************************************************/
globals
/*Ability and dummies rawcodes*/
/*******************************************************************************/
/**/ /**/
/**/ private constant integer SPELL_CODE = 'A000' /**/ /*Main Ability rawcode*/
/**/ private constant integer FREEZE_CODE = 'A001' /**/ /*Freeze ability rawcode*/
/**/ private constant integer WYRM_CODE = 'h000' /**/ /*Frost wyrm - Dummy 1 rawcode*/
/**/ private constant integer BREATH_CODE = 'h003' /**/ /*Frost wyrm - Dummy 2 rawcode*/
/**/ /**/
/*******************************************************************************/
/*Frost wyrm configuration*/
//Frost wyrm scale
private constant real WYRM_SCALE = 1
//Frost wyrm spawn height
private constant real WYRM_HEIGHT_START = 800
//Frost wyrm destination height. Once it will get on this height it will not fly lower.
private constant real WYRM_HEIGHT = 450
//Time at which forst wyrm will reach WYRM_HEIGHT. If you will se too high like
//3.0 frost wyrm will never reach WYRM_HEIGHT so it will just keep going lower.
private constant real WYRM_HEIGHT_TIME = 3.0
//Frost wyrm will not spawn on caster, it will spawn back by this distance
private constant real WYRM_CREATE_OFF = 400
//Frost wyrm will start it's animation once he will travel this distance
private constant real WYRM_ANIM_DISTANCE = 175
//Frost wyrm animation used for breath
private constant string WYRM_ANIMATION = "attack"
/*Frost breath configuration*/
//Cooldown between creating another one dummy for frost breath. At this
//moment it's 2 * 0.031250
private constant integer BREATH_CD = 2
//To make dummie spawn from wyrm's head not from chest i set this distance
private constant real BREATH_CREATE_OFF = 125
//Frost wyrm will start breating after it will travel this distance
private constant real BREATH_START = 400
//Breath dummies scale
private constant real BREATH_SCALE = 1
//Bretah dummies start height
private constant real BREATH_HEIGHT = 400
//Time at which breat dummies reach the BREATH_LAND_HEIGHT
private constant real BREATH_LAND_TIME = 0.25
//When breath dummies will get on it or lower height they will explode
private constant real BREATH_LAND_HEIGHT = 20
//Breath dummies scale when they land on the ground to make effect bigger
private constant real BREATH_DEATH_SCALE = 1.8
//Bretah dummies nimation played when they land on the ground
private constant string BREATH_ANIM = "death"
//We stop frost wyrm after this time/ 1 = 0.031250
private constant integer BREATH_ANIM_STOP = 28
/*Move speeds configuration*/
//Wyrm movement speed before breathing
private constant real MOVE_SPEED_FIRST = 600
//Wyrm movement speed when it is breating
private constant real MOVE_SPEED_SECOND = 300
/*Damage configuraton*/
//Damage range
private constant real DAMAGE_RANGE = 100
//Attack type
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC
//Damage type
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_DEATH
/*Booleans*/
//Should forst breath kill tress?
private constant boolean DESTROY_TREE = true
//Should frost breath also freeze enemy units?
private constant boolean FREEZE = true
/*Don't touch*/
//Dummy used to freeze targets
private unit FREEZE_DUMMY
endglobals
/*Function to calculate damage dealt to every unit*/
private function GetDamage takes integer level returns real
return level * 3.00
endfunction
/*Function to calculate distancetravaled by wyrm once he start breathing*/
private function GetDistance takes integer level returns real
return level * 50.00 + 650.00
endfunction
/*Which units should not be damaged*/
private function TargetFilter takes unit u, player p returns boolean
return IsUnitEnemy(u, p) and not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_FLYING)
endfunction
/*Which units should not be freezed*/
private function FreezeFilter takes unit u, player p returns boolean
return IsUnitEnemy(u, p) and not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitType(u, UNIT_TYPE_FLYING) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)
endfunction
/***********************************************************************************
* *
* CONFIGURATION END *
* *
***********************************************************************************/
private function Tree_Kill takes nothing returns boolean
call KillTree(GetFilterDestructable())
return false
endfunction
/***********************************************************************************
* *
* FROST BREATH DUMMIES MOVEMENT *
* *
***********************************************************************************/
private struct FrostBreath extends array
private static unit array dummy
private static player array owner
private static real array damage
private static real array height
private static real array heightDec
private static integer array level
static group array ignoreGroup
static group damageGroup
static rect treeRect
implement CTL
local unit t
local real dx
local real dy
implement CTLExpire
set dx = GetUnitX(dummy[this])
set dy = GetUnitY(dummy[this])
set height[this] = height[this] - heightDec[this]
call SetUnitFlyHeight(dummy[this], height[this], 0)
if height[this] <= BREATH_LAND_HEIGHT then
call GroupEnumUnitsInRange(damageGroup, dx, dy, DAMAGE_RANGE, null)
loop
set t = FirstOfGroup(damageGroup)
exitwhen t == null
if TargetFilter(t, owner[this]) and not IsUnitInGroup(t, ignoreGroup[this]) then
call UnitDamageTarget(dummy[this], t, damage[this], true, true, ATTACK_TYPE, DAMAGE_TYPE, null)
call GroupAddUnit(ignoreGroup[this], t)
static if FREEZE then
if FreezeFilter(t, owner[this]) then
call SetUnitAbilityLevel(FREEZE_DUMMY, FREEZE_CODE, level[this])
call IssueTargetOrder(FREEZE_DUMMY, "thunderbolt", t)
endif
endif
endif
call GroupRemoveUnit(damageGroup, t)
endloop
call DestroyGroup(damageGroup)
call DestroyGroup(ignoreGroup[this])
static if DESTROY_TREE then
call SetRect(treeRect, dx - DAMAGE_RANGE, dy - DAMAGE_RANGE, dx + DAMAGE_RANGE, dy + DAMAGE_RANGE)
call EnumDestructablesInRect(treeRect,function Tree_Kill,null)
endif
call SetUnitScale(dummy[this], BREATH_DEATH_SCALE, 0, 0)
call SetUnitAnimation(dummy[this], BREATH_ANIM)
call UnitApplyTimedLife(dummy[this], 'BTLF', 0.75)
set dummy[this] = null
call destroy()
endif
implement CTLNull
implement CTLEnd
static method onBreath takes unit d, player p, integer l, real h returns nothing
local thistype this = create()
set dummy[this] = d
set owner[this] = p
set level[this] = l
set damage[this] = GetDamage(l)
set height[this] = h
set heightDec[this] = height[this] / (BREATH_LAND_TIME * 32)
set damageGroup = CreateGroup()
set ignoreGroup[this] = CreateGroup()
static if DESTROY_TREE then
set treeRect = Rect(0, 0, 0, 0)
endif
endmethod
endstruct
/***********************************************************************************
* *
* FROST WYRM MOVEMENT *
* *
***********************************************************************************/
private struct FrostWyrm extends array
private static unit array caster
private static unit array wyrm
private static player array owner
private static real array angle
private static real array fSpeed
private static real array sSpeed
private static real array fDistance
private static real array sDistance
private static real array cDistance
private static real array wyrmHeight
private static real array wyrmHeightDec
private static integer array level
private static integer array breathCD
private static integer array breathCCD
private static integer array breathStop
private static boolean array wyrmBreath
private static boolean array wyrmAnimation
implement CTL
local unit d
local real dx
local real dy
local real mx
local real my
local real crx
local real cry
implement CTLExpire
set dx = GetUnitX(wyrm[this])
set dy = GetUnitY(wyrm[this])
if wyrmBreath[this] then
set crx = dx + BREATH_CREATE_OFF * Cos(angle[this])
set cry = dy + BREATH_CREATE_OFF * Sin(angle[this])
if breathCCD[this] == breathCD[this] then
set d = CreateUnit(owner[this], BREATH_CODE, crx, cry, angle[this] * bj_RADTODEG)
call SetUnitScale(d, BREATH_SCALE, 0, 0)
call SetUnitFlyHeight(d, wyrmHeight[this], 0)
call FrostBreath.onBreath(d, owner[this], level[this], wyrmHeight[this])
set breathCCD[this] = breathCCD[this] - breathCD[this]
endif
set breathCCD[this] = breathCCD[this] + 1
endif
if fDistance[this] > 0 then
set mx = dx + fSpeed[this] * Cos(angle[this])
set my = dy + fSpeed[this] * Sin(angle[this])
if (mx < WorldBounds.maxX and mx > WorldBounds.minX and my < WorldBounds.maxY and my > WorldBounds.minY) then
call SetUnitX(wyrm[this], mx)
call SetUnitY(wyrm[this], my)
endif
set cDistance[this] = cDistance[this] + fSpeed[this]
set fDistance[this] = fDistance[this] - fSpeed[this]
if cDistance[this] >= WYRM_ANIM_DISTANCE and wyrmAnimation[this] then
call SetUnitAnimation(wyrm[this], WYRM_ANIMATION)
set wyrmAnimation[this] = false
endif
else
if sDistance[this] > 0 then
set mx = dx + sSpeed[this] * Cos(angle[this])
set my = dy + sSpeed[this] * Sin(angle[this])
if (mx < WorldBounds.maxX and mx > WorldBounds.minX and my < WorldBounds.maxY and my > WorldBounds.minY) then
call SetUnitX(wyrm[this], mx)
call SetUnitY(wyrm[this], my)
endif
set cDistance[this] = cDistance[this] + sSpeed[this]
set sDistance[this] = sDistance[this] - sSpeed[this]
else
call SetUnitTimeScale(wyrm[this], 1)
call SetUnitAnimation(wyrm[this], "death")
call UnitApplyTimedLife(wyrm[this], 'BTLF', 1.00)
set caster[this] = null
set wyrm[this] = null
call destroy()
endif
endif
if wyrmHeight[this] > WYRM_HEIGHT then
set wyrmHeight[this] = wyrmHeight[this] - wyrmHeightDec[this]
call SetUnitFlyHeight(wyrm[this], wyrmHeight[this], 0)
endif
set breathStop[this] = breathStop[this] - 1
if breathStop[this] == 0 then
call SetUnitTimeScale(wyrm[this], 0)
endif
if cDistance[this] >= BREATH_START then
set wyrmBreath[this] = true
endif
set d = null
implement CTLNull
implement CTLEnd
private static method onCast takes nothing returns nothing
local thistype this = create()
local real cx
local real cy
local real tx
local real ty
local real crx
local real cry
set caster[this] = GetTriggerUnit()
set owner[this] = GetTriggerPlayer()
set level[this] = GetUnitAbilityLevel(caster[this], SPELL_CODE)
set cx = GetUnitX(caster[this])
set cy = GetUnitY(caster[this])
set tx = GetSpellTargetX()
set ty = GetSpellTargetY()
set angle[this] = Atan2(ty - cy, tx - cx)
set crx = cx - WYRM_CREATE_OFF * Cos(angle[this])
set cry = cy - WYRM_CREATE_OFF * Sin(angle[this])
set wyrm[this] = CreateUnit(owner[this], WYRM_CODE, crx, cry, angle[this] * bj_RADTODEG)
call SetUnitScale(wyrm[this], WYRM_SCALE, 0, 0)
call SetUnitFlyHeight(wyrm[this], WYRM_HEIGHT_START, 0)
set fDistance[this] = WYRM_CREATE_OFF
set sDistance[this] = GetDistance(level[this])
set fSpeed[this] = MOVE_SPEED_FIRST * 0.031250
set sSpeed[this] = MOVE_SPEED_SECOND * 0.031250
set wyrmAnimation[this] = true
set cDistance[this] = 0
set breathCD[this] = BREATH_CD
set breathCCD[this] = BREATH_CD
set breathStop[this] = BREATH_ANIM_STOP
set wyrmBreath[this] = false
set wyrmHeight[this] = WYRM_HEIGHT_START
set wyrmHeightDec[this] = (WYRM_HEIGHT_START - WYRM_HEIGHT) / (WYRM_HEIGHT_TIME * 32)
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(SPELL_CODE,function thistype.onCast)
set FREEZE_DUMMY = CreateUnit(Player(0), WYRM_CODE, 0, 0, 0)
call ShowUnit(FREEZE_DUMMY, false)
call UnitAddAbility(FREEZE_DUMMY, FREEZE_CODE)
endmethod
endstruct
endscope