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

Dummy Unit - Submission

Status
Not open for further replies.
vJASS:
scope DummyUnit initializer Init

    globals
        unit hero
        group dummies = CreateGroup()
        hashtable hash = InitHashtable()
    endglobals

    private function Spawn takes nothing returns nothing
        set hero = CreateUnit(GetLocalPlayer(),'Otch',0,0,bj_UNIT_FACING)
    endfunction

    private function Esc takes nothing returns nothing
        local integer c = 1
        local real x = GetUnitX(hero)
        local real y = GetUnitY(hero)
        local real f = GetUnitFacing(hero)
        local location l = GetUnitLoc(hero)
        local unit g
             
        loop
            exitwhen c > 8
            set g = CreateUnitAtLoc(GetLocalPlayer(),'h000',l,c*45)
            call SaveInteger(hash,0,GetHandleId(g),0)
            call GroupAddUnitSimple(g,dummies)
            set c = c + 1
        endloop
       
        set g = null
        call RemoveLocation(l)
    endfunction
   
    private function Damage takes nothing returns nothing
        local unit t = GetEnumUnit()
        if IsPlayerEnemy(GetOwningPlayer(t),GetLocalPlayer()) == true then
            call UnitDamageTarget(hero,t,4,true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
        endif
       
        set t = null
    endfunction
   
    private function MoveDummy takes nothing returns nothing
        local unit d = GetEnumUnit()
        local location l = GetUnitLoc(d)
        local location t = PolarProjectionBJ(l,50,GetUnitFacing(d))
        local integer i = LoadInteger(hash,0,GetHandleId(d))
        local group targets = CreateGroup()
               
        if i < 1000 then
            call SetUnitPositionLoc(d,t)
            call SaveInteger(hash,0,GetHandleId(d),i+50)
            set targets = GetUnitsInRangeOfLocAll(150,t)
            call ForGroup(targets,function Damage)
        else
            call GroupRemoveUnit(dummies,d)
            call KillUnit(d)
            call RemoveUnit(d)
        endif
       
        set d = null
        call GroupClear(targets)
        call DestroyGroup(targets)
        call RemoveLocation(l)
        call RemoveLocation(t)
        set targets = null
    endfunction
   
    private function Move takes nothing returns nothing
        call ForGroup(dummies, function MoveDummy)
    endfunction

    private function Init takes nothing returns nothing
        local trigger trg = CreateTrigger()
       
        call TriggerRegisterTimerEvent(trg,0.2,false)
        call TriggerAddAction(trg, function Spawn)
       
        set trg = CreateTrigger()
        call TriggerRegisterPlayerEventEndCinematic(trg,GetLocalPlayer())
        call TriggerAddAction(trg,function Esc)
       
        set trg = CreateTrigger()
        call TriggerRegisterTimerEvent(trg,0.04,true)
        call TriggerAddAction(trg,function Move)
    endfunction

endscope
 

Attachments

  • JASS Class - Dummy.w3x
    26.7 KB · Views: 49

Jampion

Code Reviewer
Level 15
Joined
Mar 25, 2016
Messages
1,327
One really nice advantage of JASS over GUI is, that you can use coordinates instead of locations. Coordinates are generally faster and do not have to be removed or nulled.

You can make global variables private. You might wanna use hero and hash in different triggers as well, but I think dummies should definitely be private. I don't have much experience with protecting in JASS, so I am not sure, what's the best way to do it.

In your "Esc" function, you do not use x, y and f. I would use coordinates rather than locations, but you should definitely not declare variables, you are not using.

GroupAddUnitSimple is an unnecessary function call; use the native. If a function has "swapped" or "Simple" in its name, you should use the native instead.

After you have removed the location, you must still null it (you should null all handles).

In your damage function you should not use "GetLocalPlayer", because I think it would cause desyncs in multiplayer maps. I don't know much about desyncs, so you should wait what IcemanBo has to say about it.

You can also just spawn the hero in the init function without creating a trigger for it, but that's up to you, what you prefer.
 
I was aware that it was quite faster to use direct coordinates, but didn't understand all the math behind them, but after studying a little bit I think I got something more acceptable.

Forgot to private those globals, that was a complete lack of attention.

Now x and y have an use.

Didn't know the difference between the GroupAddUnitSimple and GroupAddUnit, so I just used the first one, still on the learning curve...

No locations to null now, lol

I'm not sure about the GetLocalPlayer either, so I'm keeping it there for now

Yeah, I do like to use a separate trigger for it, to keep Init nice and clean

Anyway, here's the updated code and map

vJASS:
scope DummyUnit initializer Init

    globals
        private unit hero
        private group dummies = CreateGroup()
        private hashtable hash = InitHashtable()
    endglobals

    private function Spawn takes nothing returns nothing
        set hero = CreateUnit(GetLocalPlayer(),'Otch',0,0,bj_UNIT_FACING)
    endfunction

    private function Esc takes nothing returns nothing
        local integer c = 1
        local real f = GetUnitFacing(hero)
        local real x = GetUnitX(hero)
        local real y = GetUnitY(hero)
        local unit g
             
        loop
            exitwhen c > 8
            set g = CreateUnit(GetLocalPlayer(),'h000',x,y,c*45)
            call SaveInteger(hash,0,GetHandleId(g),0)
            call GroupAddUnit(dummies,g)
            set c = c + 1
        endloop
       
        set g = null
    endfunction
   
    private function Damage takes nothing returns nothing
        local unit t = GetEnumUnit()
       
        if(IsPlayerEnemy(GetOwningPlayer(t),GetLocalPlayer()) and GetWidgetLife(t) > 0.405 and IsUnitType(t,UNIT_TYPE_FLYING) == false and IsUnitType(t,UNIT_TYPE_MAGIC_IMMUNE) == false) then
            call UnitDamageTarget(hero,t,4,true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
        endif
       
        set t = null
    endfunction
   
    private function MoveDummy takes nothing returns nothing
        local unit d = GetEnumUnit()
        local real x = GetUnitX(d)
        local real y = GetUnitY(d)
        local real tx = x + 40 * Cos(GetUnitFacing(d) * bj_DEGTORAD)
        local real ty = y + 40 * Sin(GetUnitFacing(d) * bj_DEGTORAD)
        local integer i = LoadInteger(hash,0,GetHandleId(d))
        local group targets = CreateGroup()
               
        if i < 1000 then
            call SetUnitPosition(d,tx,ty)
            call SaveInteger(hash,0,GetHandleId(d),i+40)
            call GroupEnumUnitsInRange(targets,tx,ty,150,null)
            call ForGroup(targets,function Damage)
        else
            call GroupRemoveUnit(dummies,d)
            call RemoveUnit(d)
        endif
       
        call GroupClear(targets)
        call DestroyGroup(targets)
        set targets = null
        set d = null
    endfunction
   
    private function Move takes nothing returns nothing
        call ForGroup(dummies, function MoveDummy)
    endfunction

    private function Init takes nothing returns nothing
        local trigger trg = CreateTrigger()
       
        call TriggerRegisterTimerEvent(trg,0.2,false)
        call TriggerAddAction(trg, function Spawn)
       
        set trg = CreateTrigger()
        call TriggerRegisterPlayerEventEndCinematic(trg,GetLocalPlayer())
        call TriggerAddAction(trg,function Esc)
       
        set trg = CreateTrigger()
        call TriggerRegisterTimerEvent(trg,0.04,true)
        call TriggerAddAction(trg,function Move)
       
        set trg = null
    endfunction

endscope
 

Attachments

  • JASS Class - Dummy.w3x
    26.8 KB · Views: 52
LocalPlayer is the player on the local machine. When we both would play a game together, then you're the local player on your side, and I'm the local player on my side.
-> the condition brings different results depending on each player -> for some players the unit might get damaged, for some players not -> unit interfares with all players and have async data -> desync

Yeah, I do like to use a separate trigger for it, to keep Init nice and clean
You create one trigger, register one event to it, and add one action to it + implement a new function with one create unit function call
VS
one create unit function call
->
Not sure the first is more clean, and it only runs just once on map init. :)

Local unit variables should be nulled at the end of one function.

Does the map also contain code for the dummy caster?
 
I don't know if it's a bad habit, I just take it from the little experience I have programming. I like to see each function with it's sole and only purpose, so if Init is supposed to initialize the triggers, it is going to do only that and no other code will be inserted in it, if something else should happen during the first seconds of the map then Init will call that function instead of running it itself. I don't always follow this rule, but whenever I remember to do it I prefer to do it, this helps me to read the code later, is somewhat more intuitive for me.

I couldn't find any local unit variable that hasn't been nulled, sry ô.õ

It did contain the code for the dummy caster, but I was unsure if it was a requirement or not so I removed it
That's also why there's a Swap spell in the object editor, I was planning to use it to swap between the dummy caster and the dummy shockwave spells, guess there's my chance to do just that now.
_______________________________________________________________________________________________

Edit:

vJASS:
scope DummyUnit initializer Init

    globals
        private unit hero
        private boolean swap = false
        private group dummies = CreateGroup()
        private hashtable hash = InitHashtable()
    endglobals

    private function Spawn takes nothing returns nothing
        set hero = CreateUnit(GetLocalPlayer(),'Otch',0,0,bj_UNIT_FACING)
    endfunction
   
    private function Swap takes nothing returns nothing
        if GetSpellAbilityId() == 'A001' then
            if swap == false then
                set swap = true
                call BJDebugMsg("Dummy Caster")
            else
                set swap = false
                call BJDebugMsg("Dummy Shockwave")
            endif
        endif
    endfunction

    private function Esc takes nothing returns nothing
        local integer c = 1
        local real f = GetUnitFacing(hero)
        local real x = GetUnitX(hero)
        local real y = GetUnitY(hero)
        local unit g
       
        if swap == false then
            loop
                exitwhen c > 8
                set g = CreateUnit(GetLocalPlayer(),'h000',x,y,c*45)
                call SaveInteger(hash,0,GetHandleId(g),0)
                call GroupAddUnit(dummies,g)
                set c = c + 1
            endloop
        else
            set g = CreateUnit(GetLocalPlayer(),'h001',x,y,f)
            set x = x + 1 * Cos(f * bj_DEGTORAD)
            set y = y + 1 * Sin(f * bj_DEGTORAD)
            call UnitAddAbility(g,'A000')
            call IssuePointOrder(g,"shockwave",x,y)
            call SaveReal(hash,1,GetHandleId(g),f + 45.)
            call SaveInteger(hash,2,GetHandleId(g),1)
        endif
       
        set g = null
    endfunction
       
    private function Cast takes nothing returns nothing
        local unit d = GetTriggerUnit()
        local real a = LoadReal(hash,1,GetHandleId(d))
        local integer c = LoadInteger(hash,2,GetHandleId(d))
        local real x = GetUnitX(hero)
        local real y = GetUnitY(hero)
        local real tx = x + 1 * Cos(a * bj_DEGTORAD)
        local real ty = y + 1 * Sin(a * bj_DEGTORAD)
       
        if GetSpellAbilityId() == 'A000' then
            call UnitRemoveAbility(d,'A000')
            call UnitAddAbility(d,'A000')
            call SetUnitPosition(d,x,y)
            call IssuePointOrder(d,"shockwave",tx,ty)
            set a = a + 45.
            set c = c + 1
            call SaveReal(hash,1,GetHandleId(d),a)
            call SaveInteger(hash,2,GetHandleId(d),c)
            if c == 10 then
                call RemoveUnit(d)
            endif
        endif
       
        set d = null
    endfunction
       
    private function Damage takes nothing returns nothing
        local unit t = GetEnumUnit()
       
        if(IsPlayerEnemy(GetOwningPlayer(t),GetLocalPlayer()) and GetWidgetLife(t) > 0.405 and IsUnitType(t,UNIT_TYPE_FLYING) == false and IsUnitType(t,UNIT_TYPE_MAGIC_IMMUNE) == false) then
            call UnitDamageTarget(hero,t,4,true,true,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
        endif
       
        set t = null
    endfunction
   
    private function MoveDummy takes nothing returns nothing
        local unit d = GetEnumUnit()
        local real x = GetUnitX(d)
        local real y = GetUnitY(d)
        local real tx = x + 40 * Cos(GetUnitFacing(d) * bj_DEGTORAD)
        local real ty = y + 40 * Sin(GetUnitFacing(d) * bj_DEGTORAD)
        local integer i = LoadInteger(hash,0,GetHandleId(d))
        local group targets = CreateGroup()
               
        if i < 1000 then
            call SetUnitPosition(d,tx,ty)
            call SaveInteger(hash,0,GetHandleId(d),i+40)
            call GroupEnumUnitsInRange(targets,tx,ty,150,null)
            call ForGroup(targets,function Damage)
        else
            call GroupRemoveUnit(dummies,d)
            call RemoveUnit(d)
        endif
       
        call GroupClear(targets)
        call DestroyGroup(targets)
        set targets = null
        set d = null
    endfunction
   
    private function Move takes nothing returns nothing
        call ForGroup(dummies, function MoveDummy)
    endfunction

    private function Init takes nothing returns nothing
        local trigger trg = CreateTrigger()
       
        call TriggerRegisterTimerEvent(trg,0.2,false)
        call TriggerAddAction(trg, function Spawn)
       
        set trg = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(trg,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddAction(trg,function Swap)
       
        set trg = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(trg,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddAction(trg,function Cast)

        set trg = CreateTrigger()
        call TriggerRegisterPlayerEventEndCinematic(trg,GetLocalPlayer())
        call TriggerAddAction(trg,function Esc)
       
        set trg = CreateTrigger()
        call TriggerRegisterTimerEvent(trg,0.04,true)
        call TriggerAddAction(trg,function Move)
       
        set trg = null
    endfunction

endscope
 

Attachments

  • JASS Class - Dummy.w3x
    27.9 KB · Views: 48
TriggerRegisterPlayerEventEndCinematic
^is a not needed bj function.

Periodic triggers aren't really needed in JASS; timers should be used to call functions periodicly.
And a periodic function should not run without sense; so when no dummies exist, then it should not run for nothing.

There shouldn't be a delay at casting dummy, it brings not wanted result.

The local group creation isn't really needed, you may also check the other threads to compare feedback.
 
Status
Not open for further replies.
Top