scope LaunchNuclear initializer Init //requires TimerUtils, SimError, DestructableLib, GTrigger
globals
private constant integer ABILITY_ID = 'A001' //ability id of the Launch Nuclear ability
private constant integer NUC_ID = 'A000' //the ability id of the Reload Nulcear ability
private constant integer UNIT_ID = 'h000' //the unit id of the Nuclear dummy unit
private constant real INCREMENT_INC = 0.30 //each time the timer hit this value, variables (damage, speed, etc.) will increase
private constant real INTERVAL = 0.03 //interval of the timers
private constant real SPEED_ADD = 1 //speed increased by the missile every INCREMENT_INC seconds
private constant real MAX_SPEED = 13 //maximum speed of the missile
private constant real TREE_RADIUS = 150 //area where trees will be destroyed
private constant real DAMAGE_RADIUS = 525 //area where enemies will be damaged
private constant real DESCEND_DIST = 450 //the distance in between the missile and the target where the missile will start to descend to the ground.
private constant string SFX = "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl" //the effect applied when the nuclear explodes
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL //attack type of the final damage
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC //damage type of the final damage
//==============================================
private hashtable nuc = InitHashtable()
private hashtable ht = InitHashtable()
private integer temp
private rect rect1 = null
private group nucGroup
endglobals
private function GetDamage takes unit u, integer level returns real
//set the base damage here (smallest amount)
return I2R(level)*50
endfunction
private function DamageIncrement takes unit u, integer level returns real
//incremented damage per INCREMENT_INC second
return I2R(level)*2
endfunction
private function MaxMissiles takes unit u, integer level returns integer
//set the maximum number of missiles in every recharge
return 1*level
endfunction
private function Damage_Condition takes unit u, unit f returns boolean
//conditions to check units to be damaged
return IsUnitEnemy(f,GetOwningPlayer(u)) and IsUnitType(f,UNIT_TYPE_DEAD) == false and IsUnitType(f,UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
//------------------ END OF CONFIGURABLES ----------------------------
private struct Launch
unit caster
unit dummy
real speed
real dmg
real height
real count
real facing
real increment
location target
timer time
static method DamageGroup takes integer index, unit f returns nothing
local thistype dat = index
local boolean b = Damage_Condition(dat.caster,f)
if b then
call UnitDamageTarget(dat.caster,f,dat.dmg,false,false,ATTACK_TYPE,DAMAGE_TYPE,null)
endif
endmethod
static method DestroyTrees takes nothing returns nothing
if IsDestructableTree(GetEnumDestructable()) then
call KillDestructable(GetEnumDestructable())
endif
endmethod
static method CheckGroup takes nothing returns nothing
call thistype.DamageGroup.execute(temp,GetEnumUnit())
endmethod
static method OnLoop takes nothing returns nothing
local thistype dat = GetTimerData(GetExpiredTimer())
local real angle = bj_RADTODEG * Atan2(GetLocationY(dat.target) - GetUnitY(dat.dummy), GetLocationX(dat.target) - GetUnitX(dat.dummy))
local real dx = GetLocationX(dat.target) - GetUnitX(dat.dummy)
local real dy = GetLocationY(dat.target) - GetUnitY(dat.dummy)
local real dist = SquareRoot(dx * dx + dy * dy)
local real x
local real y
set dat.count = dat.count + INTERVAL
if dat.count >= INCREMENT_INC then
set dat.dmg = dat.dmg + dat.increment
if dat.speed < MAX_SPEED then
set dat.speed = dat.speed + SPEED_ADD
endif
endif
if dist > DESCEND_DIST then
call SetUnitFacing(dat.dummy,dat.facing)
set x = GetUnitX(dat.dummy) + dat.speed * Cos(angle * bj_DEGTORAD)
set y = GetUnitY(dat.dummy) + dat.speed * Sin(angle * bj_DEGTORAD)
call SetUnitX(dat.dummy,x)
call SetUnitY(dat.dummy,y)
else
set dat.height = dat.height - 5
call SetUnitFacing(dat.dummy,angle)
call SetUnitFlyHeight(dat.dummy,dat.height,1000)
set x = GetUnitX(dat.dummy) + dat.speed * Cos(angle * bj_DEGTORAD)
set y = GetUnitY(dat.dummy) + dat.speed * Sin(angle * bj_DEGTORAD)
call SetUnitX(dat.dummy,x)
call SetUnitY(dat.dummy,y)
endif
if dist <= 20 then
call RemoveSavedInteger(ht,0,GetHandleId(dat.dummy))
call DestroyEffect(AddSpecialEffect(SFX,GetUnitX(dat.dummy),GetUnitY(dat.dummy)))
call SetRect(rect1,GetUnitX(dat.dummy)-TREE_RADIUS,GetUnitY(dat.dummy)-TREE_RADIUS,GetUnitX(dat.dummy)+TREE_RADIUS,GetUnitY(dat.dummy)+TREE_RADIUS)
call EnumDestructablesInRect(rect1,null,function thistype.DestroyTrees)
call GroupEnumUnitsInRange(nucGroup,GetUnitX(dat.dummy),GetUnitY(dat.dummy),DAMAGE_RADIUS,null)
set temp = dat
call ForGroup(nucGroup,function thistype.CheckGroup)
call RemoveUnit(dat.dummy)
call RemoveLocation(dat.target)
call ReleaseTimer(dat.time)
call dat.destroy()
endif
endmethod
static method start takes nothing returns nothing
local thistype dat = thistype.allocate()
local real angle
local integer int = LoadInteger(nuc,0,GetHandleId(GetTriggerUnit()))
set dat.caster = GetTriggerUnit()
set dat.target = GetSpellTargetLoc()
set dat.dummy = CreateUnit(GetOwningPlayer(dat.caster),UNIT_ID,GetUnitX(dat.caster),GetUnitY(dat.caster),GetUnitFacing(dat.caster))
set angle = bj_RADTODEG * Atan2(GetLocationY(dat.target) - GetUnitY(dat.dummy), GetLocationX(dat.target) - GetUnitX(dat.dummy))
call SetUnitFacingTimed(dat.dummy,angle,0.7)
call PauseUnit(dat.dummy,true)
set dat.facing = angle
call SaveInteger(ht,0,GetHandleId(dat.dummy),dat)
set dat.speed = 1
set dat.dmg = GetDamage(dat.caster,GetUnitAbilityLevel(dat.caster,ABILITY_ID))
set dat.increment = DamageIncrement(dat.caster,GetUnitAbilityLevel(dat.caster,ABILITY_ID))
set int = int - 1
call SaveInteger(nuc,0,GetHandleId(dat.caster),int)
set dat.count = 0
set dat.height = 200
set dat.time = NewTimer()
call SetTimerData(dat.time,dat)
call TimerStart(dat.time,INTERVAL,true,function thistype.OnLoop)
endmethod
static method OnDeath takes nothing returns nothing
local thistype dat = LoadInteger(ht,0,GetHandleId(GetTriggerUnit()))
call RemoveLocation(dat.target)
call ReleaseTimer(dat.time)
call dat.destroy()
endmethod
static method CheckCast takes nothing returns nothing
local unit u = GetTriggerUnit()
if LoadInteger(nuc,0,GetHandleId(u)) == 0 then
call IssueImmediateOrder(u,"stop")
call SimError(GetOwningPlayer(u),"You don't have enough nuclears!")
endif
set u = null
endmethod
static method OnLearn takes nothing returns nothing
local unit u = GetTriggerUnit()
call SaveInteger(nuc,0,GetHandleId(u),0)
call UnitAddAbility(u,NUC_ID)
call UnitMakeAbilityPermanent(u,true,NUC_ID)
set u = null
endmethod
static method OnReload takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer maxa = MaxMissiles(u,GetUnitAbilityLevel(u,ABILITY_ID))
local integer int = LoadInteger(nuc,0,GetHandleId(u))
if int < maxa then
set int = int + 1
call SaveInteger(nuc,0,GetHandleId(u),int)
call DisplayTimedTextToPlayer(GetOwningPlayer(u),0,0,3.,"Nuclear Reloaded: " + I2S(int) + "/" + I2S(maxa))
else
call DisplayTimedTextToPlayer(GetOwningPlayer(u),0,0,3.,"You're fully reloaded dude: " + I2S(int) + "/" + I2S(maxa))
endif
set u = null
endmethod
static method conds takes nothing returns boolean
return GetSpellAbilityId() == ABILITY_ID
endmethod
static method CheckDeath takes nothing returns boolean
return LoadInteger(ht,0,GetHandleId(GetTriggerUnit())) != 0
endmethod
static method CheckLearn takes nothing returns boolean
return GetLearnedSkill() == ABILITY_ID and GetUnitAbilityLevel(GetTriggerUnit(),NUC_ID) == 0
endmethod
static method CheckReload takes nothing returns boolean
return GetSpellAbilityId() == NUC_ID
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerAddAction(t,function thistype.start)
call GT_RegisterStartsEffectEvent(t,ABILITY_ID)
set t = CreateTrigger()
call TriggerAddAction(t,function thistype.CheckCast)
call GT_RegisterBeginsCastingEvent(t,ABILITY_ID)
set t = CreateTrigger()
call TriggerAddAction(t,function thistype.OnDeath)
call TriggerAddCondition(t,function thistype.CheckDeath)
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
set t = CreateTrigger()
call TriggerAddAction(t,function thistype.OnLearn)
call TriggerAddCondition(t,function thistype.CheckLearn)
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_HERO_SKILL)
set t = CreateTrigger()
call TriggerAddAction(t,function thistype.OnReload)
call GT_RegisterStartsEffectEvent(t,NUC_ID)
set t = null
endmethod
endstruct
private function Init takes nothing returns nothing
call Preload(SFX)
set nucGroup = CreateGroup()
endfunction
endscope