• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Ignition v1.4

  • Like
Reactions: Archangel678
Spell Name: Ignition

Short Description: Some sort of Wizard's Disintegrate spell in Diablo 3

Full Description:
Ignites an unstoppable line of fire in front of the caster which damages nearby enemy ground units. Spell will move along with the caster.

|cffffcc00Level 1|r - 25 damage per second, lasts 4 seconds.
|cffffcc00Level 2|r - 40 damage per second, lasts 6 seconds.
|cffffcc00Level 3|r - 55 damage per second, lasts 8 seconds.
|cffffcc00Level 4|r - 70 damage per second, lasts 10 seconds.
|cffffcc00Level 5|r - 85 damage per second, lasts 12 seconds.

Credits:
- Jass New Gen Pack (JNGP) by Vexorian
- T32 by Jesus4Lyf
- RegisterPlayerUnitEvent by Magtheridon96


JASS:
/*
=====Ignition v1.4
=====Made by: Mckill2009

REQUIRES:
- Jass New Gen Pack (JNGP) by Vexorian
- T32 by Jesus4Lyf
- RegisterPlayerUnitEvent by Magtheridon96

HOW TO USE:
- Make a trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
- Copy ALL that is written here and overwrite the existing texts in the custom text
- Copy the necessary libraries (T32 and RegisterPlayerUnitEvent)
- Replace the raw code as stated below if necessary...
- You can view the raw codes by pressing CTRL+B in the object editor
*/

library Ignition uses T32, RegisterPlayerUnitEvent

globals
    private constant integer            SPELL_ID = 'A000' //spell raw code
    //Configurables 
    private constant real                    AOE = 90 //highly recommended
    private constant real               GAP_DIST = 9 //the bigger this, the longer the line
    private constant real              SFX_SPEED = 0.1 //lower value will cause lag, this is recommended
    private constant attacktype              ATK = ATTACK_TYPE_PIERCE
    private constant damagetype              DMG = DAMAGE_TYPE_FIRE
    private constant string                  SFX = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
    private constant string                  LIG = "DRAL"
    //Not configurable
    private location LOC = Location(0,0)
endglobals

//Configurables:
private constant function GetDamage takes integer i returns real
    return 10 + i * 15.
endfunction

private constant function GetDuration takes integer i returns real
    return 2 + i * 2.
endfunction
//End of Configurables:

//Never touch the code below unless you know what you're doing
private constant function UnitAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction

private function GetUnitZ takes unit u returns real
    call MoveLocation(LOC, GetUnitX(u), GetUnitY(u)) 
    return GetLocationZ(LOC) + GetUnitFlyHeight(u)
endfunction

private struct IG
    unit caster
    real effectgap
    real duration
    real damage
    real maxdist
    lightning lig
    
    method periodic takes nothing returns nothing
        local unit u
        local real x 
        local real y
        local real angle 
        local real dist = 0
        if .duration > 0 and UnitAlive(.caster) then
            set angle = GetUnitFacing(.caster) * bj_DEGTORAD
            set .duration = .duration - T32_PERIOD
            loop
                set dist = dist + AOE
                set x = GetUnitX(.caster) + dist * Cos(angle)
                set y = GetUnitY(.caster) + dist * Sin(angle)
                call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE, null)  
                loop
                    set u = FirstOfGroup(bj_lastCreatedGroup)
                    exitwhen u==null
                    if UnitAlive(u) and not IsUnitType(u, UNIT_TYPE_FLYING) and IsUnitEnemy(.caster, GetOwningPlayer(u)) then
                        call UnitDamageTarget(.caster, u, .damage, false, false, ATK, DMG, null)
                    endif
                    call GroupRemoveUnit(bj_lastCreatedGroup, u)
                endloop
                exitwhen dist >= .maxdist
            endloop
            call MoveLightningEx(.lig, true, GetUnitX(.caster), GetUnitY(.caster), GetUnitZ(.caster)+100, x, y, GetUnitZ(.caster)+100)
            //To avoid lag
            set .effectgap = .effectgap + T32_PERIOD
            if .effectgap >= SFX_SPEED then
                set .effectgap = 0
                call DestroyEffect(AddSpecialEffect(SFX, x, y))
            endif
        else
            call DestroyLightning(.lig)
            call .stopPeriodic()
            call .destroy()              
        endif
    endmethod
    
    implement T32x
    
    private static method create takes unit u returns thistype
        local thistype this = thistype.allocate()
        local integer level = GetUnitAbilityLevel(u, SPELL_ID)     
        set .caster = u
        set .duration = GetDuration(level)
        set .damage = GetDamage(level) * T32_PERIOD
        set .lig = AddLightning(LIG, true, 0, 0, 0, 0) 
        set .maxdist = AOE * GAP_DIST
        set .effectgap = 0
        call .startPeriodic()
        return this
    endmethod

    private static method cond takes nothing returns boolean
        if GetSpellAbilityId()==SPELL_ID then
            call IG.create(GetTriggerUnit())
        endif
        return false
    endmethod

    private static method onInit takes nothing returns nothing
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.cond)
    endmethod

endstruct

endlibrary



Changelogs:
v1.4
- Table replaced by T32 and RegisterPlayerUnitEvent
- Filters replaced by loops
- Most of Maker's suggestion is applied
- Code improved

v1.3
- Converted to vJASS
- Uses Table by Bribe
- Description changed
- Priod interval reduced

v1.2
- PolarXY removed as function and applied directly
- Filter unit type is changed to UNIT_TYPE_FLYING==false because amphibious cant be damaged
- Local location replaced by global
- Timers replaced by Recycling timers

v1.1
- Location converted to coordinates
- GetUnitZ applied
- Loops applied
- Nulling of variables applied
- AoE reduced from 100 to 80


Keywords:
fire, disintegrate, flame, damage, diablo, lightning, mage, wizard
Contents

Ignition v1.4 (Map)

Reviews
Reviewed by Maker, Ignition v1.4, 30th Dec 2011 Approved, could be useful. I like how the special effect and group enumeration intervals are configurable. I still think it creates too many effects by default. Improvement suggestions...

Moderator

M

Moderator

Reviewed by Maker, Ignition v1.4, 30th Dec 2011

Approved, could be useful.

I like how the special effect and group enumeration intervals are configurable. I still think it creates too many effects by default.


Improvement suggestions.
  • Store GetUnitX and GetUnitY and GetOwningPlayer into variables in periodic method
  • Store Cos(angle) and Sin(angle) into variables


Maker, Ignition v1.3, 10th Nov 2011

The ability has buff Unknown B000. Change that.
JASS:
private function GetUnitZ takes unit u returns real
    call MoveLocation(LOC, GetUnitX(u), GetUnitY(u)) 
    set Z = GetLocationZ(LOC)
    return Z + GetUnitFlyHeight(u)
endfunction
->
JASS:
private function GetUnitZ takes unit u returns real
    call MoveLocation(LOC, GetUnitX(u), GetUnitY(u)) 
    return GetLocationZ(LOC) + GetUnitFlyHeight(u)
endfunction
^Then you don't need the global Z variable.
You could set x, y and angle in looper only in THEN portion, not when you declare the variabled.
Also multiply the facing with bj_DEGTORAD when you get the facing.
You don't need x, x1, y, y1. Only x and y. Set x = GetUnitX + dist * angle
I think the lightning's position could be updated more often. However, don't create effects that often.
Maybe you could use Constant Timer Loop 32 by Nestharus then.

08:52GMT, 14th Jun 2011
Bribe:

That global location does not need to be removed, just use "MoveLocation(udg_loc, GetUnitX(u), GetUnitY(u))"
 
Level 15
Joined
Jul 6, 2009
Messages
889
1.) In function "IG_FILTER", you don't null "u".
2.) Why the absurd use of locations? Simply use coordinates. If you aren't sure how, just ask.
3.) In function "IG_LOOP", you don't null "t".
4.) In function "IG_CAST", you don't null "t".
5.) Those configurable functions should be constant.
6.) AddLightningEx does not factor in z in it's z parametre, you will need to calculate yourself. So, GetLocationZ() + 100.
7.) May I ask why you have unusual spacing?
JASS:
    local trigger t                          = CreateTrigger()          
    call TriggerRegisterAnyUnitEventBJ      (t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition                (t, Condition(function IG_CAST)) 
    set t                                    = null
8.) You shouldn't be initialising locals in the function "IG_CAST". Reason is that for every spell that is cast in the game, you will be redundantly setting them. You should move them under the if, or better yet, create a new function to be called to avoid having to declare local variables.
9.) Why are you creating the lightning with AddLightningEx, but moving it with MoveLightning?
10.) You may want to try use loops rather than declare a numerous amount of local variables in the "IG_LOOP" function.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
To all who comment, thanks guys...

1.) In function "IG_FILTER", you don't null "u".
2.) Why the absurd use of locations? Simply use coordinates. If you aren't sure how, just ask.
3.) In function "IG_LOOP", you don't null "t".
4.) In function "IG_CAST", you don't null "t".
5.) Those configurable functions should be constant.
6.) AddLightningEx does not factor in z in it's z parametre, you will need to calculate yourself. So, GetLocationZ() + 100.
7.) May I ask why you have unusual spacing?
JASS:
    local trigger t                          = CreateTrigger()          
    call TriggerRegisterAnyUnitEventBJ      (t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition                (t, Condition(function IG_CAST)) 
    set t                                    = null
8.) You shouldn't be initialising locals in the function "IG_CAST". Reason is that for every spell that is cast in the game, you will be redundantly setting them. You should move them under the if, or better yet, create a new function to be called to avoid having to declare local variables.
9.) Why are you creating the lightning with AddLightningEx, but moving it with MoveLightning?
10.) You may want to try use loops rather than declare a numerous amount of local variables in the "IG_LOOP" function.

1,3,4 - I didnt notice the nullings, gonna update it...
2 - I tried coordinates but it failed to rotate/follow the correct path, perhaps you can show me...
5 - yeah gonna fix that as well...
6 - That doesnt work, I've tried it before...
7 - It's just my style, nothing special :)...
8 - GOnna do that...
9 - I just forgot to change it...
10 - I'll try that...

thanks for your comment :)...
 
you should just seriously loop those reals on IG_LOOP and also, instead of using a custom function for polar proj, just use the formula directly for the x,y... coz right now, that custom function is dragging this down... you make it return a location, but then you use GetLocationX/Y afterwards... you should just use the formula for x,y projection directly for the x,y values rather than creating a lot of locations that are unnecessary... and if you made the reals just inside a loop, you'll only write the formulas twice (one for x, one for y) and you would only need one real x and one real y...
 
Nice Job :)
Just one small comment...
JASS:
function GetUnitZ takes unit u returns real
    local location loc = Location(0, 0)
    local real Z
    call MoveLocation(loc, GetUnitX(u), GetUnitY(u))
    set Z = GetLocationZ(loc)
    call RemoveLocation(loc)
    set loc = null
    return Z + GetUnitFlyHeight(u)
endfunction
Could you give those functions prefixes?
This function can create some problems with other functions that have the same name..
Also, the function name "GetUnitZ" is a bit too generic =P
There are some libraries in the Jass section that have that name already, so maybe
something like "IG_GetUnitZ" would be fine ^^
 
Level 15
Joined
Jul 6, 2009
Messages
889
In your "GetUnitZ" function, you should use a global location. So, initialize udg_SomeRandomLocation as Location(0., 0.), then replace the "loc" in your function with it. No need to create/remove locations constantly.

JASS:
function GetUnitZ takes unit u returns real
    local location loc = Location(0, 0)
    local real Z
    call MoveLocation(loc, GetUnitX(u), GetUnitY(u))
    set Z = GetLocationZ(loc)
    call RemoveLocation(loc)
    set loc = null
    return Z + GetUnitFlyHeight(u)
endfunction

By the way, you could have just initialized "loc" as Location(GetUnitX(u), GetUnitY(u)), could you not?
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
That sounds retarded... Why would they be faster?
(Nope, I am not experienced in this part...)

Nobody has meassured on what's faster...there's nothing wrong with your comment coz I have done that before...

But take note that if I follow your advice, your calling two function, the TriggerAddCondition AND TriggerAddAction...

While this is calling just ONE function...
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
Of course they are faster as they run earlier. It's based on logic.

1, 2 and 3. 1 Always comes first and 2 always comes before 3. (Probably the worst example ever but whatever)

@the spell

use a global location for the GetUnitZ check, useless to create and destroy and also why are you creating it and then moving it? It can just be created at the new coordinates

JASS:
local location loc = Location(0, 0)
    local real Z
    call MoveLocation(loc, GetUnitX(u), GetUnitY(u))

->

JASS:
local location loc = Location(GetUnitX(u), GetUnitY(u))
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
NO NO NO NO THIS IS NOT WHAT I MEANT WITH A GLOBAL LOCATION!

You don't have to remove it. At ini you set it as "Location(0.,0.)" and afterwards in the GetUnitZ function you only call "MoveLocation(udg_yourloc, GetUnitX(yourunit), GetUnitY(yourunit))"

You never have to remove it ever :D And it will not leak either (and those who say that it leaks...)
 
Level 10
Joined
Sep 19, 2011
Messages
527
Your code looks great, but here you have just a little details.

local timer t = CreateTimer()

Why you're creating that local timer?

call IG.create(GetTriggerUnit())

->

call thistype.create(GetTriggerUnit())

If you use allocate, then when you destroys the instance, you need to call deallocate.

private constant function UnitAlive takes unit u returns boolean

I found this function useless.

The rest is fine (to me), nice spell, very creative :D.

Greetings
 
Level 7
Joined
Sep 2, 2011
Messages
350
I really like this spell a lot. I've been looking for a spell like this for quite sometime now. Just a question, where can you change the color of the lightning?

Rating: 4.5/5
Simple yet cool
MUI and Leakless
The coding can still be improved
Other than that, it is awesome.


Happy Holidays
 
Top