• 🏆 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!

Explosions

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
JASS:
scope Explosions initializer Initialization

    globals
        private constant integer SPELL_ID = 'A000'//Spell rawcode
        private constant string EFFECT_AOE = "abilities\\weapons\\catapult\\catapultmissile.mdl"//Special effect of the explosion
        private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL//Attack type
        private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL//Damage type
        private constant boolean KILL_TREES = true//Requires FFTSystem by KhaosMachine
        private constant boolean TERRAIN_DEFORMATION = true//If you want enable/disable the terrain deformations
        private constant boolean PRELOAD = true//Preload special effect
    endglobals

    function GetExplosions takes integer level returns integer
        return 3 + level//Total of explosions each level
    endfunction

    function GetDamage takes integer level returns real
        return 15. + 15. * level//Damage of each explosion each level
    endfunction

    private constant function GetAreaOfEffect takes integer level returns real
        return 120. + 20. * level//Area of effect of the explosions each level
    endfunction
    
    private constant function GetTargetType takes unit target, player owner returns boolean
        if /*
        */not IsUnitType(target, UNIT_TYPE_DEAD) /*//Target isn't dead
        */and not IsUnitType(target, UNIT_TYPE_STRUCTURE) /*//Target isn't a structure
        */and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) /*//Target isn't magic immune
        */and IsUnitEnemy(target, owner) /*//Target is enemy of caster
        */then
            return true
        endif
        return false
    endfunction
    
    globals
        private constant group TempGroup = CreateGroup()
    endglobals

    function Actions takes nothing returns boolean
        local unit caster
        local integer level
        local integer i = 0
        local integer explosions
        local real damage
        local real aoe
        local real aoeoe
        local real x
        local real y
        local unit j
        local unit du
        local location loc
        if GetSpellAbilityId() == SPELL_ID then
            set caster = GetTriggerUnit()
            set level = GetUnitAbilityLevel(caster, SPELL_ID)
            set explosions = GetExplosions(level)
            set damage = GetDamage(level)
            set aoeoe = GetAreaOfEffect(level)
            set aoe = aoeoe * 1.2
            loop
                exitwhen i >= explosions
                    set x = (GetUnitX(caster) + aoe / 1.25 * Cos(GetUnitFacing(caster) * bj_DEGTORAD)) + GetRandomReal(0, aoe) * Cos(GetRandomReal(0, 360) * bj_DEGTORAD)
                    set y = (GetUnitY(caster) + aoe / 1.25 * Sin(GetUnitFacing(caster) * bj_DEGTORAD)) + GetRandomReal(0, aoe) * Sin(GetRandomReal(0, 360) * bj_DEGTORAD)
                    call GroupEnumUnitsInRange(TempGroup, x, y, aoeoe, null)
                    loop
                        set j = FirstOfGroup(TempGroup)
                        exitwhen j == null
                        call GroupRemoveUnit(TempGroup, j)
                        if GetTargetType(j, GetTriggerPlayer()) then
                           call UnitDamageTarget(caster, j, damage, true, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                        endif
                    endloop
                    call DestroyEffect(AddSpecialEffect(EFFECT_AOE, x, y))
                    if TERRAIN_DEFORMATION then
                        call TerrainDeformWave(x, y, x, y, 3, 500, aoeoe, 20, 100, 3)
                    endif
                    if KILL_TREES then
                        set loc = Location(x, y)
                        set udg_FFT_Real_AreaOfEffect = aoeoe
                        set udg_FFT_Point_TargetPoint = loc
                        call ExecuteFunc("FFT_Kill")
                        call RemoveLocation(loc)
                    endif
                set i = i + 1
            endloop
            set caster = null
        endif
        return false
    endfunction

    public function PreloadSpell takes nothing returns nothing
        call Preload(EFFECT_AOE)
    endfunction

    function Initialization takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t, Condition(function Actions))
        if PRELOAD then
            call PreloadSpell()
        endif
        set t = null
    endfunction

endscope

Keywords:
explosions, blizzlike, rexxar, nice spell, blizzlike spell, jass, jass spell, blizzlike jass spell
Contents

Made by KhaosMachine (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 06:59, 23rd Jul 2012 Magtheridon96: Use static ifs to evaluate the constant booleans on compile time. You need some documentation for the spell. Using a tree destruction system is...
Status
Not open for further replies.

Moderator

M

Moderator

12th Dec 2015
IcemanBo: Too long as NeedsFix. Rejected.

06:59, 23rd Jul 2012
Magtheridon96:
  • Use static ifs to evaluate the constant booleans on compile time.
  • You need some documentation for the spell.
  • Using a tree destruction system is totally not worth it.
    Check out my spell code.
    I'm using a static rect. What I do first is set the rect's bounds, then store the distance
    squared into a variable (because I want to pick destructables in a circle, not a square),
    then I enumerate over the destructables in the rect. The isTree function I wrote is the most
    efficient and compact method ever to detect a tree. (Using a hashtable along with type registry
    is the fastest yet least compact methods). I'm taking advantage of how JASS "shortcircuits" boolean
    expressions with this function. If the first part returns false, the next won't even run, and the
    function would immediately return false. I'm checking if the distance between the destructable and
    the center is less than or equal to the radius and if the destructable is tree before I kill it.
    It's simple tree detection.
    You can totally copy the code if you want. :p
  • The global group "TempGroup" should be camelCased. (tempGroup)
  • Constant functions are the same as normal functions. Remove the 'constant' keyword and you'll save 9 bytes of file size. :p
    (Including the space that you have to include in between constant and one of the words next to it)
  • Your GetTargetType function can simply return the boolean expression you have in the if block.
    (return not IsUnitType(target, UNIT_TYPE_DEAD) and not ...)
  • Since the caster isn't going to be moving anywhere while your function is executing, it would be better to
    cache his coordinates OUTSIDE the loop so you don't have to repeat the call over and over again.
    You should probably do the same for the Sin and Cos of his facing.
  • Cos(GetRandomReal(0, 360) * bj_DEGTORAD) is exactly the same as GetRandomReal(-1,1)
  • It would be recommended to store the random generated reals so you can use the same ones
    when setting the variables x and y inside the loop. (Store GetRandomReal(-1,1) and use that variable,
    and do the same for GetRandomReal(0, aoe)).
    It wouldn't make a very huge difference, but it just seems better.
  • You should probably also cache the triggering player outside the loop since he will be constant
    for every iteration you make.
  • You have one useless local unit variable in your Actions function. (local unit du)
  • It would be better if you add comments and line breaks inside your code to make things a bit
    more readable.
 
Level 7
Joined
Aug 31, 2011
Messages
125
This doesn't even work properly ;o, If each person castes it, it orders all the units the casted the ability to recast it again ._.
-Translated to Spanish:-
Esto ni siquiera funciona bien ;o, si cada persona que las castas, que ordena todas las unidades del fundido la posibilidad de que la refundición de nuevo ._.
 
Level 6
Joined
Apr 16, 2011
Messages
158
1 - You need an image of the game, I did this if you want to use:
KhaosMachine.jpg

2 - Bjs you have many, try to transform them into native

simple examples given here
JASS:
function C takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction
JASS:
local integer l     = GetUnitAbilityLevelSwapped('A000', c)
// >>>
local integer l     = GetUnitAbilityLevel(c, 'A000')
JASS:
function InitTrig_Explosions takes nothing returns nothing
    local trigger E = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( E, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( E, Condition( function C ) )
    call TriggerAddAction( E, function A )
    set E = null
endfunction

instead of calling and destroy an effect you can call like this:
call DestroyEffect(AddSpecialEffectLoc(modelName, where))


GetRandomDirectionDeg
>>>
GetRandomReal(0, 360)

you need to improve their filters, BJ's in native,take a look at the forum, is not very dificel.

 
Level 10
Joined
Sep 19, 2011
Messages
527
JASS:
function DamageSfx takes nothing returns string
    return "Abilities\\Weapons\\BoatMissile\\BoatMissile.mdl"
endfunction

function ExplosionsSfx takes nothing returns string
    return "abilities\\weapons\\catapult\\catapultmissile.mdl"
endfunction

function ExplosionsRawcode takes nothing returns integer
    return 'A000'
endfunction

function Run takes nothing returns boolean
    local unit caster
    local integer level
    local integer i = 0
    local integer explosions
    local real damage
    local real aoe
    local real x
    local real y
    local unit j

    if GetSpellAbilityId() == ExplosionsRawcode() then
        set caster = GetTriggerUnit()
        set level = GetUnitAbilityLevel(caster, ExplosionsRawcode())
        set explosions = 2 * level
        set damage = 10.00 + 10.00 * level
        set aoe = 225.
        
        loop
            exitwhen i > explosions
            
            set x = (GetUnitX(caster) + aoe / 1.25 * Cos(GetUnitFacing(caster) * bj_DEGTORAD)) + GetRandomReal(0, aoe) * Cos(GetRandomReal(0, 360) * bj_DEGTORAD)
            set y = (GetUnitY(caster) + aoe / 1.25 * Sin(GetUnitFacing(caster) * bj_DEGTORAD)) + GetRandomReal(0, aoe) * Sin(GetRandomReal(0, 360) * bj_DEGTORAD)
            
            call DestroyEffect(AddSpecialEffect(ExplosionsSfx(), x, y))
            
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, aoe, null)
            
            loop
                set j = FirstOfGroup(bj_lastCreatedGroup)
                exitwhen j == null
                call GroupRemoveUnit(bj_lastCreatedGroup, j)
                
                if IsUnitEnemy(j, GetTriggerPlayer()) then
                    call UnitDamageTarget(caster, j, damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
                    call DestroyEffect(AddSpecialEffect(DamageSfx(), GetUnitX(j), GetUnitY(j)))
                endif
            endloop
            
            set i = i + 1
        endloop
        
        set caster = null
    endif
    
    return false
endfunction

function InitTrig_Explosions1 takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Run))
endfunction

Español:

No uses BJs (la mayoría son innecesarias).
No uses location, usa coordenadas.
Cuando creas variables, ponele nombres más descriptivos (así se hace mas fácil leerlos inclusive para vos).
Fijate como trabajo con los grupos (por ahora es la manera mas eficiente/rápida de trabajar con ellos).

bj_lastCreatedGroup: Usa este grupo cuando vallas a hacer únicamente enumeraciones de unidades (como en este caso, que lo único que tenes que hacer es agarrar las unidades y hacerles daño, nada mas).

Ponele nombres más descriptivos a tus funciones.

¿Viste las funciones ExplosionsRawcode, ExplosionsSfx y DamageSfx?, las hice para que el usuario pueda configurar fácilmente la habilidad (en este caso podemos modificar sin ningún problema los efectos y el RAWCODE del spell).

English:

Don't use BJs (mostly are unnecessary).
Don't use location, use cordinates instead.
When you create variables, put descriptive names to them (makes easy read the code).
Look how I work with groups (for now, this is the best way).

bj_lastCreatedGroup: Use this group when you only need a group for enumerate units.

Put descriptive names to your functions.

Do you see the ExplosionsRawcode, ExplosionsSfx and DamageSfx functions?, I make them to make easy the job to the user (for configurate things).

Greetings/Saludos.

EDIT: Solamente trabajo en el bloque de condiciones porque éste se ejecuta primero que las acciones, por ende es más rápido. / I only work in the condition block because it executes first than the actions, so this way is more faster.
 
Level 8
Joined
Dec 30, 2011
Messages
134
JASS:
function DamageSfx takes nothing returns string
    return "Abilities\\Weapons\\BoatMissile\\BoatMissile.mdl"
endfunction

function ExplosionsSfx takes nothing returns string
    return "abilities\\weapons\\catapult\\catapultmissile.mdl"
endfunction

function ExplosionsRawcode takes nothing returns integer
    return 'A000'
endfunction

function Run takes nothing returns boolean
    local unit caster
    local integer level
    local integer i = 0
    local integer explosions
    local real damage
    local real aoe
    local real x
    local real y
    local unit j

    if GetSpellAbilityId() == ExplosionsRawcode() then
        set caster = GetTriggerUnit()
        set level = GetUnitAbilityLevel(caster, ExplosionsRawcode())
        set explosions = 2 * level
        set damage = 10.00 + 10.00 * level
        set aoe = 225.
        
        loop
            exitwhen i > explosions
            
            set x = (GetUnitX(caster) + aoe / 1.25 * Cos(GetUnitFacing(caster) * bj_DEGTORAD)) + GetRandomReal(0, aoe) * Cos(GetRandomReal(0, 360) * bj_DEGTORAD)
            set y = (GetUnitY(caster) + aoe / 1.25 * Sin(GetUnitFacing(caster) * bj_DEGTORAD)) + GetRandomReal(0, aoe) * Sin(GetRandomReal(0, 360) * bj_DEGTORAD)
            
            call DestroyEffect(AddSpecialEffect(ExplosionsSfx(), x, y))
            
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, aoe, null)
            
            loop
                set j = FirstOfGroup(bj_lastCreatedGroup)
                exitwhen j == null
                call GroupRemoveUnit(bj_lastCreatedGroup, j)
                
                if IsUnitEnemy(j, GetTriggerPlayer()) then
                    call UnitDamageTarget(caster, j, damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
                    call DestroyEffect(AddSpecialEffect(DamageSfx(), GetUnitX(j), GetUnitY(j)))
                endif
            endloop
            
            set i = i + 1
        endloop
        
        set caster = null
    endif
    
    return false
endfunction

function InitTrig_Explosions1 takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Run))
endfunction

Español:

No uses BJs (la mayoría son innecesarias).
No uses location, usa coordenadas.
Cuando creas variables, ponele nombres más descriptivos (así se hace mas fácil leerlos inclusive para vos).
Fijate como trabajo con los grupos (por ahora es la manera mas eficiente/rápida de trabajar con ellos).

bj_lastCreatedGroup: Usa este grupo cuando vallas a hacer únicamente enumeraciones de unidades (como en este caso, que lo único que tenes que hacer es agarrar las unidades y hacerles daño, nada mas).

Ponele nombres más descriptivos a tus funciones.

¿Viste las funciones ExplosionsRawcode, ExplosionsSfx y DamageSfx?, las hice para que el usuario pueda configurar fácilmente la habilidad (en este caso podemos modificar sin ningún problema los efectos y el RAWCODE del spell).

English:

Don't use BJs (mostly are unnecessary).
Don't use location, use cordinates instead.
When you create variables, put descriptive names to them (makes easy read the code).
Look how I work with groups (for now, this is the best way).

bj_lastCreatedGroup: Use this group when you only need a group for enumerate units.

Put descriptive names to your functions.

Do you see the ExplosionsRawcode, ExplosionsSfx and DamageSfx functions?, I make them to make easy the job to the user (for configurate things).

Greetings/Saludos.

EDIT: Solamente trabajo en el bloque de condiciones porque éste se ejecuta primero que las acciones, por ende es más rápido. / I only work in the condition block because it executes first than the actions, so this way is more faster.

Usas JassNewGenPack?,, si es así por favor quiero que me digas como tenes configurado todo, porque yo no lo puedo usar correctamente... desde ya gracias por tu ayuda, voy a ir practicando más, recien empiezo con jass (;:ogre_hurrhurr:
 
This would be a more optimal solution:

JASS:
function DamageSfx takes nothing returns string
    return "Abilities\\Weapons\\BoatMissile\\BoatMissile.mdl"
endfunction

function ExplosionsSfx takes nothing returns string
    return "abilities\\weapons\\catapult\\catapultmissile.mdl"
endfunction

function ExplosionsRawcode takes nothing returns integer
    return 'A000'
endfunction

function GetNumberExplosions takes integer level returns integer
    return 2 * level
endfunction

function GetExplosionsDamage takes integer level returns real
    return 10. + 10 * level
endfunction

function GetExplosionsAoE takes integer level returns real
    return 225.
endfunction

function ExplosionsAttackType takes nothing returns attacktype
    return ATTACK_TYPE_NORMAL
endfunction

function ExplosionsDamageType takes nothing returns damagetype
    return DAMAGE_TYPE_NORMAL
endfunction

function ExplosionsActions takes nothing returns boolean
    local unit caster
    local unit target
    local integer level
    local integer i = 0
    local integer explosions
    local real damage
    local real aoe
    local real x
    local real y
    local real casterX
    local real casterY
    local real angle
    local real randAngle
    local real randAoE
    local player owner
    
    if GetSpellAbilityId() == ExplosionsRawcode() then
        set caster = GetTriggerUnit()
        set level = GetUnitAbilityLevel(caster, ExplosionsRawcode())
        set explosions = GetNumberExplosions(level)
        set damage = GetExplosionsDamage(level)
        set aoe = GetExplosionsAoE(level)
        
        set angle = GetUnitFacing(caster) * bj_DEGTORAD
        
        set casterX = GetUnitX(caster) + aoe / 1.25 * Cos(angle)
        set casterY = GetUnitY(caster) + aoe / 1.25 * Sin(angle)
        
        set owner = GetTriggerPlayer()
        
        loop
            exitwhen i >= explosions
            
            set randAngle = GetRandomReal(0, 360) * bj_DEGTORAD
            set randAoE = GetRandomReal(0, aoe)
            
            set x = casterX + randAoE * Cos(randAngle)
            set y = casterY + randAoE * Sin(randAngle)
            
            call DestroyEffect(AddSpecialEffect(ExplosionsSfx(), x, y))
            
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, aoe, null)
            loop
                set target = FirstOfGroup(bj_lastCreatedGroup)
                exitwhen target == null
                
                if IsUnitEnemy(target, owner) then
                    call UnitDamageTarget(caster, target, damage, false, false, ExplosionsAttackType(), ExplosionsDamageType(), null)
                    call DestroyEffect(AddSpecialEffect(DamageSfx(), GetUnitX(target), GetUnitY(target)))
                endif
                
                call GroupRemoveUnit(bj_lastCreatedGroup, target)
            endloop
            
            set i = i + 1
        endloop
        
        set caster = null
        set owner = null
    endif
    
    return false
endfunction

function InitTrig_Explosions1 takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function ExplosionsActions))
    set t = null
endfunction

It doesn't require JNGP by the way.
 
Level 4
Joined
Apr 18, 2011
Messages
60
This doesn't even work properly ;o, If each person castes it, it orders all the units the casted the ability to recast it again ._.
-Translated to Spanish:-
Esto ni siquiera funciona bien ;o, si cada persona que las castas, que ordena todas las unidades del fundido la posibilidad de que la refundición de nuevo ._.

i talk spanish and dont use google translator google is just not good >.<
corectly translated

"Esto nisiquiera funciona bien ;O, si cada persona usa la habilidad entonces ordena todas las unidades usando la habilidad les ordena usarla de nuevo ._."

well more or less :)

translate wisely man ¬¬
 
Level 10
Joined
Sep 19, 2011
Messages
527
This would be a more optimal solution:

Agree with the extra functions, but the extra variables, they're just useless (my opinion).

set t = null

Why the people here do this?
It's not necessary, you will never destroy a spell trigger.

EDIT: Nice boobs link :ogre_hurrhurr:

EDIT2:
Usas JassNewGenPack?,, si es así por favor quiero que me digas como tenes configurado todo, porque yo no lo puedo usar correctamente... desde ya gracias por tu ayuda, voy a ir practicando más, recien empiezo con jass (;

Español

Si, uso el NewGen. Lo único que debes hacer es descargarlo, descomprimirlo en cualquier parte y abrirlo (NewGen WE.exe). Cuando lo abras, vas a Reinventing the craft (en los menú de arriba) y destildas la opción que dice: "Enable Reinventing the craft".
Después cerras, y te bajas la actualización del JassHelper (así podes usar las nuevas actualizaciones de vJASS, ZINC, etc.).

Actualización: http://www.wc3c.net/attachment.php?attachmentid=48033&d=1266209195

Cuando lo termines de descargar, abrilo y busca la carpeta que dice "executables". Abrila y extraé su contenido en la carpeta jasshelper de tu NewGen. Las demás carpetas extraelas así nomas también en la carpeta jasshelper del NewGen.

Acordate que NewGen puede tener algunos problemas con algunos anti-virus, así que agregalo a las excepciones para que no haya problemas.

Saludos :).

English

Yes I do. The only you need to do is download, decompress in any folder and open it (NewGen WE.exe). When you open it, go to Reinventing the craft (in the top menues) and remove the tick from the Enable Reinventing the craft option.
Close it, and download the updates to the JassHelper (so you will can use the new features of vJASS, ZINC, etc.).

Update: http://www.wc3c.net/attachment.php?attachmentid=48033&d=1266209195

When you finish, open it and find the executables folder. Open it and decompress their content in the jasshelper folder of your NewGen.
The other folders decompress it in the jasshelper too.

Remember, NewGen can get some troubles with some anti-virus, so add it to exceptions to prevent errors.

Greetings.
 
Last edited:
Why the people here do this?
It's not necessary, you will never destroy a spell trigger.

type trigger extends agent

Thus, triggers increase the reference count.
The less the reference count, the greater the performance of the Jass Virtual Machine.
That's why nulling triggers is good :D

And those extra variables are used to make things run a tiny bit faster ;P
 
Level 10
Joined
Sep 19, 2011
Messages
527
Thus, triggers increase the reference count.
The less the reference count, the greater the performance of the Jass Virtual Machine.
That's why nulling triggers is good :D

Ah, now yes :D

And those extra variables are used to make things run a tiny bit faster ;P

owner has only 1 uses.

I don't know if those variables makes more faster the spell, I think that they are only to make easy read the code.
 
Last edited:
Status
Not open for further replies.
Top