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

[JASS] Is This Mui? Spell Help!

Status
Not open for further replies.
Level 10
Joined
May 27, 2009
Messages
494
I recently made a spell and i like to ask if its mui

if not.. pls make it mui :cry:
its in jass.. and its my first spell made in jass so i would like to have some help

JASS:
scope ParsleyEntanglement initializer Init 
    globals
        private constant integer SPELL_ID = 'A00M' 
        private constant integer DAbility_ID = 'A00N'  
        private constant integer DUMMY_ID = 'h003'  
        private constant real PERange = 400. 
        private constant real PEDelay = 2. 
        private constant integer PEInstances = 2 
        private constant attacktype PE_ATTACKTYPE = ATTACK_TYPE_MAGIC 
        private constant damagetype PE_DAMAGETYPE = DAMAGE_TYPE_NORMAL 
    endglobals
    
    private function PETargets takes unit target,unit c returns boolean
        return (GetWidgetLife(target) > 0.405) and (IsUnitType(target, UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) == false) and (IsUnitType(target, UNIT_TYPE_MECHANICAL) == false) and (IsUnitEnemy(target,GetOwningPlayer(c)))
    endfunction 
    
    private function PEDamageReal takes integer i returns real 
        local real array r
        set r[1] = 100.
        set r[2] = 150.
        set r[3] = 200.
        return r[i]
    endfunction
    

    globals
        group petarg
        boolexpr b
        unit caster
        integer peindex = 0
        integer pelvl
        timer pet
        real pedmg
    endglobals
    
    private function PECond takes nothing returns boolean
        return GetSpellAbilityId() == SPELL_ID
    endfunction
    
    private function PEPick takes nothing returns boolean
        return PETargets(GetFilterUnit(),GetTriggerUnit())
    endfunction
    
    private function PEDamage takes nothing returns nothing
        call UnitDamageTarget(caster,GetEnumUnit(),pedmg,true,false,PE_ATTACKTYPE,PE_DAMAGETYPE,WEAPON_TYPE_CLAW_HEAVY_SLICE)
    endfunction 
    
    private function PETimeLoop takes nothing returns nothing
        if peindex < PEInstances then
            set peindex = peindex + 1
            call ForGroup(petarg,function PEDamage)
        else
            call ReleaseTimer(pet)
        endif
    endfunction
    
    private function PEActions takes nothing returns nothing
        local location spellLoc = GetSpellTargetLoc()
        local real spellx = GetLocationX(spellLoc)
        local real spelly = GetLocationY(spellLoc)
        local unit pedummy
        set caster = GetTriggerUnit()
        set pelvl = GetUnitAbilityLevel(caster,SPELL_ID)
        set pedmg = PEDamageReal(pelvl)
        call GroupEnumUnitsInRange(petarg,spellx,spelly,PERange,b)
        call CreateUnitAtLoc(GetOwningPlayer(caster),DUMMY_ID,spellLoc,0) 
        call UnitAddAbility(GetLastCreatedUnit(),DAbility_ID) 
        call SetUnitAbilityLevel(GetLastCreatedUnit(),DAbility_ID,pelvl) 
        call IssueImmediateOrder(GetLastCreatedUnit(),"stomp") 
        set pedummy = GetLastCreatedUnit() 
        set udg_PE_Level = GetUnitAbilityLevel(caster,SPELL_ID)
        set udg_PE_Owner = GetOwningPlayer(caster)
        set udg_PE_location = spellLoc
        call TriggerExecute(gg_trg_Parsley_Entanglement_Dummy)
        set pet = NewTimer()
        call SetTimerData(pet,GetUnitTypeId(caster))
        call TimerStart(pet,PEDelay,true,function PETimeLoop)
    endfunction
    
    
//========================================================
    private function Init takes nothing returns nothing
        local trigger PEtrg = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(PEtrg, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(PEtrg,Condition(function PECond))
        call TriggerAddAction(PEtrg,function PEActions)
        set b = Condition(function PEPick)
        //====
        set petarg = CreateGroup()
        //Preload
        set bj_lastCreatedUnit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_ID, 0, 0, 0)
        call UnitAddAbility(bj_lastCreatedUnit,SPELL_ID)
        call KillUnit(bj_lastCreatedUnit)
    endfunction
    
endscope

don't mind the variables, they are for debugging purposes only :grin:
variables with udg_ prefix
EDIT:
my spell uses timerutils

and if see any similarity around the threads here in hive, i just follow the tutorial that flame_phoenix made about making jass spell :)
 
Level 8
Joined
Jul 28, 2008
Messages
211
Didn't check is it mui, but I saw a few things.
Why do you use a global caster variable?
And also
JASS:
private function PEDamageReal takes integer i returns real 
        local real array r
        set r[1] = 100.
        set r[2] = 150.
        set r[3] = 200.
        return r[i]
    endfunction
should be
JASS:
function PEDamageReal takes integer lvl returns real
    return lvl * 50 + 100.
endfunction
because the user might want it to have more levels than 3.

EDIT: You could check if its MUI by making a map and adding more units with the ability and casting it at the same time with more of them. If it works like it should, it's MUI but if it doesn't it isn't.

EDIT 2: Don't use LastCreatedUnit(). Instead of
JASS:
local unit dummy
call CreateUnit(......)
set dummy = GetLastCreatedUnit()
you can simply use
JASS:
local unit dummy = CreateUnit(.....)
 
Level 8
Joined
Jul 28, 2008
Messages
211
No worries, you'll get better ^^ just don't give up.
The way I see it, you don't need the SetTimerData(). You never use the stored data, you used the global caster variable instead.

EDIT: And you forgot to null pedummy
JASS:
set pedummy = null
at the end of your actions.
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
  • Avoid using locations. Use GetSpellTagetX and GetSpellTargetY instead of GetSpellTargetLoc. That way, you don't need to worry about leaking.
  • You're using TimerUtils incorrectly. Because of this, the spell is not MUI. Though this is a bit old, this tutorial is helpful.
  • What is call TriggerExecute(gg_trg_Parsley_Entanglement_Dummy)?
  • You could do group petarg = CreateGroup() instead of doing it in the Init function like the tutorial said to do.
  • For preloading, it might be better to use RemoveUnit instead of KillUnit.
  • Using GetWidgetLife(target) > 0.405 is not the best way to determine if a unit is alive. Check this thread for more information.
Good luck with Jass!
 
Level 10
Joined
May 27, 2009
Messages
494
bump

+ update
(sry if double post)

here's the new code with the struct @_@

JASS:
scope ParsleyEntanglement initializer Init 
    globals
        private constant integer SPELL_ID = 'A00M' 
        private constant integer DAbility_ID = 'A00N'  
        private constant integer DUMMY_ID = 'h003'  
        private constant integer BUFF_ID = 'B003'
        private constant real PERange = 400. 
        private constant real PEDelay = 2.
        private constant real PELoop = 0.3
        private constant real PEDuration = 4.
        private constant integer PEInstances = 2 
        private constant attacktype PE_ATTACKTYPE = ATTACK_TYPE_MAGIC 
        private constant damagetype PE_DAMAGETYPE = DAMAGE_TYPE_NORMAL 
    endglobals
    
    private function PETargets takes unit target,unit c returns boolean
        return (GetWidgetLife(target) > 0.405) and (IsUnitType(target, UNIT_TYPE_STRUCTURE) == false) and (IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) == false) and (IsUnitType(target, UNIT_TYPE_MECHANICAL) == false) and (IsUnitEnemy(target,GetOwningPlayer(c)))
    endfunction 
    
    private function PEDamageReal takes integer i returns real 
        return i * 50. + 50.
    endfunction
    
    private function PEPick takes nothing returns boolean
        return PETargets(GetFilterUnit(),GetTriggerUnit())
    endfunction
    
    globals
        boolexpr peb
    endglobals
    // function by blade.dk
    private function CopyGroup takes group g returns group
        set bj_groupAddGroupDest = CreateGroup()
        call ForGroup(g, function GroupAddGroupEnum)
        return bj_groupAddGroupDest
    endfunction
    
private struct Data
    unit caster
    group petargets = CreateGroup()
    real pecounter = 0
    boolean pebOn = false
    
    static method create takes unit c, group g returns Data
        local Data D = Data.allocate()
        set D.caster = c
        set D.pecounter = 0.
        set D.petargets = g
        return D
    endmethod
    
    method onDestroy takes nothing returns nothing
        set .pebOn = false
    endmethod
        
endstruct
    
    private function PELoop2 takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local Data D = Data(GetTimerData(t))
        local real PEdam = PEDamageReal(GetUnitAbilityLevel(D.caster,SPELL_ID))
        local real PEDur = PEDuration
        local unit f
        local unit p
        local group pecopy = CreateGroup()
        local group pedmggrp = CreateGroup()
        set pecopy = CopyGroup(D.petargets)
        loop
            set f = FirstOfGroup(pecopy)
            exitwhen(f == null)
            if not D.pebOn and GetUnitAbilityLevel(f,BUFF_ID) > 0 then
                set D.pebOn = true
            endif
            call GroupRemoveUnit(pecopy,f)
        endloop
        set D.pecounter = D.pecounter + PELoop
        if D.pecounter + PELoop >= PEDelay then
            set pedmggrp = CopyGroup(D.petargets)
            set D.pecounter = 0
            loop
                set p = FirstOfGroup(pedmggrp)
                exitwhen(p == null)
                call UnitDamageTarget(D.caster,p,PEdam,true,false,PE_ATTACKTYPE,PE_DAMAGETYPE,WEAPON_TYPE_CLAW_HEAVY_SLICE) 
                call GroupRemoveUnit(pedmggrp,p)
            endloop
        endif
        if D.pecounter > PEDuration then
            call D.destroy()
            call ReleaseTimer(t)
        endif
        set f = null
    endfunction
    
    
    private function PEActions2 takes nothing returns nothing
        local Data D
        local group petarg
        local timer t = NewTimer()
        local unit pedummy = CreateUnitAtLoc(GetOwningPlayer(GetTriggerUnit()),DUMMY_ID,GetSpellTargetLoc(),0)
        call GroupEnumUnitsInRange(petarg,GetSpellTargetX(),GetSpellTargetY(),PERange,peb)
        set D = Data.create(GetTriggerUnit(),petarg)
        call SetTimerData(t,integer(D))
        call TimerStart(t,PELoop,true,function PELoop2) 
        call UnitAddAbility(pedummy,DAbility_ID)
        call SetUnitAbilityLevel(pedummy,DAbility_ID,GetUnitAbilityLevel(GetTriggerUnit(),SPELL_ID))
        call IssueImmediateOrder(pedummy,"stomp")
        call UnitApplyTimedLife(pedummy,'BTLF', 5.)
        set t = null
        set pedummy = null
    endfunction

    private function PECond2 takes nothing returns boolean
        return GetSpellAbilityId() == SPELL_ID
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger PEtrg = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(PEtrg, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(PEtrg,Condition(function PECond2))
        call TriggerAddAction(PEtrg,function PEActions2)
        set peb = Condition(function PEPick)
        //====
        //Preload
        set bj_lastCreatedUnit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_ID, 0, 0, 0)
        call UnitAddAbility(bj_lastCreatedUnit,SPELL_ID)
        call RemoveUnit(bj_lastCreatedUnit)
    endfunction
    
endscope

but my problems i get is:
My Dummy Doesn't cast the ability i gave
The trigger does not damage the targeted units..

pls help :cry:

EDIT:
i still do not change the UnitAlive native... but here's a draft pls check it :((
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Set petarg to CreateGroup() when you declare it, otherwise it won't work. (In PEActions2)

Code Optimization:

  • Don't use GetSpellTargetLoc. Use CreateUnit instead of CreateUnitAtLoc
  • You can use GetTriggerPlayer() instead of GetOwningPlayer(GetTriggerUnit()).
  • In
    JASS:
    call SetUnitAbilityLevel(pedummy,DAbility_ID,GetUnitAbilityLevel(GetTriggerUnit(),SPELL_ID))
    you can use D.caster instead of GetTriggerUnit().
  • The CopyGroup function has a group leak since it's always creating a new group each time it's called. It might be better to use it directly. Likewise, pecopy and pedmggrp leak since they're never destroyed. The best way to deal with them is to a)Use globals instead of locals b)Use GroupUtils to recycle groups c)Destroy them. (Don't forget to null group variables once you're done too)
 
Status
Not open for further replies.
Top