saw792
Is known to say things. That is all.
- Reaction score
- 280
Flaming Blades
Images:
Creates a cyclone of flaming blades that each deal damage on contact.
Level 1: 30 damage per blade
Level 2: 60 damage per blade
Level 3: 90 damage per blade
Made in vJASS:
MUI: Yes
Leakless: Seems to be
Comments and suggestions are welcome.
Thankyou.
EDIT: Updated
EDIT2: Updated, now uses a global timer.
Images:
Creates a cyclone of flaming blades that each deal damage on contact.
Level 1: 30 damage per blade
Level 2: 60 damage per blade
Level 3: 90 damage per blade
Made in vJASS:
JASS:
scope FlamingBlades initializer Init
//**************************************************************************
//
// Flaming Blades by saw792
//
// Requires:
// - a vJASS preprocessor
// - CSData (included in test map)
// - dummy.mdx (included in test map)
//
// Implementation:
// - Create a blank trigger, convert it to custom text
// - Paste this code into the space (replace other text)
// - Create a dummy unit using the dummy.mdx model
// - Create a dummy ability
// - Configure below
//
//***************************************************************************
// Configuration
//***************************************************************************
globals
//Rawcode of dummy ability
private constant integer ABIL_ID = 'A000'
//Rawcode of dummy unit
private constant integer DUMMY_ID = 'h000'
//Special effect that appears on the ground
private constant string SFX_GROUND = "Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeTarget.mdl"
//Special effect that appears in the cyclone
private constant string SFX_MISSILE = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl"
//Special effect path of the actual blade
private constant string SFX_BLADE = "Abilities\\Weapons\\BloodElfSpellThiefMISSILE\\BloodElfSpellThiefMISSILE.mdl"
//Radius of spinning blades
private constant real RADIUS = 250
//Max height of the cyclone
private constant real HEIGHT = 100
//Duration (in seconds)
private constant real DURATION = 5
//Timer interval (0.04 recommended, any lower will cause lag)
private constant real INTERVAL = 0.04
//Number of individual blades (must be greater than 2)
private constant integer NUMBER_OF_BLADES = 14
//Number of times the cyclone rotates every second
private constant real ROTATION = 2
//Length of time that the cyclone spins at double speed
private constant real DOUBLE_SPEED_TIME = 1
//Constant that controls the rate of expansion of the cyclone during the double speed time
//Recommended between -1 and 1
//Positive = expand, Negative = contract
private constant real EXPANSION_FACTOR = 0
//Damage (per level)that each blade will do upon contact with enemy unit
private constant real DAMAGE = 30
//Individual units can only be damaged this often (seconds)
//Multiple of interval is recommended
private constant real DAMAGE_TIME = 0.24
endglobals
//************************************************************************
// Do not edit below here
//************************************************************************
globals
private constant integer num = NUMBER_OF_BLADES - 1
private timer time
endglobals
private struct Data
unit array u [num]
real array x [num]
real array y [num]
effect array e [num]
effect f
real tx
real ty
integer ticks = 0
integer level
group g = CreateGroup()
group g2 = CreateGroup()
unit caster
static method create takes nothing returns Data
local Data d = Data.allocate()
local location s = GetSpellTargetLoc()
local integer i = 0
set d.caster = GetTriggerUnit()
set d.level = GetUnitAbilityLevel(d.caster, ABIL_ID)
set d.tx = GetLocationX(s)
set d.ty = GetLocationY(s)
set d.f = AddSpecialEffect(SFX_GROUND, d.tx, d.ty)
loop
exitwhen i == NUMBER_OF_BLADES
set d.u<i> = CreateUnit(GetOwningPlayer(GetTriggerUnit()), DUMMY_ID, d.tx, d.ty, 0)
set d.e<i> = AddSpecialEffectTarget(SFX_BLADE, d.u<i>, "origin")
call UnitAddAbility(d.u<i>, 'Amrf')
call UnitRemoveAbility(d.u<i>, 'Amrf')
set d.x<i> = d.tx + i * (RADIUS / (num)) * Cos((i * 360 / (NUMBER_OF_BLADES - 2)) * bj_DEGTORAD)
set d.y<i> = d.ty + i * (RADIUS / (num)) * Sin((i * 360 / (NUMBER_OF_BLADES - 2)) * bj_DEGTORAD)
call SetUnitFlyHeight(d.u<i>, i * (HEIGHT / (num)), 0)
set i = i + 1
endloop
call RemoveLocation(s)
set s = null
return d
endmethod
method onDestroy takes nothing returns nothing
local integer i = 0
call DestroyEffect(.f)
call DestroyGroup(.g)
call DestroyGroup(.g2)
loop
exitwhen i == NUMBER_OF_BLADES
call DestroyEffect(.e<i>)
call ShowUnit(.u<i>, false)
call KillUnit(.u<i>)
set i = i + 1
endloop
endmethod
endstruct
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == ABIL_ID
endfunction
private function Filt takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false
endfunction
private function Callback takes nothing returns nothing
local timer t = GetExpiredTimer()
local Data d = GetCSData(t)
local integer i = 0
local real j = (DURATION / INTERVAL) - (DOUBLE_SPEED_TIME / INTERVAL) - 1
local real k
local integer s = 0
local unit u
if ModuloReal(d.ticks, DAMAGE_TIME / INTERVAL) == 0 then
call GroupClear(d.g2)
endif
if d.ticks >= (DURATION / INTERVAL) then
call d.destroy()
call PauseTimer(t)
call DestroyTimer(t)
elseif d.ticks >= j then
loop
exitwhen i == NUMBER_OF_BLADES
set k = i * (RADIUS / (num)) + i * (d.ticks - j) * EXPANSION_FACTOR
if k < 0 then
set k = 0
endif
call GroupEnumUnitsInRange(d.g, d.x<i>, d.y<i>, 50, Filter(function Filt))
loop
set u = FirstOfGroup(d.g)
exitwhen u == null or s == 20
if IsUnitInGroup(u, d.g2) == false and IsUnitEnemy(u, GetOwningPlayer(d.caster)) then
call UnitDamageTarget(d.u<i>, u, DAMAGE * d.level , true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
call GroupAddUnit(d.g2, u)
call GroupRemoveUnit(d.g, u)
set s = s + 1
endloop
set d.x<i> = d.tx + k * Cos(((i * 360 / (NUMBER_OF_BLADES - 2)) + (d.ticks * (360 / (1 / INTERVAL / (2 * ROTATION))))) * bj_DEGTORAD)
set d.y<i> = d.ty + k * Sin(((i * 360 / (NUMBER_OF_BLADES - 2)) + (d.ticks * (360 / (1 / INTERVAL / (2 * ROTATION))))) * bj_DEGTORAD)
call SetUnitX(d.u<i>, d.x<i>)
call SetUnitY(d.u<i>, d.y<i>)
if i > (NUMBER_OF_BLADES / 2) then
call DestroyEffect(AddSpecialEffectTarget(SFX_MISSILE, d.u<i>, "origin"))
endif
set i = i + 1
endloop
set d.ticks = d.ticks + 1
else
loop
exitwhen i == NUMBER_OF_BLADES
call GroupEnumUnitsInRange(d.g, d.x<i>, d.y<i>, 50, Filter(function Filt))
loop
set u = FirstOfGroup(d.g)
exitwhen u == null or s == 20
if IsUnitInGroup(u, d.g2) == false and IsUnitEnemy(u, GetOwningPlayer(d.caster)) then
call UnitDamageTarget(d.u<i>, u, DAMAGE * d.level, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
call GroupAddUnit(d.g2, u)
call GroupRemoveUnit(d.g, u)
set s = s + 1
endloop
set d.x<i> = d.tx + i * (RADIUS / (num)) * Cos(((i * 360 / (NUMBER_OF_BLADES - 2)) + (d.ticks * (360 / (1 / INTERVAL / ROTATION)))) * bj_DEGTORAD)
set d.y<i> = d.ty + i * (RADIUS / (num)) * Sin(((i * 360 / (NUMBER_OF_BLADES - 2)) + (d.ticks * (360 / (1 / INTERVAL / ROTATION)))) * bj_DEGTORAD)
call SetUnitX(d.u<i>, d.x<i>)
call SetUnitY(d.u<i>, d.y<i>)
if i > (NUMBER_OF_BLADES / 2) then
call DestroyEffect(AddSpecialEffectTarget(SFX_MISSILE, d.u<i>, "origin"))
endif
set i = i + 1
endloop
set d.ticks = d.ticks + 1
endif
set u = null
endfunction
private function Actions takes nothing returns nothing
local Data d = Data.create()
set time = CreateTimer()
call SetCSData(time, d)
call TimerStart(time, INTERVAL, true, function Callback)
endfunction
private function Init 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 Actions)
set t = null
endfunction
endscope</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
MUI: Yes
Leakless: Seems to be
Comments and suggestions are welcome.
Thankyou.
EDIT: Updated
EDIT2: Updated, now uses a global timer.
Attachments
-
33 KB Views: 555