Spell Flames from Heaven [vJass]

Status
Not open for further replies.

NeuroToxin

New Member
Reaction score
46
Okay, so I've been working on this one, and Here it is. I call it Flames from Heaven.

Flames of Heaven - [R]
Using the solar power from the sun, the firelord takes the energy and creates 12 fireballs that fly towards him, and explode, knocking back units near him, and dealing damage.
Level 1: Deals 10 damage per fireball, 100 knockback.
Level 2: Deals 15 damage per fireball, 150 knockback.
Level 3: Deals 20 damage per fireball, 200 knockback.
Level 4: Deals 25 damage per fireball, 250 knockback.

Credits to Jesus4lyf from thehelper.net for his system Key Timers 2.
Credits to Vexorian for JNGP.

Requires Jass Newgen Pack and Key Timers 2

In the near future: A smooth knockback.

Firelord.jpg

Code:
JASS:

scope FlamesofHeaven initializer Init
    globals
    
//The ability ID of the spell - Flames of Heaven
        private constant integer ABILITY_CODE = 'A000'
        
//The Unit ID of the dummy unit
        private constant integer DUMMY_ID = 'h000'
        
//The offset per movement
        private constant real OFFSET = 20
        
//The distance the units are created away from the caster.
        private constant integer DISTANCE = 900
        
//The special effect to be played for the explosion
        private constant string EXPLOSION = "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl"
        
//The attack type for the damage.
        private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL

//The damage type for the damage.
        private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL

//The weapon type for the damage.
        private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS

    endglobals
    
    private function DAMAGE takes integer lvl returns real
        return 5 + (lvl * 5.)
    endfunction
    
    private function NUM_DUMMIES takes integer lvl returns real
        return 12 + (lvl * 0.)
    endfunction
    
    private function AOE takes integer lvl returns real
        return 250 + (lvl * 0.)
    endfunction
    
    private function KNOCKBACK takes integer lvl returns real
        return 50 + (lvl * 50.)
    endfunction
    
    private function AOE_Expr takes nothing returns boolean
        local Flames f = Flames.FInteger
        return f.Caster != GetFilterUnit() and IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
    endfunction

    struct Flames
        unit Caster
        unit Dummyunit
        real Angle
        real Offset
        static integer FInteger
    endstruct
    
    private function DamageUnits takes nothing returns nothing
        local Flames f = Flames.FInteger
        local real damage = DAMAGE(GetUnitAbilityLevel(f.Caster, ABILITY_CODE))
        local real knockback = KNOCKBACK(GetUnitAbilityLevel(f.Caster, ABILITY_CODE))
        local real casterx = GetUnitX(f.Caster)
        local real castery = GetUnitY(f.Caster)
        local real targetx = GetUnitX(GetEnumUnit())
        local real targety = GetUnitY(GetEnumUnit())
        local real dx = targetx - casterx
        local real dy = targety - castery
        local real tempreal = SquareRoot( dx * dx + dy * dy )
        local real offsetx
        local real offsety
        local real angle = bj_RADTODEG * Atan2(targety - castery, targetx - casterx)
        call UnitDamageTarget(f.Caster, GetEnumUnit(), damage, true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
    loop
        exitwhen tempreal >= knockback
        set offsetx = targetx + 5 * Cos(angle * bj_DEGTORAD)
        set offsety = targety + 5 * Sin(angle * bj_DEGTORAD)
        call SetUnitX(GetEnumUnit(), offsetx)
        call SetUnitY(GetEnumUnit(), offsety)
        set tempreal = tempreal + 5
    endloop
    endfunction
    
    private function GroupEnum takes group g, real x, real y, real radius returns group
        call GroupEnumUnitsInRange( g, x, y, radius, Condition(function AOE_Expr))
        return g
    endfunction
    
    private function MovingFlames takes nothing returns boolean
        local Flames f = KT_GetData()
        local real offsetx
        local real offsety
        local group tempgroup
        local integer SENumber = 0
        local real radius = AOE(GetUnitAbilityLevel(f.Caster, ABILITY_CODE))
        local real casterx = GetUnitX(f.Caster)
        local real castery = GetUnitY(f.Caster)
        local real dummyx = GetUnitX(f.Dummyunit)
        local real dummyy = GetUnitY(f.Dummyunit)
        local real dx = casterx - dummyx
        local real dy = castery - dummyy
        local real tempreal = SquareRoot(dx * dx + dy * dy)
        local boolean cond = (tempreal >= 70)
    if cond then
        set f.Angle = f.Angle - 4
        set f.Offset = f.Offset - 10
        set offsetx = casterx + f.Offset * Cos(f.Angle * bj_DEGTORAD)
        set offsety = castery + f.Offset * Sin(f.Angle * bj_DEGTORAD)
        call SetUnitX(f.Dummyunit, offsetx)
        call SetUnitY(f.Dummyunit, offsety)
        call SetUnitFlyHeight(f.Dummyunit, GetUnitFlyHeight(f.Dummyunit) - 1, 0)  
    else
        set tempgroup = CreateGroup()
        call GroupEnum(tempgroup, casterx, castery, radius)
        set Flames.FInteger = f
        call ForGroup(tempgroup, function DamageUnits)
    loop
        exitwhen SENumber >= 2
        set offsetx = casterx + (20 * SENumber) * Cos((180 * SENumber) * bj_DEGTORAD)
        set offsety = castery + (20 * SENumber) * Sin((180 * SENumber) * bj_DEGTORAD)
        call DestroyEffect(AddSpecialEffect(EXPLOSION, offsetx, offsety))
        set SENumber = SENumber + 1
    endloop
        call RemoveUnit(f.Dummyunit)
        call f.destroy()
        return true
    endif
        return false
    endfunction
    
    private function CreateStructs takes unit u, player p, real a returns nothing
        local Flames f = Flames.create()
        local real x = GetUnitX(GetTriggerUnit())
        local real y = GetUnitY(GetTriggerUnit())
        local real offsetx = x + DISTANCE * Cos(a)
        local real offsety = y + DISTANCE * Sin(a)
        set f.Caster = u
        set f.Angle = a
        set f.Offset = DISTANCE
        set f.Dummyunit = CreateUnit( p, DUMMY_ID, offsetx, offsety, a)
        call KT_Add( function MovingFlames, f, 0.03 )
    endfunction

    private function OnCast takes nothing returns nothing
        local real num_dummies = NUM_DUMMIES(GetUnitAbilityLevel(GetTriggerUnit(), ABILITY_CODE))
        local integer index = 0
    if GetSpellAbilityId() == ABILITY_CODE then
    loop
        exitwhen index == num_dummies
        call CreateStructs(GetTriggerUnit(), GetTriggerPlayer(), (360 / 12) * index)
        set index = index + 1
    endloop
    endif
    endfunction

    //===========================================================================
    function Init takes nothing returns nothing
        local trigger t = CreateTrigger(  )
        local integer index = 0
        call TriggerAddAction( t, function OnCast )
    loop
        exitwhen index == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent( t, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set index = index + 1
    endloop
    endfunction
endscope
 

Attachments

  • Flames from Heaven.w3x
    29.6 KB · Views: 347

emjlr3

Change can be a good thing
Reaction score
395
  • why store num_dummies before you even know if you need to use it?
  • when creating structs, first store GetTriggerUnit() and GetTriggerPlayer().
  • 360/12 - this should be dependant on the number of dummies), also this should be in radians, not degrees.
  • DISTANCE and OFFSET should be level dependent.
  • An explanation for your configurable functions would be nice.
  • Store AOE when first cast.
  • When comparing distances, save yourself the SquareRoot call and compare it to the square of your break point.
  • Fly height should be a configurable, not just randomly set.
  • When grabbing units within a group, conduct all of your effects in the boolexpr function, to save yourself a forgroup call. Also, why not just use hte EnumUnitsinRange native?
  • Store Condition(function AOE_Expr) as a boolexpr global, it will be faster.
  • Again, DAMAGE and KNOCKBACK should be stored at the beggining of the spell, not calculated each time they are needed.
  • Your knockback is worthless. You would be better off just updating the units position once. It would achieve the same effect.
  • IMO, you need a better test map. With some camps, and revival triggers at least.


Stress tested. Runs smooth. The only time it started to hurt fps was during the end of spell when the explosion creations were all firing simultaneously.

I imagine from the post above though that this has a ll probably been mentioned previously, so I am probably wasting my breath.

It needs some work, but by no means is it terrible.
 

NeuroToxin

New Member
Reaction score
46
@ emjlr3 A lot of those have already been fixed, the problem, is that in my updated map, the knockback doesn't work. That's why I have that thread, knockback doesn't work, but everyone turned that into a debate about KT2. Also, will storing them in the struct provide more efficiency?
 

emjlr3

Change can be a good thing
Reaction score
395
so you submitted a half completed spell and expect it to be accepted? - closed until further notice. pm me if you figure out what you are doing.
 
Status
Not open for further replies.
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top