- Joined
- Dec 19, 2012
- Messages
- 411
JASS:
scope NuclearExplosion initializer Init
//Nuclear Explosion
/*
--------------------------------------------------------------------------------------
----------------------------Start of Configuration------------------------------------
--------------------------------------------------------------------------------------
*/
globals
private constant integer NE_DummyId = 'h000'
private constant integer NE_SideNuclearExplodeUnitId = 'h001'
private constant integer NE_MainNuclearExplodeUnitId = 'h002'
private constant integer NE_AbilityId = 'A001'
private constant real NE_MainNuclearHeight = 25.
private constant real NE_MainNuclearDistance = 55. //Detect nearby side nuclears and combine them if small or equal to this value
private constant real NE_SideNuclearHeight = 25.
private constant real NE_SideNuclearDetectRange = 75.
private constant real NE_MoveSpeed = 5. //Dont set this value too high or will lead to unnature movement
private constant real NE_SideNuclearAoe = 75. //Detect units in range of SideNuclear ( only need to configure if NE_IsExplode is set to true )
private constant real NE_SideNuclearExplodeExpireTime = 3.
private constant real NE_MainNuclearExplodeExpireTime = 1.
private constant real NE_SideNuclearExplodeTimeScale = 1. //Expired time for side nuclear explode dummy unit
private constant real NE_MainNuclearExplodeTimeScale = 1. //Expired time for main nuclear explode dummy unit
private constant boolean NE_IsExplode = true //If unit near will lead to side nuclear to explode
//IsDestroyTree haven add
private constant boolean NE_IsDestroyTree = true
private constant boolean NE_IsEnableMainNuclearSpawn = false //Spawn the main nuclear at targeted point which increase ReachCount by 1 if set to true
private constant attacktype NE_MainNuclearAttackType = ATTACK_TYPE_CHAOS
private constant attacktype NE_SideNuclearAttackType = ATTACK_TYPE_CHAOS
private constant damagetype NE_MainNuclearDamageType = DAMAGE_TYPE_UNIVERSAL
private constant damagetype NE_SideNuclearDamageType = DAMAGE_TYPE_UNIVERSAL
private constant weapontype NE_MainNuclearWeaponType = WEAPON_TYPE_WHOKNOWS
private constant weapontype NE_SideNuclearWeaponType = WEAPON_TYPE_WHOKNOWS
private constant string NE_MainNuclearModel = "Abilities\\Weapons\\LordofFlameMissile\\LordofFlameMissile.mdl"
private constant string NE_SideNuclearModel = "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnMissile.mdl"
endglobals
//-----------------------------------------------------------------------------------
private constant function NE_SideNuclearExplodeRange takes integer NE_AbilityLv returns real
return 50. + NE_AbilityLv*50
endfunction
//-----------------------------------------------------------------------------------
private constant function NE_NuclearSpawn takes integer NE_AbilityLv returns integer
return NE_AbilityLv*4
endfunction
//Side Nuclear explode damage ( only need to configure if NE_IsExplode is set to true )
//-----------------------------------------------------------------------------------
private constant function NE_SideNuclearDamage takes integer NE_AbilityLv returns real
return NE_AbilityLv*50.
endfunction
//-----------------------------------------------------------------------------------
private constant function NE_MainNuclearDamage takes integer NE_ReachCount returns real
return NE_ReachCount*50.
endfunction
//-----------------------------------------------------------------------------------
private constant function NE_MainNuclearExplodeRange takes integer NE_ReachCount returns real
return NE_ReachCount*100. + 100
endfunction
//-----------------------------------------------------------------------------------
/*
-------------------------------------------------------------------------------------
------------------------------End of Configuration-----------------------------------
-------------------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------------
private constant function NE_LoopIndexMUI takes integer NE_AbilityLv returns integer
return 3 + NE_AbilityLv*4
endfunction
//-----------------------------------------------------------------------------------
globals
private constant integer array NE
private boolean Rb = true
endglobals
private struct NuclearExplosion
integer AbilityLv
integer NuclearSpawn
integer ReachCount //Number of Side Nuclear reached casting point
integer Stage //Determine spell's stage
integer DestroyedCount
integer SideNuclearCount //For MUI purpose
integer LoopIndex
integer array SideNuclearInt[8000]
real Distance //Used for setting the distance between casting point and Side Nuclear
real x //x coordinate of casting point
real y //y coordinate of casting point
unit caster // Triggering Unit
unit MainNuclear //Used for store created Main Nuclear
unit array SideNuclear[8000] //Used for store created Side Nuclear
effect MainNuclearEffect //Used for store Main Nuclear missile effect
effect array SideNuclearEffect[8000] //Used for store Side Nuclear missile effect
static real MainDamage //Main Nuclear damage
static real MainExplodeRange //Main Nuclear explode range
static real SideDamage //Side Nuclear damage
static timer Timer = CreateTimer()
static group G = CreateGroup()
static integer MaxIndex = 0
static method NE_Loop takes nothing returns nothing
local integer CurrentIndex = 1 //Used for loop
local integer GroupCount = 0
local player TriggerPlayer //Used for store TriggerPlayer
local real SideNuclearX //Used for detect units
local real SideNuclearY //Used for detect units
local real x2 //Used for set SideNuclear position
local real y2 //Used for set SideNuclear position
local real angel
local unit u = null // Used for FirstOfGroup
local thistype this
loop
exitwhen CurrentIndex > MaxIndex
set this = NE[CurrentIndex]
set TriggerPlayer = GetOwningPlayer(this.caster)
if this.Stage == 0 then
//-----------------------------------------------------------------------------------------------------------------------------
//---------------------------------------Start of first stage------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
set this.Stage = 1
//Start of creating Main Nuclear
//****************************************************
if NE_IsEnableMainNuclearSpawn == true then
set this.MainNuclear = CreateUnit(TriggerPlayer, NE_DummyId, this.x, this.y, bj_UNIT_FACING)
call SetUnitFlyHeight(this.MainNuclear, (GetUnitFlyHeight(this.MainNuclear) + NE_MainNuclearHeight), 0.00)
set this.MainNuclearEffect = AddSpecialEffectTarget(NE_MainNuclearModel, this.MainNuclear, "origin")
set this.ReachCount = this.ReachCount + 1
endif
//****************************************************
//End of creating Main Nuclear
set this.Distance = NE_DistanceSpawn
set this.LoopIndex = this.SideNuclearCount - NE_LoopIndexMUI(this.AbilityLv - 1)
//Start of creating Side Nuclears
//****************************************************
loop
exitwhen this.LoopIndex > this.SideNuclearCount
set angel = 360/this.NuclearSpawn*this.LoopIndex
set this.SideNuclearInt[this.LoopIndex] = this.LoopIndex
set x2 = this.x + this.Distance*Cos(Deg2Rad(angel))
set y2 = this.y + this.Distance*Sin(Deg2Rad(angel))
set this.SideNuclear[this.LoopIndex] = CreateUnit(TriggerPlayer, NE_DummyId, x2, y2, angel-180.)
call SetUnitFlyHeight(this.SideNuclear[this.LoopIndex], GetUnitFlyHeight(this.SideNuclear[LoopIndex]) + NE_SideNuclearHeight, 0.00)
set this.SideNuclearEffect[this.LoopIndex] = AddSpecialEffectTarget(NE_SideNuclearModel, this.SideNuclear[LoopIndex], "origin")
set this.LoopIndex = this.LoopIndex + 1
endloop
//****************************************************
//End of creating Side Nuclears
//-----------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------End of first stage----------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
elseif this.Stage == 1 then
//-----------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------Start of second stage---------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
set this.Distance = this.Distance - NE_MoveSpeed
if udg_b == false then
set udg_b = true
call PauseTimer(Timer)
endif
set this.LoopIndex = this.SideNuclearCount - NE_LoopIndexMUI(this.AbilityLv - 1) + this.DestroyedCount
//Start of SetUnitX/Y ( Side Nuclears )
//****************************************************
loop
exitwhen this.LoopIndex > this.SideNuclearCount
set angel = 360/this.NuclearSpawn*this.SideNuclearInt[this.LoopIndex]
set x2 = this.x + this.Distance*Cos(Deg2Rad(angel))
set y2 = this.y + this.Distance*Sin(Deg2Rad(angel))
call SetUnitX(this.SideNuclear[this.LoopIndex], x2)
call SetUnitY(this.SideNuclear[this.LoopIndex], y2)
//Start of NE_IsExplode actions
//****************************************************
if NE_IsExplode then
call GroupClear(G)
call GroupEnumUnitsInRange(G, x2, y2, NE_SideNuclearAoe, null)
loop
set u = FirstOfGroup(G)
exitwhen u == null
if u != this.caster and GetUnitTypeId(u) != NE_SideNuclearExplodeUnitId and GetUnitTypeId(u) != NE_SideNuclearExplodeUnitId then
set GroupCount = GroupCount + 1
endif
call GroupRemoveUnit(G, u)
endloop
if GroupCount > 0 then
set GroupCount = 0
call RemoveUnit(this.SideNuclear[this.LoopIndex])
call DestroyEffect(this.SideNuclearEffect[this.LoopIndex])
set this.SideNuclear[this.LoopIndex] = null
set this.SideNuclear[this.LoopIndex] = CreateUnit(TriggerPlayer, NE_SideNuclearExplodeUnitId, x2, y2, bj_UNIT_FACING)
call UnitApplyTimedLife(this.SideNuclear[this.LoopIndex], 'BTLF', NE_SideNuclearExplodeExpireTime)
call SetUnitTimeScale(this.SideNuclear[this.LoopIndex], NE_SideNuclearExplodeTimeScale)
if this.DestroyedCount != NE_NuclearSpawn(this.AbilityLv) then
set this.SideNuclear[this.LoopIndex] = null
set this.SideNuclearEffect[this.LoopIndex] = null
set this.SideNuclear[this.LoopIndex] = this.SideNuclear[this.SideNuclearCount]
set this.SideNuclearEffect[this.LoopIndex] = this.SideNuclearEffect[this.SideNuclearCount]
set this.SideNuclearInt[this.LoopIndex] = 0
set this.SideNuclearInt[this.LoopIndex] = this.SideNuclearInt[this.SideNuclearCount]
set this.SideNuclearCount = this.SideNuclearCount - 1
set this.DestroyedCount = this.DestroyedCount + 1
set this.LoopIndex = this.LoopIndex - 1
endif
call GroupClear(G)
call GroupEnumUnitsInRange(G, x2, y2, NE_SideNuclearAoe, null)
loop
set u = FirstOfGroup(G)
exitwhen u == null
if GetWidgetLife(u) > .405 and u != this.caster and IsUnitEnemy(u, TriggerPlayer) then
call UnitDamageTarget(this.caster, u, NE_SideNuclearDamage(this.AbilityLv), true, false, NE_SideNuclearAttackType, NE_SideNuclearDamageType, NE_SideNuclearWeaponType)
endif
call GroupRemoveUnit(G, u)
endloop
if this.DestroyedCount == NE_NuclearSpawn(this.AbilityLv) and this.ReachCount == 0 then
call this.destroy()
endif
endif
endif
//****************************************************
//End of NE_IsExplode actions
set this.LoopIndex = this.LoopIndex + 1
endloop
//****************************************************
//End of SetUnitX/Y ( Side Nuclears )
//If conditions full filled then end of second stage
//****************************************************
if this.Distance <= NE_MainNuclearDistance then
set this.Stage = 2
set this.ReachCount = this.ReachCount + NE_NuclearSpawn(this.AbilityLv) - this.DestroyedCount
set this.LoopIndex = this.SideNuclearCount - NE_LoopIndexMUI(this.AbilityLv - 1)
loop
exitwhen this.LoopIndex > this.SideNuclearCount
call RemoveUnit(this.SideNuclear[this.LoopIndex])
call DestroyEffect(this.SideNuclearEffect[this.LoopIndex])
set this.LoopIndex = this.LoopIndex + 1
endloop
elseif this.DestroyedCount == this.SideNuclearCount and this.ReachCount != 0 then
set this.Stage = 2
endif
//****************************************************
//End of jumped final stage
//-----------------------------------------------------------------------------------------------------------------------------
//--------------------------------------------End of second stage--------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
elseif this.Stage == 2 then
//-----------------------------------------------------------------------------------------------------------------------------
//--------------------------------------------Start of final stage-------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
set this.Stage = 3
call RemoveUnit(this.MainNuclear)
call DestroyEffect(this.MainNuclearEffect)
set this.MainNuclear = null
set this.MainNuclear = CreateUnit(TriggerPlayer, NE_MainNuclearExplodeUnitId, this.x, this.y, bj_UNIT_FACING)
call UnitApplyTimedLife(this.MainNuclear, 'BTLF', NE_MainNuclearExplodeExpireTime)
call SetUnitTimeScale(this.MainNuclear, NE_MainNuclearExplodeTimeScale)
call GroupClear(G)
call GroupEnumUnitsInRange(G, this.x, this.y, NE_MainNuclearExplodeRange(this.ReachCount), null)
loop
set u = FirstOfGroup(G)
if GetWidgetLife(u) > .405 and u != this.caster and IsUnitEnemy(u, TriggerPlayer) then
call UnitDamageTarget(this.caster, u, NE_MainNuclearDamage(this.ReachCount), true, false, NE_MainNuclearAttackType, NE_MainNuclearDamageType, NE_MainNuclearWeaponType)
endif
call GroupRemoveUnit(G, u)
endloop
call this.destroy()
//-----------------------------------------------------------------------------------------------------------------------------
//--------------------------------------------End of final stage---------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
endif
set TriggerPlayer = null
set CurrentIndex = CurrentIndex + 1
endloop
endmethod
static method NE_Configure takes nothing returns boolean
local thistype this
//Start of setting initial data
//****************************************************
if GetSpellAbilityId() == NE_AbilityId then
set this = thistype.allocate()
set MaxIndex = MaxIndex + 1
set this = MaxIndex
set NE[MaxIndex] = this
set this.x = GetSpellTargetX()
set this.y = GetSpellTargetY()
set this.caster = GetTriggerUnit()
set this.AbilityLv = GetUnitAbilityLevel(this.caster, NE_AbilityId)
set this.SideDamage = NE_SideNuclearDamage(this.AbilityLv)
set this.NuclearSpawn = NE_NuclearSpawn(this.AbilityLv)
set this.Stage = 0
set this.DestroyedCount = 0
set this.SideNuclearCount = NE_NuclearSpawn(this.AbilityLv)*this
if MaxIndex == 1 then
call TimerStart(Timer, 0.0312500, true, function thistype.NE_Loop)
endif
endif
//****************************************************
//End of setting initial data
return false
endmethod
method destroy takes nothing returns nothing
local integer R
local integer R2
local integer R3
local integer R4
local thistype T = thistype.allocate()
set R = this // LoopIndex
set T = this + 1 // For replace previous data
loop
if Rb then
set Rb = false
set R2 = NE_NuclearSpawn(this.AbilityLv)*this
set R4 = R2 // constant number
set R3 = R2 - NE_LoopIndexMUI(this.AbilityLv - 1)
loop
exitwhen R3 > R2
set this.SideNuclear[R3] = null
set this.SideNuclearEffect[R3] = null
set this.SideNuclearInt[R3] = 0
set R3 = R3 + 1
endloop
set this.MainNuclear = null
set this.MainNuclearEffect = null
set this.caster = null
set this.ReachCount = 0
set this.LoopIndex = 0
else
//Get next data
set this = this + 1
set R2 = NE_NuclearSpawn(this.AbilityLv)*this
set R3 = R2 - NE_LoopIndexMUI(this.AbilityLv - 1)
set this = this - 1
//set back
//replace data
loop
exitwhen R3 > R2
set this.SideNuclear[R3-R4] = null
set this.SideNuclearEffect[R3-R4] = null
set this.SideNuclear[R3-R4] = T.SideNuclear[R3]
set this.SideNuclearEffect[R3-R4] = T.SideNuclearEffect[R3]
set this.SideNuclearInt[R3-R4] = T.SideNuclearInt[R3]
set R3 = R3 + 1
endloop
set this.MainNuclear = null
set this.MainNuclearEffect = null
set this.MainNuclear = T.MainNuclear
set this.MainNuclearEffect = T.MainNuclearEffect
set this.caster = T.caster
set this.Distance = T.Distance
set this.x = T.x
set this.y = T.y
set this.AbilityLv = T.AbilityLv
set this.SideDamage = T.SideDamage
set this.NuclearSpawn = T.NuclearSpawn
set this.Stage = T.Stage
set this.DestroyedCount = T.DestroyedCount
set this.ReachCount = T.ReachCount
set this.LoopIndex = T.LoopIndex
set this.SideNuclearCount = T.SideNuclearCount
set R = R + 1
exitwhen R >= MaxIndex - 1
set this = R
set T = R + 1
endif
if MaxIndex == 1 then
exitwhen true
endif
endloop
set MaxIndex = MaxIndex - 1
set Rb = true
if MaxIndex == 0 then
call PauseTimer(Timer)
endif
call T.deallocate()
call this.deallocate()
endmethod
endstruct
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Filter(function NuclearExplosion.NE_Configure))
set t = null
endfunction
endscope
This's the spell that i made (whole concept is create N number of SideNuclears around the spell targeted point and move to the targeted point.), but the destroy method always got problem with the replace method. If I cast 1 time, it seem work fine; If I cast 2 times, it same work fine; If I cast 3 times, after the 1st spell ended and called destroy method the 2nd spell stopped continue and 3rd spell seem taken the 2nd spell's data.. any idea?