Tinki3
Special Member
- Reaction score
- 418
A new, original, fully MUI, JASS/New gen enhanced spell from your favourite spellmaker .
Import Difficulty: High-ish
Units Affected: Enemy, ground
Target Type: Point
Spell Info:
Creates a disk of fire at the target location. The disk will then begin moving from one spot to another with speed depending on the level of Fire Disk. The disk will spit fire balls outwards in a circular formation that sizzle enemies upon contact dealing damage. After a limited amount of time, the disk will explode dealing large damage to enemy ground units in an area, and will knock them back a short range. Disk destroys trees upon contact.
Code:
Read Me:
The spell looks far better in-game.
Enjoy.
Import Difficulty: High-ish
Units Affected: Enemy, ground
Target Type: Point
Spell Info:
Creates a disk of fire at the target location. The disk will then begin moving from one spot to another with speed depending on the level of Fire Disk. The disk will spit fire balls outwards in a circular formation that sizzle enemies upon contact dealing damage. After a limited amount of time, the disk will explode dealing large damage to enemy ground units in an area, and will knock them back a short range. Disk destroys trees upon contact.
Code:
JASS:
scope FireDisk
globals
private constant integer Main_Spell_ID = 039;A000039; //Raw code of "Fire Disk"
private constant integer Dummy_Ability = 039;A001039; //Raw code of "Fire Disk Dummy Ability"
private constant integer Disk_Part_ID = 039;h001039; //Raw code of "Fire Disk Part"
private constant integer Dummy_Caster_ID = 039;h002039; //Raw code of "Dummy Caster"
private constant integer Disk_Centre_Part_ID = 039;h003039; //Raw code of "Fire Disk Center Part"
private constant string Dummy_Ability_String = "carrionswarm" //Order string for dummy ability (match with object editor)
private constant string Disk_Explosion_SFX_1 = "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl" //The effect created at the disk's centre when it dies
private constant string Disk_Explosion_SFX_2 = "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl" //The effect created on units that were affected by the explosion
private constant boolean Disk_Destroys_Trees = true //If "true" - disk will destroy trees; if "false" - disk will NOT destroy trees
private constant integer Disk_Part_Amount = 10 //The amount of fireballs/dummy units to be created as the ring (won't be exact amount created)
private constant real Disk_Rotation_Speed = -0.075 //The speed in which fireballs orbit the centre of the disk ('-' numbers spin disk clockwise, '+' spin disk anticlockwise)
private constant real Disk_Move_Speed_Base = 0.75 //Formula = Disk_Move_Speed_Base * LEVEL * Disk_Move_Speed_Multiplier (disk moves at this speed)
private constant real Disk_Move_Speed_Multiplier = 3.25 // " " " " " " " "
private constant real Disk_Size = 130.0 //The radius of the circle (remember the full "size" of the circle will be a Disk_Size * 2 area)
private constant real Disk_Move_Distance = 675.0 //The distance the disk moves at one time (can vary)
private constant real Disk_Dummy_Ability_Cast_Interval = 0.1 //The interval between each cast of the Dummy_Ability_1 ability
private constant integer Disk_Dummy_Ability_Casting_Angle_Increment_Value = 1 //MUST be a number ABOVE 0, a whole number (an integer), and should be a number that is a FACTOR of the "Disk_Part_Amount" value. This value is used to determine the angle increment in which the dummy caster unit casts the dummy spell at. The smaller the number inserted for this global value, the smaller the angle will be between each wave of fire; the higher the number is, the greater the angle will be between each wave of fire. Remember that this value is linked with the "Disk_Part_Amount" value. If you increase the Disk_Part_Amount value, you would probably want to increase the value on this line so that the fireballs are nicely spread. You will have to experiment with this value before you will understand fully what you have just read.
private constant real Disk_Lifespan_Base = 8//The base value for how long the disk lives (formula = Disk_Lifespan_Base * LEVEL)
private constant real Disk_Explosion_AoE = 300.0 //The AoE of the explosion when the disk dies
private constant real Disk_Explosion_Dmg_Base = 80 //The damage base value of the explosion when the disk dies (formula = LEVEL * Disk_Explosion_Dmg_Base)
private constant real Disk_Tree_Destroy_Area = 225.0 //The area in which trees/destructables are picked to be killed/destroyed when the disk is nearby
private constant real Disk_Explosion_Knockback_Distance = 325.0 //The distance units are knocked back by the explosion when the disk dies
private constant real Disk_Explosion_Knockback_Speed = 15.0 //The speed in which units are knocked back by the explosion when the disk dies
private constant real Timer_Interval = 0.03 //The interval between each timer callback function execution
endglobals
private struct dat
unit u
unit array p[Disk_Part_Amount ]
real array A[Disk_Part_Amount]
unit c
integer lvl
real s
real a
real a2
integer a3
real D
real L
trigger trig
triggeraction ta
endstruct
private struct dat2
real c
real OX
real OY
real dmg
unit U
unit array P[100]
endstruct
private function Unit_Filter takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(bj_ghoul[40])) and GetWidgetLife(GetFilterUnit()) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) != true and IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING) != true
endfunction
private function Destroy_Destructs takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction
private function Refund takes unit u, real m, real m2, integer lvl returns nothing
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) + (m - m2))
call UnitRemoveAbility(u, Main_Spell_ID)
call UnitAddAbility(u, Main_Spell_ID)
call SetUnitAbilityLevel(u, Main_Spell_ID, lvl)
endfunction
private function Error takes player P,string S returns nothing
local sound s = CreateSoundFromLabel("InterfaceError", false, false, false, 10, 10)
if(GetLocalPlayer() == P) then
call ClearTextMessages()
call DisplayTimedTextToPlayer(P, 0.52, -1.0, 2.0, "|cffffcc00" + S + "|r" )
call StartSound(s)
endif
call KillSoundWhenDone(s)
set s = null
endfunction
private function Knockback takes nothing returns nothing
local timer T = GetExpiredTimer()
local dat2 dd = dat2(GetHandleInt(T, "dd"))
local integer i = 1
local real X
local real Y
local real PX
local real PY
local real ang
local unit p
local rect R
if dd.c > 0 then
set dd.c = dd.c - Disk_Explosion_Knockback_Speed
loop
exitwhen dd.P<i> == null
set X = GetUnitX(dd.P<i>)
set Y = GetUnitY(dd.P<i>)
set ang = Atan2(Y-dd.OY, X-dd.OX)
set PX = X + Disk_Explosion_Knockback_Speed * Cos(ang)
set PY = Y + Disk_Explosion_Knockback_Speed * Sin(ang)
set R = Rect(X - 135, Y - 135, X + 135, Y + 135)
call EnumDestructablesInRect(R, null, function Destroy_Destructs)
call SetUnitPosition(dd.P<i>, PX, PY)
call UnitDamageTarget(dd.U, dd.P<i>, dd.dmg, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
call DestroyEffect(AddSpecialEffect(Disk_Explosion_SFX_2, X, Y))
call RemoveRect(R)
set R = null
set i = i + 1
endloop
else
call PauseTimer(T)
call FlushHandleLocals(T)
call dd.destroy()
call DestroyTimer(T)
endif
set T = null
endfunction
private function Shoot_Flames takes nothing returns nothing
local trigger trg = GetTriggeringTrigger()
local dat d2 = dat(GetHandleInt(trg, "d"))
local real X = GetUnitX(d2.c)
local real Y = GetUnitY(d2.c)
local real PX
local real PY
local unit z
if d2.a3 <= Disk_Part_Amount then
set PX = X + Disk_Size/1.4 * Cos(d2.A[d2.a3])
set PY = Y + Disk_Size/1.4 * Sin(d2.A[d2.a3])
set z = CreateUnit(GetOwningPlayer(d2.u), Dummy_Caster_ID, X, Y, 0)
call UnitAddAbility(z, Dummy_Ability)
call SetUnitAbilityLevel(z, Dummy_Ability, d2.lvl)
call IssuePointOrder(z, Dummy_Ability_String, PX, PY)
set d2.a3 = d2.a3 + Disk_Dummy_Ability_Casting_Angle_Increment_Value
set z = null
else
set d2.a3 = 1
endif
set trg = null
endfunction
private function Move_Disk takes nothing returns nothing
local timer t = GetExpiredTimer()
local dat d = dat(GetHandleInt(t, "d"))
local real X1 = GetUnitX(d.c)
local real Y1 = GetUnitY(d.c)
local real X2 = X1 + d.s * Cos(d.a)
local real Y2 = Y1 + d.s * Sin(d.a)
local integer i = 1
local real X3
local real Y3
local real PX
local real PY
local rect R
local boolexpr b
local timer T
local group g
local dat2 dd
if d.L < Disk_Lifespan_Base * d.lvl then
if Disk_Destroys_Trees == true then
set R = Rect(X1 - Disk_Tree_Destroy_Area, Y1 - Disk_Tree_Destroy_Area, X1 + Disk_Tree_Destroy_Area, Y1 + Disk_Tree_Destroy_Area)
call EnumDestructablesInRect(R, null, function Destroy_Destructs)
call RemoveRect(R)
set R = null
endif
if d.D <= Disk_Move_Distance and IsTerrainPathable(X2, Y2, PATHING_TYPE_WALKABILITY) != true then
call SetUnitPosition(d.c, X2, Y2)
set d.D = d.D + d.s
loop
exitwhen i > Disk_Part_Amount
set X3 = GetUnitX(d.p<i>)
set Y3 = GetUnitY(d.p<i>)
set d.A<i> = d.A<i> + Disk_Rotation_Speed
set PX = X1 + Disk_Size * Cos(d.A<i>)
set PY = Y1 + Disk_Size * Sin(d.A<i>)
call SetUnitPosition(d.p<i>, PX, PY)
set i = i + 1
endloop
else
set d.a = GetRandomReal(1, 360)
set d.D = 0
endif
set d.L = d.L + Timer_Interval
else
set i = 1
set dd = dd.create()
set g = CreateGroup()
set dd.c = Disk_Explosion_Knockback_Distance
set dd.OX = X1
set dd.OY = Y1
set dd.dmg = (Disk_Explosion_Dmg_Base * d.lvl)/ (Disk_Explosion_Knockback_Distance/Disk_Explosion_Knockback_Speed)
set dd.U = d.u
set T = CreateTimer()
set b = Condition(function Unit_Filter)
set bj_ghoul[40] = d.u
call GroupEnumUnitsInRange(g, X1, Y1, Disk_Explosion_AoE, b)
loop
set dd.P<i> = FirstOfGroup(g)
exitwhen dd.P<i> == null
set i = i + 1
call GroupRemoveUnit(g, dd.P[i-1])
endloop
call SetHandleInt(T, "dd", dd)
call TimerStart(T, Timer_Interval, true, function Knockback)
call DestroyBoolExpr(b)
call DestroyGroup(g)
call DestroyEffect(AddSpecialEffect(Disk_Explosion_SFX_1, X1, Y1))
call TriggerRemoveAction(d.trig, d.ta)
call FlushHandleLocals(d.trig)
call DestroyTrigger(d.trig)
call PauseTimer(t)
call FlushHandleLocals(t)
call d.destroy()
call DestroyTimer(t)
set T = null
set b = null
set g = null
endif
set t = null
endfunction
private function Cast takes nothing returns nothing
local location P = GetSpellTargetLoc()
local real m = GetUnitState(GetTriggerUnit(), UNIT_STATE_MANA)
local real A1 = GetLocationX(P)
local real B1 = GetLocationY(P)
local real A2
local real B2
local real ZX
local real m2
local boolean Z
local integer M = 1
local integer J = 0
local integer x = 1
local timer t
local real ang
local dat d
loop
exitwhen M > Disk_Part_Amount
set ZX = 360/Disk_Part_Amount * M * bj_DEGTORAD
set A2 = A1 + Disk_Size * Cos(ZX)
set B2 = B1 + Disk_Size * Sin(ZX)
if IsTerrainPathable(A2, B2, PATHING_TYPE_WALKABILITY) then
set J = 1
endif
set M = M + 1
endloop
set Z = IsTerrainPathable(A1, B1, PATHING_TYPE_WALKABILITY) != true and J == 0
call RemoveLocation(P)
set P = null
if Z == false then
call Error(GetOwningPlayer(GetTriggerUnit()), "Cannot create disk there" )
call TriggerSleepAction(0.1)
set m2 = GetUnitState(GetTriggerUnit(), UNIT_STATE_MANA)
call Refund(GetTriggerUnit(), m, m2, GetUnitAbilityLevel(GetTriggerUnit(), Main_Spell_ID))
return
endif
set t = CreateTimer()
set d = dat.create()
set d.u = GetTriggerUnit()
set d.c = CreateUnit(GetOwningPlayer(d.u), Disk_Centre_Part_ID, A1, B1, 0)
set d.lvl = GetUnitAbilityLevel(d.u, Main_Spell_ID)
set d.s = Disk_Move_Speed_Base * d.lvl * Disk_Move_Speed_Multiplier
set d.a = Atan2(B1-GetUnitY(d.u), A1-GetUnitX(d.u))
set d.a2 = GetRandomReal(1, 360)
set d.a3 = GetRandomInt(1, Disk_Part_Amount)
set d.D = 0
set d.L = 0
set d.trig = CreateTrigger()
call TriggerRegisterTimerEvent(d.trig, Disk_Dummy_Ability_Cast_Interval, true)
set d.ta = TriggerAddAction(d.trig, function Shoot_Flames)
call UnitApplyTimedLife(d.c, 039;BTLF039;, Disk_Lifespan_Base * d.lvl)
loop
exitwhen x > Disk_Part_Amount
set ang = 360/Disk_Part_Amount * x * bj_DEGTORAD
set d.p[x] = CreateUnit(GetOwningPlayer(d.u), Disk_Part_ID, A1 + Disk_Size * Cos(ang), B1 + Disk_Size * Sin(ang), Atan2(GetUnitY(d.p[x]) - B1, GetUnitX(d.p[x]) - A1))
set d.A[x] = Atan2(GetUnitY(d.p[x]) - B1, GetUnitX(d.p[x]) - A1)
call UnitApplyTimedLife(d.p[x], 039;BTLF039;, Disk_Lifespan_Base * d.lvl)
set x = x + 1
endloop
call SetHandleInt(d.trig, "d", d)
call SetHandleInt(t, "d", d)
call TimerStart(t, Timer_Interval, true, function Move_Disk)
set t = null
endfunction
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == Main_Spell_ID
endfunction
function InitTrig_Fire_Disk takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition(t, Condition( function Conditions ) )
call TriggerAddAction(t, function Cast )
set t = null
endfunction
endscope
</i></i></i></i></i></i></i></i></i></i></i></i></i></i>
Read Me:
* IMPLEMENTATION *
__________________
What's Needed?
--------------
>> Variable - "GameCache" (see variables menu)
>> Unit - "Dummy Caster"
>> Unit - "Fire Disk Center Part"
>> Unit - "Fire Disk Part"
>> Ability - "Fire Disk"
>> Ability - "Fire Disk Dummy Ability"
>> Trigger - "Fire Disk"
>> System - "Local Handle Vars" (located in the trigger header)
>> Tool - "JASS New Gen" (get it here if you don't have: http://wc3campaigns.net/showthread.php?t=90999)
How do I Implement The Spell?
-----------------------------
==Please Read Carefully If You're A Novice==
1. Firstly, copy and paste the needed abilities, units, trigger, system & game cache variable
into your map. Note that the system should be pasted into your map's trigger header,
& that the variable "GameCache" should have the same name when pasted into your map,
as in my map (quite important if your a novice). Also, the trigger needs to have exactly
the same name as well, with it being "Fire Disk" (don't forget the space).
2. Now look at the "Fire Disk" trigger under "globals".
The first 5 lines are what's gonna make the spell work properly.
Those numbers/letters 'A000', 'A001' ... etc, are called rawcodes.
'A000' is for the Fire Disk ability, and the others are for the dummy abilities and units.
Each object has a specific rawcode, which means they would've most likely changed
when they were pasted into your map.
What you need to do is to change those rawcodes to that of your map's rawcodes for
those 5 pieces of data.
Rawcodes can be viewed by pressing CTRL + D when in the Object Editor.
They will be the first 4 symbols next to your object's icon.
Replace all the rawcodes under "globals" accordingly with the rawcodes from your map, & remember
to put them between the ' marks (important).
3. Give the ability Fire Disk to some unit and test to see if it works.
If it fails, I advise you to read steps 1 & 2 again.
If you're getting errors with the trigger, check that the trigger's name is exactly
the same as the one in this map, and that you have all the stuff from " What's Needed?" in your map.
Have fun,
Tinki3
__________________
What's Needed?
--------------
>> Variable - "GameCache" (see variables menu)
>> Unit - "Dummy Caster"
>> Unit - "Fire Disk Center Part"
>> Unit - "Fire Disk Part"
>> Ability - "Fire Disk"
>> Ability - "Fire Disk Dummy Ability"
>> Trigger - "Fire Disk"
>> System - "Local Handle Vars" (located in the trigger header)
>> Tool - "JASS New Gen" (get it here if you don't have: http://wc3campaigns.net/showthread.php?t=90999)
How do I Implement The Spell?
-----------------------------
==Please Read Carefully If You're A Novice==
1. Firstly, copy and paste the needed abilities, units, trigger, system & game cache variable
into your map. Note that the system should be pasted into your map's trigger header,
& that the variable "GameCache" should have the same name when pasted into your map,
as in my map (quite important if your a novice). Also, the trigger needs to have exactly
the same name as well, with it being "Fire Disk" (don't forget the space).
2. Now look at the "Fire Disk" trigger under "globals".
The first 5 lines are what's gonna make the spell work properly.
Those numbers/letters 'A000', 'A001' ... etc, are called rawcodes.
'A000' is for the Fire Disk ability, and the others are for the dummy abilities and units.
Each object has a specific rawcode, which means they would've most likely changed
when they were pasted into your map.
What you need to do is to change those rawcodes to that of your map's rawcodes for
those 5 pieces of data.
Rawcodes can be viewed by pressing CTRL + D when in the Object Editor.
They will be the first 4 symbols next to your object's icon.
Replace all the rawcodes under "globals" accordingly with the rawcodes from your map, & remember
to put them between the ' marks (important).
3. Give the ability Fire Disk to some unit and test to see if it works.
If it fails, I advise you to read steps 1 & 2 again.
If you're getting errors with the trigger, check that the trigger's name is exactly
the same as the one in this map, and that you have all the stuff from " What's Needed?" in your map.
Have fun,
Tinki3
The spell looks far better in-game.
Enjoy.