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

Blast Orb v1.00

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Like
Reactions: eXcoScaRp
Here we go: my first real JASS spell, that I also try to make it follow JESP standards.


Spell Description:

The caster summons an orb made of pure electric energy. The orb will grow each second, increasing it's size, until it explodes. The bigger the orb is the more damage it wil deal when it implode. Orb will pull enemy units near it, and the bigger the orb is the bigger the pull range. For each second orb channels 100 damage and 100 AOE. Ally units in 450 AOE of the orb will have their movement and attack speed increased by 5 %.

Level 1 : Orb lasts 3 seconds.
Level 2 : Orb lasts 4 seconds.
Level 3 : Orb lasts 5 seconds.

So, like I said, my first real JASS spell. It's far from perfect, and I am welcoming any suggestions on how to improve my code, and If i left some leaks, point them to remove them. I hope you will all be full of understanding, and give me some nice comments :).

Credits:

Dr Super Good (for teaching me hashtables, and being such a nice and helping guy :))
BoneBreaker (for teaching me how to use constant functions)
emjlr3 (I thought many of JASS from looking at his spells)

Code is posted in a first comment. Comment and rate, please, and enjoy :).

Keywords:
Orb, Pull, Channel, Grow, Transparent, Damage Area
Contents

Just another Warcraft III map (Map)

Reviews
12th Dec 2015 IcemanBo: Too long time as NeedsFix. Rejected. 10:30, 5th Feb 2010 TriggerHappy: Please consider using vJass. And don't use locations, use coordinates. Also, you don't need to "null" reals and integers. FirstOfGroup loops...

Moderator

M

Moderator

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

10:30, 5th Feb 2010
TriggerHappy:

Please consider using vJass.
And don't use locations, use coordinates.

Also, you don't need to "null" reals and integers.

FirstOfGroup loops are bad, though in vanilla jass they are the most elegant solution I suppose.
 
Level 8
Joined
Jun 18, 2007
Messages
214
Here's the code:
JASS:
//***************************************************************************************************
//* ===================   
//* Blast Orb   
//* ===================  
//* Made by Shdow89 
//* 
//*
//* How to implement:
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* 1. Copy the spells Blast Orb, Orb Haste (dummy) to your map.
//* 
//*
//* 2. Copy the dummy unit Blast Orb Dummy, Dummy Caster(BlastOrb) to your map. To Blast Orb Dummy
//*    unit give the spell Orb Haste (dummy), and change the model path of the Dummy Caster(BlastOrb) unit
//*    to any model you like. If you like it doesn't have to be any model, you can set it to none.mdl.
//*
//* 3. Make a global variable of type hashtable and name it Hash.     
//*
//* 4. Copy Blast Orb buff to your map and make sure that spell Orb Hate (dummy) has that buff    
//* 
//*
//* 5. Copy this trigger to your map and the code in the custom script section of this map, and
//*    change the dummy unit raw codes in it to those in your map.
//*
//* 
//* Choosable/Effects:
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯   
//*    Go down through constant function and change to what you like. Units affected are:
//*    Enemy Units, Non-Magic immune, Non-Structures and living. This can not be changed in the constants. 
//*    But if you know your way around JASS I'm sure you'll find it with ease (I hope so).
//*
//* Editor's Word: 
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 
//*    This is my first real JASS spell, and I am not sure if it follows JESP standards.
//*    I'm open to all suggestions, and if I didn't remove some leaks point them to me, please.
//*    I'm also finding for comments on how to improve my code, everything is welcome.
//*    But please don't judge me, and start calling me noob if I did something wrong,
//*    like I said, this is my first real JASS spell, and I'm very proud if it :).
//*    Have fun, and I hope you'll enjoy :).
//* 
//* Credits:
//* ¯¯¯¯¯¯¯¯
//*    First and namely to Dr Super Good, for teaching me how to use hashtables.
//*    BoneBraker for teaching me how to use constants.
//*    emjlr3 whos spells forced me to learn JASS
//*   
//*
//*************************************************************************************************
constant function Blast_Orb_SFX_Explosion takes nothing returns string
    return "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl" // The effect for orb explosion
endfunction

constant function Blast_Orb_Unit_SFX takes nothing returns string
    return "Abilities\\Weapons\\Bolt\\BoltImpact.mdl" // The effect for damaged enemies
endfunction

constant function Blast_Orb_Rawcode takes nothing returns integer
    return 'A000' // Blast Orb Rawcode, change this to your rawcode
endfunction

constant function Orb_BuffID takes nothing returns integer
    return 'BTLF' // The buff ID for the unit exp. timer (Generic), you don't have to change this.
endfunction

constant function Blast_DummyID takes nothing returns integer
    return 'h000' // Blast Orb Dummy rawcode, CHANGE this to your code
endfunction

constant function Blast_DummyCasterID takes nothing returns integer
    return 'h001'// Dummy Caster(BlastOrb) rawcode, CHANGE this to your code. And change the model in the object editor, if you want.
endfunction

constant function Orb_Haste_AbilityID takes nothing returns integer
    return 'A001' // Orb Haste ability rawcode, CHANGE this to your code
endfunction

constant function Blast_Increment_Size takes nothing returns real
    return 1.00  // The orb size that changes every second(x1). Keep this under 5.
endfunction

constant function Blast_Orb_Pull_Loop takes nothing returns real
    return 0.03 // The speed of the timer, lower it is the faster it gets (can cause lagg if it's very low)
endfunction

constant function Blast_Orb_Time takes integer i returns integer
    return 2+i // The timer orb exists 2 + level of the Blast Orb ability seconds.
endfunction

constant function Blast_Orb_AOEDamage takes integer i returns real
    return 100.00*i // Damage and Area of Effect, that changes every secondU
endfunction

constant function Blast_Orb_Pull_Speed takes nothing returns real
    return 3.00 // Pull speed of the orb, higher it is, faster the pull
endfunction

constant function DummyCaster_Red takes nothing returns integer
    return 0.5 // Dummy Caster(BlastOrb) vertex coloring for color red
endfunction

constant function DummyCaster_Green takes nothing returns integer
    return 0.5 // Dummy Caster(BlastOrb) vertex coloring for color green
endfunction

constant function DummyCaster_Blue takes nothing returns integer
    return 0.5 // Dummy Caster(BlastOrb) vertex coloring for color blue
endfunction

constant function DummyCaster_Transparent takes nothing returns integer
    return 60 // Dummy Caster(BlastOrb) transparency
endfunction

constant function Blast_CasterAnimation takes nothing returns string
    return "channel" // Dummy Caster(BlatOrb) loop animation string
endfunction

//==========================================================================================
// If you know JASS, freely edit this. If not leave it as it is.

function Blast_Orb_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == Blast_Orb_Rawcode()
endfunction

function Blast_Orb_Filter takes nothing returns boolean // Filter function for picking units in group
    return IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false and (GetWidgetLife(GetFilterUnit())>0.405)
endfunction

function Blast_Orb_Pull_Group takes nothing returns nothing
    local timer t = GetExpiredTimer()
         
    local unit dummy = LoadUnitHandle(udg_Hash, GetHandleId(t), 1)
    local unit w      

    local location p = GetUnitLoc(dummy)
    local location p1
    local location p3

    local group g = GetUnitsInRangeOfLocAll(Blast_Orb_AOEDamage(GetUnitAbilityLevel(dummy, Orb_Haste_AbilityID())), p)
    loop
        set w = FirstOfGroup(g)
        exitwhen w == null
        call GroupRemoveUnit(g,w)
        
        if IsUnitEnemy(w, GetOwningPlayer(dummy)) and IsUnitType(w, UNIT_TYPE_STRUCTURE) == false and IsUnitType(w, UNIT_TYPE_MAGIC_IMMUNE) == false and (GetWidgetLife(w)>0.405) then
                       set p1 = GetUnitLoc(w)
                       set p3 = PolarProjectionBJ(p,(DistanceBetweenPoints(p, p1) - Blast_Orb_Pull_Speed()), AngleBetweenPoints(p, p1))
                       call SetUnitPositionLoc( w, p3)
                       call RemoveLocation(p1)
                       call RemoveLocation(p3)
        endif
    endloop
    set dummy = null
    set w = null
    call RemoveLocation(p)
    call DestroyGroup(g)
endfunction

function Blast_Orb_Actions takes nothing returns nothing
 local timer t = CreateTimer()
   
 local unit c = GetTriggerUnit()
 local unit dummy
 local unit dummy1

 local integer i = 0

 local real size = Blast_Increment_Size()

 local real x = GetSpellTargetX()
 local real y = GetSpellTargetY()

 local real x1 = GetUnitX(c)
 local real y1 = GetUnitY(c)

    set dummy = CreateUnit(GetOwningPlayer(c), Blast_DummyID(), x, y, 0)
    call UnitApplyTimedLife(dummy, Orb_BuffID(), Blast_Orb_Time(GetUnitAbilityLevel(c, Blast_Orb_Rawcode())))
    set dummy1 = CreateUnit(GetOwningPlayer(c), Blast_DummyCasterID(), x1, y1, GetUnitFacing(c))
        call SetUnitAnimation(dummy1, Blast_CasterAnimation())
        call SetUnitVertexColor(dummy1, DummyCaster_Red(), DummyCaster_Green(), DummyCaster_Blue(), DummyCaster_Transparent())
        
    call SaveUnitHandle(udg_Hash, GetHandleId(t), 1, dummy)
    call TimerStart(t, Blast_Orb_Pull_Loop(), true, function Blast_Orb_Pull_Group)
                            loop
                                set i = i+1
                                exitwhen i > Blast_Orb_Time(GetUnitAbilityLevel(c, Blast_Orb_Rawcode()))
                                call SetUnitScale(dummy, size, size, size)
                                 call SetUnitAbilityLevel(dummy, Orb_Haste_AbilityID(), i)
                                set size = size + Blast_Increment_Size()
                                call TriggerSleepAction(1)
                            endloop
    call DestroyTimer(t)
    call DamageEnemiesArea(c, Blast_Orb_AOEDamage(GetUnitAbilityLevel(dummy, Orb_Haste_AbilityID())), x, y, Blast_Orb_AOEDamage(GetUnitAbilityLevel(dummy, Orb_Haste_AbilityID())), true, false,ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS, Blast_Orb_Unit_SFX()) 
    call PauseUnit(dummy1, true)
    call ShowUnit(dummy1, false)
    call DestroyEffect(AddSpecialEffect(Blast_Orb_SFX_Explosion(), x, y))
    set c = null
    set dummy1 = null
    set i = 0
    set x = 0.00
    set y = 0.00
    set x1 = 0.00
    set y1 = 0.00
    set size = 0.00
endfunction

function InitTrig_Blast_Orb takes nothing returns nothing
    local trigger t = CreateTrigger()

    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Blast_Orb_Conditions))
    call TriggerAddAction(t, function Blast_Orb_Actions)
 
    set udg_Hash = InitHashtable()

    call Preload(Blast_Orb_SFX_Explosion())
    call Preload(Blast_Orb_Unit_SFX())

    set t = null
endfunction

Comments on how to implement and use can be found in the map.
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Checking :) if im in the mood i'll review :)

EDIT:
Fix all these:
JASS:
constant function DummyCaster_Red takes nothing returns integer
    return 0.5 // Dummy Caster(BlastOrb) vertex coloring for color red
endfunction

constant function DummyCaster_Green takes nothing returns integer
    return 0.5 // Dummy Caster(BlastOrb) vertex coloring for color green
endfunction

constant function DummyCaster_Blue takes nothing returns integer
    return 0.5 // Dummy Caster(BlastOrb) vertex coloring for color blue
endfunction

they should return real, otherwise they crashed my WC3
 
Level 8
Joined
Jun 18, 2007
Messages
214
Checking :) if im in the mood i'll review :)

EDIT:
Fix all these:
JASS:
constant function DummyCaster_Red takes nothing returns integer
    return 0.5 // Dummy Caster(BlastOrb) vertex coloring for color red
endfunction

constant function DummyCaster_Green takes nothing returns integer
    return 0.5 // Dummy Caster(BlastOrb) vertex coloring for color green
endfunction

constant function DummyCaster_Blue takes nothing returns integer
    return 0.5 // Dummy Caster(BlastOrb) vertex coloring for color blue
endfunction

they should return real, otherwise they crashed my WC3

They would? Well in SetUnitVertexColoring, it's asking for integers? Do you mean that it should return real as in value in constant function, or real number?
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
Ok, what you could do is either that these functions end with "returns real" and in the SetUnitVertexColoring you use R2I (real to integer) for each value, or you keep it as "returns integer" but you remove the decimal.

Ok I'm not gonna do a formal review since I'm too tired to do so, but:

Avoid this:
JASS:
GetUnitsInRangeOfLocAll(Blast_Orb_AOEDamage(GetUnitAbilityLevel(dummy, Orb_Haste_AbilityID())), p)
This leaks a group and is inefficient.

Here's what you do:
JASS:
constant function Filters takes nothing returns boolean
     return true
endfunction

JASS:
    local group g = CreateGroup()
     local fitlerfunc f = Filter(function Filters)
    call GroupEnumUnitsInRangeOfLoc(g, whichLocation, radius, f) //use coordinates btw, Loc is inefficient!
    call DestroyFilter(f)
    // then the ForGroup and then don't forget to destroy...


And you seriously need to avoid using points so that you are able of avoiding the usage of PolarProjectionBJ, DistanceBetweenPoints, and AngleBetweenPoints.

Oh, and try using vJass :) since you now know Jass, it'll take you a matter of 30 minutes to learn using vJass...
 
Level 8
Joined
Jun 18, 2007
Messages
214
Ok, what you could do is either that these functions end with "returns real" and in the SetUnitVertexColoring you use R2I (real to integer) for each value, or you keep it as "returns integer" but you remove the decimal.

Ok I'm not gonna do a formal review since I'm too tired to do so, but:

Avoid this:
JASS:
GetUnitsInRangeOfLocAll(Blast_Orb_AOEDamage(GetUnitAbilityLevel(dummy, Orb_Haste_AbilityID())), p)
This leaks a group and is inefficient.

Here's what you do:
JASS:
constant function Filters takes nothing returns boolean
     return true
endfunction

JASS:
    local group g = CreateGroup()
     local fitlerfunc f = Filter(function Filters)
    call GroupEnumUnitsInRangeOfLoc(g, whichLocation, radius, f) //use coordinates btw, Loc is inefficient!
    call DestroyFilter(f)
    // then the ForGroup and then don't forget to destroy...


And you seriously need to avoid using points so that you are able of avoiding the usage of PolarProjectionBJ, DistanceBetweenPoints, and AngleBetweenPoints.

Oh, and try using vJass :) since you now know Jass, it'll take you a matter of 30 minutes to learn using vJass...

Allrighty then, thank you for commenting, and helping, I'll get on to that, and reupload it today :)
 
Level 8
Joined
Jun 18, 2007
Messages
214
Anyways, I think the scaling should be smoother, it is just getting pumper bigger awkwardly, looking weird o_O
The effects are like o_O

A big boom followed by a smaller boom? The boom gives the feeling of the units being pushed outwards in my opinion.

Well you could change the scaling to happens every 0.50 seconds, or to change by .5 of it's size by the second. And yea, I always have trouble with SFX, couldnt find something that fits it :p. Anyway thx for commenting.
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
Inlined polar projections for X/Y:

X:
newx = x + offset * Cos(radian)

Y:
newy = y + offset * Sin(radian)

You should really replace GetUnitLoc() with GetUnitX/Y.

Get JNGP if you don't have it already and try using TESH to help you understand how to use non BJ calculations for radian between coordinates, distance between coordinates, etc.

EDIT:

Don't double post.
 
Level 8
Joined
Jun 18, 2007
Messages
214
Inlined polar projections for X/Y:

X:
newx = x + offset * Cos(radian)

Y:
newy = y + offset * Sin(radian)

You should really replace GetUnitLoc() with GetUnitX/Y.

Get JNGP if you don't have it already and try using TESH to help you understand how to use non BJ calculations for radian between coordinates, distance between coordinates, etc.

EDIT:

Don't double post.

You people amaze me xD. This spell is over 6 months old, and it was my first JASS spell. This spell is long history, and I'll just delete it, wasn't even sure someone will actually review it. Sorry, I didn't do anything about it sooner, but I just didn't have time lately to do anything. My spells now are WHOLE a LOT off different :p. Oh and about the double post: Did you see the time difference between the first and second post?
 
Top