Rheiko
Spell Reviewer
- Joined
- Aug 27, 2013
- Messages
- 4,122
//---------------------------------------------------------------------------
//
// Rheiko presents
// Skyfall Boulders v1.0
//
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Description:
// Conjures a number of boulders up in the sky and creates two
// portals, one right below the boulders and another right above
// the target location, connected to each other, increasing the
// fall duration, allowing the boulders to hit the ground
// with lethal impact, causing 2 seconds stun to the nearby
// enemies units and knocking them back.
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Credits:
// - AlienAtSystem for CircleOutBuff.mdx and
// CircleOutBuff_Portrait.mdx
// - WILL THE ALMIGHTY for NewDirtEXNofire.mdx
// - Bribe for Knockback2D System
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//
// == HOW TO IMPORT ==
//
// 1. Copy Skyfall Boulders ability from Object Editor and paste it
// into your map.
// 2. Copy Skyfall Boulders (Stun) ability from Object Editor and
// paste it into your map.
// 3. Copy SB_Dummy1, SB_Dummy2, SB_Dummy3, SB_Dummy4, SB_DummyCaster
// unit from Object Editor and paste them into your map.
// 4. Make sure your World Editor has "Automatically Create Unknown
// Variable" enabled. You can find it in File => Preferences
// 5. Copy the trigger in Skyfall Boulders folder and in Knockback2D
// folder (Optional) and paste them into your map.
// 6. Double check to make sure everything works properly.
//
// Note:
// If you prefer to not import Knockback2D and does not want to
// utilize the Knockback aspect of the spell, simply import the
// triggers in Skyfall Boulders. You can leave the triggers in
// Knockback2D out. But make sure you change the value of:
//
// constant function SKBO_KBTrigger takes nothing returns trigger
// return gg_trg_Knockback_2D
// endfunction
//
// you can find it configuration down below, change it to null like this:
//
// constant function SKBO_KBTrigger takes nothing returns trigger
// return null
// endfunction
//
// it is recommended that you also disable SKBO_Knockback function by
// setting it to false. You should now be good to go!! ^_^
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//***************************************************************************
// Configuration Starts Here
//***************************************************************************
//---------------------------------------------------------------------------
// The AbilityID for Skyfall Boulders Spell, make sure it has the same
// value as in Object Editor (to check, press CTRL+D in Object Editor)
//---------------------------------------------------------------------------
constant function SKBO_AbilityID takes nothing returns integer
return 'A000'
endfunction
//---------------------------------------------------------------------------
// The AbilityID for Dummy to cast,
// make sure it has the same value as in Object Editor
// (to check, press CTRL+D in Object Editor)
// - First one is for stun purpose (based on firebolt)
// - Second one is for destroying tree purpose (harvest)
//---------------------------------------------------------------------------
constant function SKBO_StunAbilityID takes nothing returns integer
return 'A001'
endfunction
constant function SKBO_HarvestAbilityID takes nothing returns integer
return 'Ahrl'
endfunction
//---------------------------------------------------------------------------
// This is the Order ID of DummyAbility, this is required to cast the
// ability itself. Check out this list for a reference:
// https://github.com/nestharus/JASS/blob/master/jass/Systems/OrderIds/script.j
//---------------------------------------------------------------------------
constant function SKBO_DOrderID takes nothing returns integer
return 852231
endfunction
//---------------------------------------------------------------------------
// The DummyID for Skyfall Boulders Spell, make sure it has the same
// value as in Object Editor (to check, press CTRL+D in Object Editor)
// - Dummy1 = The boulder
// - Dummy2 = The Portal in the ground
// - Dummy3 = The Portal in the sky
// - Dummy4 = The feral spirit effect for spawn effect
//---------------------------------------------------------------------------
constant function SKBO_Dummy1ID takes nothing returns integer
return 'h000'
endfunction
constant function SKBO_Dummy2ID takes nothing returns integer
return 'h001'
endfunction
constant function SKBO_Dummy3ID takes nothing returns integer
return 'h002'
endfunction
constant function SKBO_Dummy4ID takes nothing returns integer
return 'h003'
endfunction
constant function SKBO_DummyCasterID takes nothing returns integer
return 'h004'
endfunction
//---------------------------------------------------------------------------
// This determines the owner for the dummy units
// You can set it to Neutral Passive to not mess up with game scoreboard
//---------------------------------------------------------------------------
constant function SKBO_DummyOwner takes nothing returns player
return Player(PLAYER_NEUTRAL_PASSIVE)
endfunction
//---------------------------------------------------------------------------
// This determines the size/scale of the dummy
// - Dummy1 = The boulder
// - Dummy2 = The Portal in the ground
// - Dummy3 = The Portal in the sky
// - Dummy4 = The feral spirit effect for spawn effect
//---------------------------------------------------------------------------
constant function SKBO_Dummy1Size takes nothing returns real
return 1.5
endfunction
constant function SKBO_Dummy2Size takes nothing returns real
return 1.0
endfunction
constant function SKBO_Dummy3Size takes nothing returns real
return 1.0
endfunction
constant function SKBO_Dummy4Size takes nothing returns real
return 1.0
endfunction
//---------------------------------------------------------------------------
// This determines the starting height of the dummy
// - Dummy1 = The boulder
// - Dummy2 = The Portal in the ground
// - Dummy3 = The Portal in the sky
// - Dummy4 = The feral spirit effect for spawn effect
//---------------------------------------------------------------------------
constant function SKBO_Dummy1Height takes nothing returns real
return 500.0
endfunction
constant function SKBO_Dummy2Height takes nothing returns real
return 0.0
endfunction
constant function SKBO_Dummy3Height takes nothing returns real
return 500.0
endfunction
constant function SKBO_Dummy4Height takes nothing returns real
return 500.0
endfunction
//---------------------------------------------------------------------------
// This determines the special effect model we will use in the spell
// - Appears when the boulder explodes
//---------------------------------------------------------------------------
constant function SKBO_EffectString takes nothing returns string
return "war3mapImported\\NewDirtEXNofire.mdx"
endfunction
//---------------------------------------------------------------------------
// How many boulders will be conjured and be used throughout the spell?
// Feel free to play around with the number
//---------------------------------------------------------------------------
constant function SKBO_BaseNumber takes nothing returns integer
return 1
endfunction
constant function SKBO_NumberPerLvl takes nothing returns integer
return 2
endfunction
//---------------------------------------------------------------------------
// How much damage should the ability deal?
// The calculation will be something like this:
// Dmg = BaseDmg + (DmgPerLvl * Lvl)
//---------------------------------------------------------------------------
constant function SKBO_BaseDmg takes nothing returns real
return 100.0
endfunction
constant function SKBO_DmgPerLvl takes nothing returns real
return 75.0
endfunction
//---------------------------------------------------------------------------
// This determines the Attack Type, Damage Type, and Weapon Type for the spell
// It can be impactful if you consider how each type interact with armor type
// You can ignore these if they do not concern you
//---------------------------------------------------------------------------
constant function SKBO_AT takes nothing returns attacktype
return ATTACK_TYPE_NORMAL
endfunction
constant function SKBO_DT takes nothing returns damagetype
return DAMAGE_TYPE_NORMAL
endfunction
constant function SKBO_WT takes nothing returns weapontype
return WEAPON_TYPE_WHOKNOWS
endfunction
//---------------------------------------------------------------------------
// How big of a radius will be affected by the damage?
// This is also known as Area of Effect
// The calculation will be something like this:
// Aoe = BaseAoe + (AoePerLvl * Lvl)
//---------------------------------------------------------------------------
constant function SKBO_BaseAoe takes nothing returns real
return 350.0
endfunction
constant function SKBO_AoePerLvl takes nothing returns real
return 0.0
endfunction
//---------------------------------------------------------------------------
// How fast should the boulder fall?
//---------------------------------------------------------------------------
constant function SKBO_BaseSpeed takes nothing returns real
return 30.0
endfunction
constant function SKBO_SpeedPerLvl takes nothing returns real
return 0.0
endfunction
//---------------------------------------------------------------------------
// This is the acceleration value for the falling boulders
//---------------------------------------------------------------------------
constant function SKBO_BaseAccel takes nothing returns real
return 1.5
endfunction
constant function SKBO_AccelPerLvl takes nothing returns real
return 0.0
endfunction
//---------------------------------------------------------------------------
// This allows you toggle the supported features
// - return true to enable
// - return false to disable
//---------------------------------------------------------------------------
constant function SKBO_TreeDestroy takes nothing returns boolean
return true
endfunction
constant function SKBO_Knockback takes nothing returns boolean
return true
endfunction
constant function SKBO_Stun takes nothing returns boolean
return true
endfunction
//---------------------------------------------------------------------------
// Here you can adjust the settings of your knockback
// You can ignore these if SKBO_Knockback is disabled
//---------------------------------------------------------------------------
constant function SKBO_KBDistance takes nothing returns real
return 300.0
endfunction
constant function SKBO_KBTime takes nothing returns real
return 0.70
endfunction
//---------------------------------------------------------------------------
// This is the trigger for Bribe's Knockback2D system
// In case you do not want to import KB2D system into your map
// You can just change this to return null
// Don't forget to disable SKBO_Knockback as well
//---------------------------------------------------------------------------
constant function SKBO_KBTrigger takes nothing returns trigger
return gg_trg_Knockback_2D
endfunction
//---------------------------------------------------------------------------
// The Timer Interval for Loop Function
// Don't change this value unless you know what you are doing
//---------------------------------------------------------------------------
constant function SKBO_Interval takes nothing returns real
return 0.0312500
endfunction
//---------------------------------------------------------------------------
// This is Target Filter, you can modify this to suit your preferences
//---------------------------------------------------------------------------
constant function SKBO_TargetFilter takes unit u, player p returns boolean
return not(IsUnitType(u, UNIT_TYPE_STRUCTURE)) and (IsUnitEnemy(u, p)) and not(IsUnitType(u, UNIT_TYPE_DEAD))
endfunction
//***************************************************************************
// End of Configuration
//***************************************************************************
//---------------------------------------------------------------------------
// RecycleNode Function
//---------------------------------------------------------------------------
function SKBO_RecycleNode takes integer Node returns nothing
set udg_SKBO_RecycledStack[udg_SKBO_RecycledSize] = Node
set udg_SKBO_RecycledSize = udg_SKBO_RecycledSize + 1
set udg_SKBO_NodeNext[udg_SKBO_NodePrev[Node]] = udg_SKBO_NodeNext[Node]
set udg_SKBO_NodePrev[udg_SKBO_NodeNext[Node]] = udg_SKBO_NodePrev[Node]
endfunction
//---------------------------------------------------------------------------
// CreateNode Function
//---------------------------------------------------------------------------
function SKBO_CreateNode takes nothing returns integer
local integer Node
if (udg_SKBO_RecycledSize == 0) then
set udg_SKBO_MaxIndex = udg_SKBO_MaxIndex + 1
set Node = udg_SKBO_MaxIndex
else
set udg_SKBO_RecycledSize = udg_SKBO_RecycledSize - 1
set Node = udg_SKBO_RecycledStack[udg_SKBO_RecycledSize]
endif
set udg_SKBO_NodeNext[Node] = 0
set udg_SKBO_NodeNext[udg_SKBO_NodePrev[0]] = Node
set udg_SKBO_NodePrev[Node] = udg_SKBO_NodePrev[0]
set udg_SKBO_NodePrev[0] = Node
return Node
endfunction
//---------------------------------------------------------------------------
// Destroy Tree Snippet
//---------------------------------------------------------------------------
function SKBO_IsDestTree takes destructable d returns boolean
return IssueTargetOrderById(udg_SKBO_DummyCaster,852018,d) and IssueImmediateOrderById(udg_SKBO_DummyCaster,851972)
endfunction
function SKBO_DestroyTree takes destructable d returns nothing
if SKBO_IsDestTree(d) and GetWidgetLife(d) > 0.405 then
call KillDestructable(d)
endif
endfunction
function SKBO_TreeFilter takes nothing returns boolean
call SKBO_DestroyTree(GetFilterDestructable())
return false
endfunction
//---------------------------------------------------------------------------
// Loop Function
//---------------------------------------------------------------------------
function SKBO_Loop takes nothing returns nothing
local integer Node = 0
local integer i = 0
local integer index = 0
local real angle
local real x
local real y
local unit u
local group g = CreateGroup()
local rect r
loop
set Node = udg_SKBO_NodeNext[Node]
exitwhen Node == null
// Stage 1 handles the fall
if (udg_SKBO_Stage[Node] == 1) then
if (udg_SKBO_CurrentHeight[Node] > 0) then
set udg_SKBO_CurrentHeight[Node] = udg_SKBO_CurrentHeight[Node] - udg_SKBO_Velocity[Node]
set udg_SKBO_Velocity[Node] = udg_SKBO_Velocity[Node] + udg_SKBO_Accel[Node]
call SetUnitFlyHeight(udg_SKBO_DummyUnit[Node], udg_SKBO_CurrentHeight[Node], 0)
else
if (udg_SKBO_Teleported[Node] == true) then
set udg_SKBO_Stage[Node] = 2
else
call KillUnit(udg_SKBO_DummyUnit2[Node])
call KillUnit(udg_SKBO_DummyUnit3[Node])
set udg_SKBO_CurrentHeight[Node] = SKBO_Dummy1Height()
call SetUnitFlyHeight(udg_SKBO_DummyUnit[Node], udg_SKBO_CurrentHeight[Node], 0)
set udg_SKBO_Teleported[Node] = true
// Move the boulders
call SetUnitX(udg_SKBO_DummyUnit[Node], udg_SKBO_DTargetX[Node])
call SetUnitY(udg_SKBO_DummyUnit[Node], udg_SKBO_DTargetY[Node])
endif
endif
// Stage 2 handles damage and recycle
elseif (udg_SKBO_Stage[Node] == 2) then
call KillUnit(udg_SKBO_DummyUnit[Node])
call DestroyEffect(AddSpecialEffect(SKBO_EffectString(), udg_SKBO_DTargetX[Node], udg_SKBO_DTargetY[Node]))
// Deal damage and stuff only if it's the instance of Parent Node
if (udg_SKBO_Parent[Node] == 0) then
call GroupEnumUnitsInRange(g, udg_SKBO_STargetX[Node], udg_SKBO_STargetY[Node], udg_SKBO_Aoe[Node], null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if (SKBO_TargetFilter(u, udg_SKBO_Player[Node])) then
if (SKBO_Stun()) then
call IssueTargetOrderById(udg_SKBO_DummyCaster, SKBO_DOrderID(), u)
endif
if ((GetWidgetLife(u) - udg_SKBO_Dmg[Node]) <= 0.405) then
call SetUnitExploded( u, true )
endif
call UnitDamageTarget(udg_SKBO_Caster[Node], u, udg_SKBO_Dmg[Node], false, false, SKBO_AT(), SKBO_DT(), SKBO_WT())
if (SKBO_Knockback()) then
set x = GetUnitX(u)
set y = GetUnitY(u)
set udg_Knockback2DAngle = bj_RADTODEG * Atan2(y - udg_SKBO_STargetY[Node], x - udg_SKBO_STargetX[Node])
set udg_Knockback2DDistance = SKBO_KBDistance()
set udg_Knockback2DTime = SKBO_KBTime()
set udg_Knockback2DUnit = u
call TriggerExecute( SKBO_KBTrigger() )
endif
endif
call GroupRemoveUnit(g, u)
endloop
// Check if user wants to destroy tree
if (SKBO_TreeDestroy()) then
set r = Rect(udg_SKBO_STargetX[Node] - udg_SKBO_Aoe[Node], udg_SKBO_STargetY[Node] - udg_SKBO_Aoe[Node], udg_SKBO_STargetX[Node] + udg_SKBO_Aoe[Node], udg_SKBO_STargetY[Node] + udg_SKBO_Aoe[Node])
call EnumDestructablesInRect(r, Condition(function SKBO_TreeFilter), null)
call RemoveRect(r)
endif
endif
// Recycle
call SKBO_RecycleNode(Node)
// Turn off when there's no running instance left
if (udg_SKBO_NodePrev[0] == 0) then
call PauseTimer(udg_SKBO_Timer)
endif
endif
endloop
call DestroyGroup(g)
set g = null
endfunction
//---------------------------------------------------------------------------
// CreateBoulder Function
//---------------------------------------------------------------------------
function SKBO_CreateBoulder takes integer parent, real x, real y, real angle returns nothing
local integer Node = SKBO_CreateNode()
local unit u
// Set up the necessary data for boulder dummy
set udg_SKBO_Parent[Node] = parent
set udg_SKBO_CurrentHeight[Node] = udg_SKBO_CurrentHeight[udg_SKBO_Parent[Node]]
set udg_SKBO_Stage[Node] = udg_SKBO_Stage[udg_SKBO_Parent[Node]]
set udg_SKBO_Teleported[Node] = udg_SKBO_Teleported[udg_SKBO_Parent[Node]]
set udg_SKBO_Velocity[Node] = udg_SKBO_Velocity[udg_SKBO_Parent[Node]]
set udg_SKBO_Accel[Node] = udg_SKBO_Accel[udg_SKBO_Parent[Node]]
set udg_SKBO_Aoe[Node] = udg_SKBO_Aoe[udg_SKBO_Parent[Node]]
set udg_SKBO_DTargetX[Node] = udg_SKBO_DTargetX[udg_SKBO_Parent[Node]]
set udg_SKBO_DTargetY[Node] = udg_SKBO_DTargetY[udg_SKBO_Parent[Node]]
// Create the boulder
set udg_SKBO_DummyUnit[Node] = CreateUnit(SKBO_DummyOwner(), SKBO_Dummy1ID(), x, y, angle)
call SetUnitScale(udg_SKBO_DummyUnit[Node], SKBO_Dummy1Size(), SKBO_Dummy1Size(), SKBO_Dummy1Size())
call SetUnitFlyHeight(udg_SKBO_DummyUnit[Node], SKBO_Dummy1Height(), 0)
// Create the spawn effect
set udg_SKBO_DummyUnit2[Node] = CreateUnit(SKBO_DummyOwner(), SKBO_Dummy2ID(), x, y, angle)
call SetUnitScale(udg_SKBO_DummyUnit2[Node], SKBO_Dummy2Size(), SKBO_Dummy2Size(), SKBO_Dummy2Size())
call SetUnitFlyHeight(udg_SKBO_DummyUnit2[Node], SKBO_Dummy2Height(), 0)
set u = CreateUnit(SKBO_DummyOwner(), SKBO_Dummy4ID(), x, y, angle)
call SetUnitScale(u, SKBO_Dummy4Size(), SKBO_Dummy4Size(), SKBO_Dummy4Size())
call SetUnitFlyHeight(u, SKBO_Dummy4Height(), 0)
call KillUnit(u)
set u = null
// Create the teleported effect
set udg_SKBO_DummyUnit3[Node] = CreateUnit(SKBO_DummyOwner(), SKBO_Dummy3ID(), udg_SKBO_DTargetX[Node], udg_SKBO_DTargetY[Node], angle)
call SetUnitScale(udg_SKBO_DummyUnit3[Node], SKBO_Dummy3Size(), SKBO_Dummy3Size(), SKBO_Dummy3Size())
call SetUnitFlyHeight(udg_SKBO_DummyUnit3[Node], SKBO_Dummy3Height(), 0)
endfunction
//---------------------------------------------------------------------------
// Main Function
//---------------------------------------------------------------------------
function SKBO_Main takes nothing returns boolean
// Declare locals
local integer Node = 0
local integer loopInt = 0
local integer iLevel
local integer index = 0
local real rLevel
local real x1
local real y1
local real x2
local real y2
local real x3
local real y3
local real angle
local unit u
if (GetSpellAbilityId() == SKBO_AbilityID()) then
// set up node
set Node = SKBO_CreateNode()
// Mark this instance as a parent
set udg_SKBO_Parent[Node] = 0
// Assign data to locals
set u = GetTriggerUnit()
set iLevel = GetUnitAbilityLevel(u, SKBO_AbilityID())
set rLevel = I2R(iLevel)
set x1 = GetUnitX(u)
set y1 = GetUnitY(u)
set x2 = GetSpellTargetX()
set y2 = GetSpellTargetY()
set angle = bj_RADTODEG * Atan2(y2-y1, x2-x1)
// Assign data to globals
set udg_SKBO_Caster[Node] = u
set udg_SKBO_Player[Node] = GetTriggerPlayer()
set udg_SKBO_Dmg[Node] = SKBO_BaseDmg() + (SKBO_DmgPerLvl() * rLevel)
set udg_SKBO_Aoe[Node] = SKBO_BaseAoe() + (SKBO_AoePerLvl() * rLevel)
set udg_SKBO_Velocity[Node] = SKBO_BaseSpeed() + (SKBO_SpeedPerLvl() * rLevel)
set udg_SKBO_Accel[Node] = SKBO_BaseAccel() + (SKBO_AccelPerLvl() * rLevel)
set udg_SKBO_Number[Node] = SKBO_BaseNumber() + (SKBO_NumberPerLvl() * iLevel)
set udg_SKBO_CurrentHeight[Node] = SKBO_Dummy1Height()
set udg_SKBO_Stage[Node] = 1
set udg_SKBO_Teleported[Node] = false
set udg_SKBO_STargetX[Node] = x2
set udg_SKBO_STargetY[Node] = y2
// Start timer if this is the only instance
if (udg_SKBO_NodePrev[Node] == 0) then
call TimerStart(udg_SKBO_Timer, SKBO_Interval(), true, function SKBO_Loop)
endif
if (udg_SKBO_Number[Node] > 1) then
loop
set loopInt = loopInt + 1
exitwhen loopInt > udg_SKBO_Number[Node]
set angle = I2R(loopInt) * (360.0 / udg_SKBO_Number[Node])
// Set up the location of boulder spawn
set x3 = x1 + udg_SKBO_Aoe[Node] / 2 * Cos(angle * bj_DEGTORAD)
set y3 = y1 + udg_SKBO_Aoe[Node] / 2 * Sin(angle * bj_DEGTORAD)
// Set up the location where the boulder will teleport
set udg_SKBO_DTargetX[Node] = x2 + udg_SKBO_Aoe[Node] / 2 * Cos(angle * bj_DEGTORAD)
set udg_SKBO_DTargetY[Node] = y2 + udg_SKBO_Aoe[Node] / 2 * Sin(angle * bj_DEGTORAD)
// Create the boulder
call SKBO_CreateBoulder(Node, x3, y3, angle)
endloop
else
// Set up the location of boulder spawn
set x3 = x1 + udg_SKBO_Aoe[Node] / 2 * Cos(angle * bj_DEGTORAD)
set y3 = y1 + udg_SKBO_Aoe[Node] / 2 * Sin(angle * bj_DEGTORAD)
// Set up the location where the boulder will teleport
set udg_SKBO_DTargetX[Node] = x2
set udg_SKBO_DTargetY[Node] = y2
// Create the boulder
call SKBO_CreateBoulder(Node, x3, y3, angle)
endif
set u = null
endif
return false
endfunction
//===========================================================================
function InitTrig_Skyfall_Boulders takes nothing returns nothing
local trigger SKBO_Trig = CreateTrigger()
local integer index = 0
local real x = 0
local real y = 0
// Register event
loop
call TriggerRegisterPlayerUnitEvent(SKBO_Trig, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
// Register Main Function
call TriggerAddCondition(SKBO_Trig, Condition(function SKBO_Main))
// Create Dummy Caster
set udg_SKBO_DummyCaster = CreateUnit(SKBO_DummyOwner(), SKBO_DummyCasterID(), x, y, 0)
call UnitAddAbility(udg_SKBO_DummyCaster, SKBO_StunAbilityID())
call UnitAddAbility(udg_SKBO_DummyCaster, SKBO_HarvestAbilityID())
endfunction