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

[vJASS] Correct use of Dummy

Status
Not open for further replies.
Level 19
Joined
Mar 18, 2012
Messages
1,716
Hello everybody!
I have a question about the correct use of Dummy (by Nestharus). The way I coded this Fireball spell works (pretty sure) perfectly, but i used i used Dummy as

private static Dummy array dummies instead of an non array version.

Two Questions:

1) Is a non array use superior to an array usage or is it just a matter of "style".

2)If seen a couple of time:

private static method run takes nothing returns boolean
why boolean?

Thanks in advance.

Here is the code:

JASS:
globals
    private constant integer ABILITY_CODE = 'A03A'
    private constant real BALL_SPEED = 15.
    private constant real BALL_HEIGHT = 65.
    private constant string FIREBALL_PATH = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
    private constant string FIREBALL_EXPLODE = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl"
    private constant string EXPLOSION_PATH = ""
    private constant real AOE = 200.
    private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
    private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
endglobals

    private function GetDamage takes integer level returns real
        return 100. + 50*level
    endfunction

    private function GetRange takes integer level returns integer
        return 100//100 + 0*level
    endfunction

    private function TargetFilter takes unit caster, player owner, unit target returns boolean
        return not IsUnitType(target, UNIT_TYPE_STRUCTURE) and not IsUnitType(target, UNIT_TYPE_DEAD) and IsUnitEnemy(target, owner) and GetUnitAbilityLevel(target, 'Aloc') == 0
    endfunction

private struct Fireball extends array

    private static player array owner
    private static unit array caster
    private static constant real TIMEOUT = 0.03125
    private static group ENU = CreateGroup()
    private static integer array ticks
    private static real array facing
    private static real array x
    private static real array y
    private static effect array model
    private static real array damage
    private static Dummy array dummies /*better use no array ????*/
    
    implement CTTC
        local unit u
    implement CTTCExpire
    if ticks[this] >= 1 then
        set ticks[this] = ticks[this] - 1
            set x[this] = x[this] + BALL_SPEED*Cos(facing[this])
            set y[this] = y[this] + BALL_SPEED*Sin(facing[this])
        if x[this] < WorldBounds.maxX and x[this] > WorldBounds.minX and y[this] < WorldBounds.maxY and y[this] > WorldBounds.minY then
        
            if IsTerrainWalkable(x[this], y[this]) then
        
                call SetUnitX(dummies[this].unit, x[this])
                call SetUnitY(dummies[this].unit, y[this])
                
    
                call GroupEnumUnitsInRange(ENU, x[this], y[this], AOE, null)
                    
                    loop
                        set u = FirstOfGroup(ENU)
                        exitwhen u == null
                        call GroupRemoveUnit(ENU, u)
            
                        if TargetFilter(caster[this],owner[this], u) then
                            call UnitDamageTarget(caster[this], u, damage[this], false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                            call ArcingTextTag.create( "|cffff0000" + I2S(R2I(damage[this])) + "|r", u)
                            
                            call GroupClear(ENU)
                            call DestroyEffect(AddSpecialEffect(FIREBALL_EXPLODE,x[this], y[this]))
                            call DestroyEffect(model[this])
                            call dummies[this].destroy()
                            call this.destroy()
                            set owner[this] = null
                            set caster[this] = null
                        exitwhen true
                        endif
                    endloop
            else
                set ticks[this] = 0
            endif
        else
            set ticks[this] = 0
        endif
    else
        call DestroyEffect(AddSpecialEffect(FIREBALL_EXPLODE,x[this], y[this]))
        call DestroyEffect(model[this])
        call dummies[this].destroy()
        call this.destroy()
        set owner[this] = null
        set caster[this] = null
    endif

    implement CTTCNull
    implement CTTCEnd

    
    private static method run takes nothing returns nothing/*returns boolean???*/
        local thistype this = create()
        local integer level = GetUnitAbilityLevel(caster[this], ABILITY_CODE)
        
        set caster[this] = GetTriggerUnit()
        set owner[this] = GetTriggerPlayer()
        
        set damage[this] = GetDamage(level)
        set ticks[this] = GetRange(level)
        
        set facing[this] = Atan2(GetSpellTargetY() - GetUnitY(caster[this]), GetSpellTargetX() - GetUnitX(caster[this]))
        set x[this] = GetUnitX(caster[this])
        set y[this] = GetUnitY(caster[this])
        set dummies[this] = Dummy.create(x[this], y[this], facing[this]*bj_RADTODEG)
        set model[this] = AddSpecialEffectTarget(FIREBALL_PATH, dummies[this].unit, "origin")
        call SetUnitFlyHeight(dummies[this].unit, BALL_HEIGHT, 0)
      /*return false?????*/
    endmethod
        
    
    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(ABILITY_CODE, function thistype.run)
    endmethod
endstruct
 
(1) A non-array will allocate less memory. However, if you need the array, then use an array. If you are using an array of dummies (e.g. 2-3 or more) on the instance's spell cast, you may need to resort to a pseudo 2D-array or a hashtable.

(2) It returns boolean because RegisterSpellEffectEvent actually passes the function into a trigger condition, rather than a trigger action. Thus, all of the checking and functionality is consolidated into one function. PJASS may throw an error if you provide a function that does not return boolean. If you have an older version of JNGP, though, you might not get that error.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
If you want multiple copies of the missiles, then you are required to use an array.

1. No. It depends on what you are using it for.
2. It could be used for checking if the function was successful, another possibility, is that, the function in question will be used as parameters for Condition or Filter.


EDIT: PurgeandFire's answer was better than mine.
 
Thank you for the fast answer.

I think i will re-write the spell to a non array version.

I'm using JNGP 2.0.2

In the spell you posted, you need the array because it is part of the storage. Otherwise, it will lose its MUI. If you want to a avoid an array, you would have to use a hashtable (but that takes up memory as well, so arrays are a better option if you can easily integrate them).

Keep in mind that this code:
JASS:
struct Test
    static real array x

    method example takes nothing returns nothing 
        set x[this] = 5
    endmethod
endstruct
Is exactly the same as:
JASS:
struct Test 
    real x
    method example takes nothing returns nothing 
        set this.x = 5
    endmethod
endstruct

It may appear that the "x" in the second script is not an array, but internally it is doing the same as the first script.

why not use JNGP 5.0 ?

What is JNGP 5.0? :p The latest compilation is 2.0.X by moyack. I'm guessing you mean JNGP v5d, but that is actually an older version. It is still 100% usable, but moyack's version has some nice features.
 
Status
Not open for further replies.
Top