// CONSTANTS
constant function TNT_Cactus_AbilityId takes nothing returns integer
return 'A000'
endfunction
constant function TNT_Cactus_CactusId takes nothing returns integer
return 'h000'
endfunction
constant function TNT_Cactus_FireProjectileId takes nothing returns integer
return 'n001'
endfunction
constant function TNT_Cactus_ShowCountDown takes nothing returns boolean
return true
endfunction
constant function TNT_Cactus_AoE takes nothing returns real
return 350.
endfunction
function TNT_Cactus_Damage takes nothing returns real
return 114.
endfunction
function TNT_Cactus_AbilityLevel takes unit spellCaster returns integer
return GetUnitAbilityLevel(spellCaster,TNT_Cactus_AbilityId())
endfunction
function TNT_Cactus_CactusDuration takes unit spellCaster returns integer
return 2 + TNT_Cactus_AbilityLevel(spellCaster)
endfunction
function TNT_Cactus_CactusEffect1 takes nothing returns string
return "Abilities\\Spells\\Orc\\FeralSpirit\\feralspirittarget.mdl"
endfunction
function TNT_Cactus_CactusEffect2 takes nothing returns string
return "Abilities\\Spells\\NightElf\\EntanglingRoots\\EntanglingRootsTarget.mdl"
endfunction
function TNT_Cactus_CactusDeathEffect takes nothing returns string
return "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
endfunction
function TNT_Cactus_IsUnitMatching takes unit spellCaster, unit enumUnit returns boolean
return IsUnitEnemy(spellCaster,GetOwningPlayer(enumUnit)) and not IsUnitType(enumUnit,UNIT_TYPE_DEAD) and not IsUnitType(enumUnit,UNIT_TYPE_STRUCTURE)
endfunction
function TNT_Cactus_AttackType takes nothing returns attacktype
return ATTACK_TYPE_NORMAL
endfunction
function TNT_Cactus_DamageType takes nothing returns damagetype
return DAMAGE_TYPE_FIRE
endfunction
function TNT_Cactus_WeaponType takes nothing returns weapontype
return WEAPON_TYPE_WHOKNOWS
endfunction
function TNT_Cactus_GetMaxEffects takes integer abilityLevel returns integer
return 9 + abilityLevel * 3
endfunction
function TNT_Cactus_GetProjMaxHeight takes integer currentEffectCount returns real
return GetRandomReal(-8.+22.*currentEffectCount,98.+22.*currentEffectCount)+250.
endfunction
function TNT_Cactus_GetProjFacingAngle takes nothing returns real
return I2R(GetRandomInt(0,359))
endfunction
function TNT_Cactus_ExplosionText takes nothing returns string
return "BOOM!"
endfunction
function TNT_Cactus_SecondaryExplosionEffect takes nothing returns string
return "Abilities\\Spells\\Human\\Flare\\FlareCaster.mdl"
endfunction
function TNT_Cactus_FireDeathDuration takes nothing returns real
return 1.
endfunction
function TNT_Cactus_FireDeath_DamageAoE takes nothing returns real
return 240.
endfunction
function TNT_Cactus_FireDeath_Damage takes nothing returns real
return 250.
endfunction
// ADDITIONAL FUNCTIONS
function Trig_TNT_Cactus_RemoveOnDeathTimer takes nothing returns nothing
local timer deathTimer = GetExpiredTimer()
local integer deathTimerId = GetHandleId(deathTimer)
local unit whichUnit = LoadUnitHandle(udg_TNT_Cactus_H,deathTimerId,0)
call RemoveUnit(whichUnit)
call FlushChildHashtable(udg_TNT_Cactus_H,deathTimerId)
call DestroyTimer(deathTimer)
set deathTimer = null
set whichUnit = null
endfunction
function Trig_TNT_Cactus_RemoveOnDeath takes unit abilityCaster, unit whichUnit, real deathDuration returns nothing
local timer deathTimer = CreateTimer()
local integer deathTimerId = GetHandleId(deathTimer)
local unit enumUnit
call GroupEnumUnitsInRange(udg_TNT_Cactus_TempGroup,GetUnitX(whichUnit),GetUnitY(whichUnit),TNT_Cactus_FireDeath_DamageAoE(),null)
loop
set enumUnit = FirstOfGroup(udg_TNT_Cactus_TempGroup)
exitwhen enumUnit == null
if TNT_Cactus_IsUnitMatching(abilityCaster,enumUnit) then
call UnitDamageTarget(abilityCaster,enumUnit,TNT_Cactus_FireDeath_Damage(),true,false,TNT_Cactus_AttackType(),TNT_Cactus_DamageType(),TNT_Cactus_WeaponType())
endif
call GroupRemoveUnit(udg_TNT_Cactus_TempGroup,enumUnit)
endloop
call SetUnitAnimation(whichUnit,"death")
call SaveUnitHandle(udg_TNT_Cactus_H,deathTimerId,0,whichUnit)
call TimerStart(deathTimer,deathDuration,false,function Trig_TNT_Cactus_RemoveOnDeathTimer)
set deathTimer = null
endfunction
function Trig_TNT_Cactus_FadingTextSingle takes player p, string msg, integer red, integer green, integer blue, real x, real y, real vel, real fade, real life returns nothing
local texttag t = CreateTextTag()
call SetTextTagText(t,msg,.024)
call SetTextTagPos(t,x,y,0.)
call SetTextTagColor(t,red,green,blue,255)
call SetTextTagVelocity(t,0,vel)
call SetTextTagVisibility(t,GetLocalPlayer()==p)
call SetTextTagFadepoint(t,fade)
call SetTextTagLifespan(t,life)
call SetTextTagPermanent(t,false)
set t = null
endfunction
function Trig_TNT_Cactus_GetAngleBetweenCoords takes real xa, real xb, real ya, real yb returns real
return 57.295827 * Atan2(yb - ya, xb - xa)
endfunction
function Trig_TNT_Cactus_MoveProjectile_Timer takes nothing returns nothing
local timer moveTimer = GetExpiredTimer()
local integer moveTimerId = GetHandleId(moveTimer)
local unit whichProjectile = LoadUnitHandle(udg_TNT_Cactus_H,moveTimerId,0)
local real projectileX = GetUnitX(whichProjectile)
local real projectileY = GetUnitY(whichProjectile)
local real finalX = LoadReal(udg_TNT_Cactus_H,moveTimerId,1)
local real finalY = LoadReal(udg_TNT_Cactus_H,moveTimerId,2)
local real moveSpeed = LoadReal(udg_TNT_Cactus_H,moveTimerId,3)/33.
local real distancePassed = LoadReal(udg_TNT_Cactus_H,moveTimerId,4)
local real finalDistance = LoadReal(udg_TNT_Cactus_H,moveTimerId,5)
local real moveAngle = Trig_TNT_Cactus_GetAngleBetweenCoords(projectileX,finalX,projectileY,finalY)
local real newX = projectileX + moveSpeed * Cos(moveAngle)
local real newY = projectileY + moveSpeed * Sin(moveAngle)
local boolean killProjectile = LoadBoolean(udg_TNT_Cactus_H,moveTimerId,6)
local real deathTime = LoadReal(udg_TNT_Cactus_H,moveTimerId,7)
call SaveReal(udg_TNT_Cactus_H,moveTimerId,4,distancePassed+moveSpeed)
if distancePassed < finalDistance then
call SetUnitX(whichProjectile,newX)
call SetUnitY(whichProjectile,newY)
else
if killProjectile then
call Trig_TNT_Cactus_RemoveOnDeath(LoadUnitHandle(udg_TNT_Cactus_H,moveTimerId,8),whichProjectile,TNT_Cactus_FireDeathDuration())
endif
call FlushChildHashtable(udg_TNT_Cactus_H,moveTimerId)
call PauseTimer(moveTimer)
call DestroyTimer(moveTimer)
endif
set moveTimer = null
set whichProjectile = null
endfunction
function Trig_TNT_Cactus_MoveProjectile takes unit abilityCaster, unit whichProjectile, real fromX, real fromY, real moveAngle, real moveDistance, real moveSpeed, boolean killProjectile returns nothing
local timer moveTimer = CreateTimer()
local integer moveTimerId = GetHandleId(moveTimer)
call SaveUnitHandle(udg_TNT_Cactus_H,moveTimerId,0,whichProjectile)
call SaveReal(udg_TNT_Cactus_H,moveTimerId,1,fromX+moveDistance*Cos(moveAngle*.0174533))
call SaveReal(udg_TNT_Cactus_H,moveTimerId,2,fromY+moveDistance*Sin(moveAngle*.0174533))
call SaveReal(udg_TNT_Cactus_H,moveTimerId,3,moveSpeed)
call SaveReal(udg_TNT_Cactus_H,moveTimerId,4,0.)
call SaveReal(udg_TNT_Cactus_H,moveTimerId,5,moveDistance)
call SaveBoolean(udg_TNT_Cactus_H,moveTimerId,6,killProjectile)
call SaveUnitHandle(udg_TNT_Cactus_H,moveTimerId,8,abilityCaster)
call TimerStart(moveTimer,.03,true,function Trig_TNT_Cactus_MoveProjectile_Timer)
set moveTimer = null
endfunction
function Trig_TNT_Cactus_ThrowUnitZ_Timer takes nothing returns nothing
local timer flipTimer = GetExpiredTimer()
local integer flipTimerId = GetHandleId(flipTimer)
local real defaultZ = LoadReal(udg_TNT_Cactus_H,flipTimerId,0)
local unit whichUnit = LoadUnitHandle(udg_TNT_Cactus_H,flipTimerId,1)
local real maxZ = LoadReal(udg_TNT_Cactus_H,flipTimerId,2)
local real currentZ = GetUnitFlyHeight(whichUnit)
if currentZ > 1. then
call SetUnitFlyHeight(whichUnit,currentZ+maxZ,0.)
set maxZ = maxZ - 2.4525
call SaveReal(udg_TNT_Cactus_H,flipTimerId,2,maxZ)
else
call SetUnitFlyHeight(whichUnit,defaultZ,0.)
call FlushChildHashtable(udg_TNT_Cactus_H,flipTimerId)
call PauseTimer(flipTimer)
call DestroyTimer(flipTimer)
endif
set flipTimer = null
set whichUnit = null
endfunction
function Trig_TNT_Cactus_ThrowUnitZ takes unit whichUnit, real maxZ returns nothing
local timer flipTimer = CreateTimer()
local integer flipTimerId = GetHandleId(flipTimer)
local real currentHeight = GetUnitFlyHeight(whichUnit)
call UnitAddAbility(whichUnit,'Amrf')
call UnitRemoveAbility(whichUnit,'Amrf')
call SetUnitFlyHeight(whichUnit,2.,0.)
call SaveReal(udg_TNT_Cactus_H,flipTimerId,0,currentHeight)
call SaveUnitHandle(udg_TNT_Cactus_H,flipTimerId,1,whichUnit)
call SaveReal(udg_TNT_Cactus_H,flipTimerId,2,SquareRoot(maxZ*245.25)/10.)
call TimerStart(flipTimer,.03,true,function Trig_TNT_Cactus_ThrowUnitZ_Timer)
set flipTimer = null
endfunction
// SPELL FUNCTIONS
function Trig_TNT_Cactus_onDeath takes nothing returns nothing
local timer deathTimer = GetExpiredTimer()
local integer deathTimerId = GetHandleId(deathTimer)
local unit abilityCaster = LoadUnitHandle(udg_TNT_Cactus_H,deathTimerId,0)
local player casterOwner = GetOwningPlayer(abilityCaster)
local unit explodingCactus = LoadUnitHandle(udg_TNT_Cactus_H,deathTimerId,1)
local integer abilityLevel = TNT_Cactus_AbilityLevel(abilityCaster)
local real targetX = GetUnitX(explodingCactus)
local real targetY = GetUnitY(explodingCactus)
local unit fireProjectile
local real realHeight
local real realAngle
local integer i = 1
local unit enumUnit
call ShowUnit(explodingCactus,false)
call RemoveUnit(explodingCactus)
call DestroyEffect(AddSpecialEffect(TNT_Cactus_CactusDeathEffect(),targetX,targetY))
call DestroyEffect(AddSpecialEffect(TNT_Cactus_SecondaryExplosionEffect(),targetX,targetY))
loop
exitwhen i > TNT_Cactus_GetMaxEffects(abilityLevel)
set realHeight = TNT_Cactus_GetProjMaxHeight(i)
set realAngle = TNT_Cactus_GetProjFacingAngle()
set fireProjectile = CreateUnit(casterOwner,TNT_Cactus_FireProjectileId(),targetX,targetY,realAngle)
call Trig_TNT_Cactus_ThrowUnitZ(fireProjectile,realHeight)
call Trig_TNT_Cactus_MoveProjectile(abilityCaster,fireProjectile,targetX,targetY,realAngle,GetRandomReal(TNT_Cactus_AoE(),TNT_Cactus_AoE()+450.),500.,true)
set i = i + 1
endloop
call GroupEnumUnitsInRange(udg_TNT_Cactus_TempGroup,targetX,targetY,TNT_Cactus_AoE(),null)
loop
set enumUnit = FirstOfGroup(udg_TNT_Cactus_TempGroup)
exitwhen enumUnit == null
if TNT_Cactus_IsUnitMatching(abilityCaster,enumUnit) then
call UnitDamageTarget(abilityCaster,enumUnit,TNT_Cactus_Damage(),true,false,TNT_Cactus_AttackType(),TNT_Cactus_DamageType(),TNT_Cactus_WeaponType())
endif
call GroupRemoveUnit(udg_TNT_Cactus_TempGroup,enumUnit)
endloop
call FlushChildHashtable(udg_TNT_Cactus_H,deathTimerId)
call DestroyTimer(deathTimer)
set fireProjectile = null
set deathTimer = null
set explodingCactus = null
set casterOwner = null
set abilityCaster = null
endfunction
function Trig_TNT_Cactus_CountDown takes nothing returns nothing
local timer textTimer = GetExpiredTimer()
local integer textTimerId = GetHandleId(textTimer)
local real targetX = LoadReal(udg_TNT_Cactus_H,textTimerId,0)
local real targetY = LoadReal(udg_TNT_Cactus_H,textTimerId,1)
local real remainingDuration = LoadReal(udg_TNT_Cactus_H,textTimerId,2)-1
local player casterOwner = LoadPlayerHandle(udg_TNT_Cactus_H,textTimerId,3)
call SaveReal(udg_TNT_Cactus_H,textTimerId,2,remainingDuration)
if remainingDuration > 0. then
call Trig_TNT_Cactus_FadingTextSingle(casterOwner,I2S(R2I(remainingDuration)),255,0,0,targetX,targetY,.0355,1.,1.)
else
call Trig_TNT_Cactus_FadingTextSingle(casterOwner,TNT_Cactus_ExplosionText(),255,0,0,targetX,targetY,.0355,1.,1.)
call FlushChildHashtable(udg_TNT_Cactus_H,textTimerId)
call PauseTimer(textTimer)
call DestroyTimer(textTimer)
endif
set textTimer = null
set casterOwner = null
endfunction
function Trig_TNT_Cactus_Conditions takes nothing returns boolean
local unit abilityCaster = GetTriggerUnit()
local player casterOwner = GetTriggerPlayer()
local real targetX = GetSpellTargetX()
local real targetY = GetSpellTargetY()
local unit explodingCactus
local real cactusDuration = TNT_Cactus_CactusDuration(abilityCaster)
local timer deathTimer
local timer textTimer
local integer deathTimerId
local integer textTimerId
if GetSpellAbilityId() == TNT_Cactus_AbilityId() then
set explodingCactus = CreateUnit(casterOwner,TNT_Cactus_CactusId(),targetX,targetY,0.)
set deathTimer = CreateTimer()
set deathTimerId = GetHandleId(deathTimer)
call DestroyEffect(AddSpecialEffect(TNT_Cactus_CactusEffect1(),targetX,targetY))
call DestroyEffect(AddSpecialEffect(TNT_Cactus_CactusEffect2(),targetX,targetY))
call UnitApplyTimedLife(explodingCactus,'BTLF',cactusDuration+.04)
call SaveUnitHandle(udg_TNT_Cactus_H,deathTimerId,0,abilityCaster)
call SaveUnitHandle(udg_TNT_Cactus_H,deathTimerId,1,explodingCactus)
call TimerStart(deathTimer,cactusDuration,false,function Trig_TNT_Cactus_onDeath)
if TNT_Cactus_ShowCountDown() then
set textTimer = CreateTimer()
set textTimerId = GetHandleId(textTimer)
call SaveReal(udg_TNT_Cactus_H,textTimerId,0,targetX)
call SaveReal(udg_TNT_Cactus_H,textTimerId,1,targetY)
call SaveReal(udg_TNT_Cactus_H,textTimerId,2,cactusDuration)
call SavePlayerHandle(udg_TNT_Cactus_H,textTimerId,3,casterOwner)
call TimerStart(textTimer,1.,true,function Trig_TNT_Cactus_CountDown)
endif
endif
set textTimer = null
set deathTimer = null
set explodingCactus = null
set casterOwner = null
set abilityCaster = null
return false
endfunction
//===========================================================================
function InitTrig_TNT_Cactus takes nothing returns nothing
local trigger TNT_Cactus = CreateTrigger()
set udg_TNT_Cactus_H = InitHashtable()
call TriggerRegisterAnyUnitEventBJ(TNT_Cactus,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(TNT_Cactus,Condition(function Trig_TNT_Cactus_Conditions))
set TNT_Cactus = null
endfunction