• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Can't add ability to a group of units

Status
Not open for further replies.
Level 3
Joined
Aug 25, 2013
Messages
22
Hello Hive

I've trying to get a spell done in JASS.
Basically it is a target AoE spell. All friendly units in the AoE temporarily receive a spell (actually a self-only aura) that lasts until they lose the spell debuff
After a long time correcting syntax so the editor would allow me to 'turn on' the thing, now I find out that it does not work at all (The target units receive no new ability)

Here's the trigger, keep in mind that I'm yet a newbie in the ways of JASS so this may hurt the eyes of seasoned JASSers.

JASS:
function InnerV_Conditions takes nothing returns boolean
return GetSpellAbilityId()=='A00E' //AoE SPELL THAT WILL ACT AS THE 'TEMPORARY BUFF'
endfunction

function InnerV_Allies takes nothing returns boolean //SUPPOSEDLY THIS FILTERS OUT ENEMY UNITS
if(IsUnitEnemy(GetEnumUnit(),GetOwningPlayer(GetSpellAbilityUnit()))) then
return false
endif
return true
endfunction

function InnerV_Buff takes nothing returns nothing
call UnitAddAbility(GetEnumUnit(),'A000') //ABILITY GRANTED TO THE TARGET UNITS
loop
call TriggerSleepAction(.5)
exitwhen(GetUnitAbilityLevel(GetEnumUnit(),'B017')<1) //BUFF PLACED BY THE 'A00E' SPELL
endloop
call UnitRemoveAbility(GetEnumUnit(),'A000')
endfunction

function InnerV_Actions takes nothing returns nothing//THIS FUNCTION (SUPPOSEDLY) DEFINES THE UNIT GROUP
local location targetarea = GetSpellTargetLoc()
local group targets = CreateGroup()
call GroupEnumUnitsInRangeOfLoc(targets,targetarea,325,Filter(function InnerV_Allies))
call ForGroup(targets,function InnerV_Buff)
endfunction

//===========================================================================
function InitTrig_Inner_Vitality_Aura takes nothing returns nothing
local trigger Inner_Vitality_Aura = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(Inner_Vitality_Aura,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(Inner_Vitality_Aura,Condition(function InnerV_Conditions))
call TriggerAddAction(Inner_Vitality_Aura,function InnerV_Actions)
set Inner_Vitality_Aura = null
endfunction


I know that I've not cleared, destroyed and nulled the 'group' local variable, but will the trigger work if I do? I mean, if the group is destroyed before the units lose the buff, wouldn't they remain with the spell given permanently?
 
You shouldn't use TriggerAddAction do everything in the TriggerAddCondition. If you don't understand then look at my tutorial converting GUI to efficient JASS.

Don't use triggerSleepAction. Create spells using some form of indexing like indexed arrays.

Your spell won't be removed because of the TSA. It is not MUI the way you have it.

None of those answered his question.. I'm also pretty sure it's MUI as is.

Anyway, here's a better version of your code with some debug messages. Try it out, and let me know what messages display.

JASS:
function InnerV_Actions takes nothing returns boolean
    local real x
    local real y
    local group g
    local unit u
    local player p
    
    call BJDebugMsg("INIT")
    
    if (GetSpellAbilityId()=='A00E') then
        call BJDebugMsg("SPELL STARTED")
        
        set x = GetSpellTargetX()
        set y = GetSpellTargetY()
        set g = CreateGroup()
        set p = GetOwningPlayer(GetSpellAbilityUnit())
        call GroupEnumUnitsInRange(g, x, y, 325, null)
        
        call BJDebugMsg("LOOPING THROUGH GROUP")
        
        set u = FirstOfGroup(g)
        loop
            exitwhen u==null
            if (IsUnitEnemy(u, p)) then
                call UnitAddAbility(u, 'A000') //ABILITY GRANTED TO THE TARGET UNITS
                call BJDebugMsg("ADD BUFF TO " + GetUnitName(u))
                loop
                    call TriggerSleepAction(.5)
                    exitwhen(GetUnitAbilityLevel(u, 'B017')<1) //BUFF PLACED BY THE 'A00E' SPELL
                endloop
                call UnitRemoveAbility(u, 'A000')
            endif
        endloop
        
        call DestroyGroup(g)
        set g = null
    endif
    
    return false
endfunction

//===========================================================================
function InitTrig_Inner_Vitality_Aura takes nothing returns nothing
    local trigger Inner_Vitality_Aura = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(Inner_Vitality_Aura,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(Inner_Vitality_Aura, Condition(function InnerV_Actions))
endfunction
 
Level 3
Joined
Aug 25, 2013
Messages
22
@TriggerHappy
Now it adds the ability, I had to correct a line because it was checking if the unit was an enemy of the caster (The spell is intended to affect friendly units, not enemy units). And while it added the ability, it only did so to 1 of all the units in the target area

Also it didn't remove the ability from the unit once it lost the buff

@deathismyfriend
So I gather that the GetEnumUnit function is what makes it not MUI. What should I use instead?


And while the TSA is what causes the spell to not be removed, my trigger as it is does not even add the spell
what is the precise error that causes this to happen (the spell not even being added)? Basically what I aimed for was to pick every unit in the group and add an ability but obviously I made a mistake somewhere
 
TH's code will likely sorta work if you change it to actions instead of conditions, e.g.:
JASS:
function InnerV_Actions takes nothing returns nothing
    local real x
    local real y
    local group g
    local unit u
    local player p
    
    call BJDebugMsg("INIT")
    
    if (GetSpellAbilityId()=='A00E') then
        call BJDebugMsg("SPELL STARTED")
        
        set x = GetSpellTargetX()
        set y = GetSpellTargetY()
        set g = CreateGroup()
        set p = GetOwningPlayer(GetSpellAbilityUnit())
        call GroupEnumUnitsInRange(g, x, y, 325, null)
        
        call BJDebugMsg("LOOPING THROUGH GROUP")
        
        set u = FirstOfGroup(g)
        loop
            exitwhen u==null
            if (IsUnitEnemy(u, p)) then
                call UnitAddAbility(u, 'A000') //ABILITY GRANTED TO THE TARGET UNITS
                call BJDebugMsg("ADD BUFF TO " + GetUnitName(u))
                loop
                    call TriggerSleepAction(.5)
                    exitwhen(GetUnitAbilityLevel(u, 'B017')<1) //BUFF PLACED BY THE 'A00E' SPELL
                endloop
                call UnitRemoveAbility(u, 'A000')
            endif
        endloop
        
        call DestroyGroup(g)
        set g = null
    endif
endfunction

//===========================================================================
function InitTrig_Inner_Vitality_Aura takes nothing returns nothing
    local trigger Inner_Vitality_Aura = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(Inner_Vitality_Aura,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction(Inner_Vitality_Aura, function InnerV_Actions)
endfunction


TriggerSleepAction() will end the thread in conditions.

However, the issue with it is that the loop will wait for the buff to fade off the first unit before iterating through to the next unit. If that is what you desire, then perfect, but I'm pretty sure you wanted the buffs to occur simultaneously.

-------

About your original code, one thing I noticed is that in the filter you pass GetEnumUnit() instead of GetFilterUnit().

GetFilterUnit() responds to the filter from GroupEnum...() functions. GetEnumUnit() responds to ForGroup(). But in general, your code might hit problems in the ForGroup(). I don't exactly remember how TSA behaves within a ForGroup(), but I believe it just halts the thread as well.

In general, this is a perfect example of a spell that could be improved with timers. Do you use vJASS or regular JASS (basically, do you use JNGP or the regular editor)? It is a bit more cumbersome to code in plain JASS, so I'll wait for your response before showing an example of how to code the spell properly. I can code it in simple JASS as well, but it is easier to code with a globals block.

edit: 2 posts happened while I was writing this. I'm slow. :p

@SecondHand: He converted the original trigger from GUI but optimized it by removing some BJ's (so it isn't purely GUI-converted JASS). It is natural to do that when you are starting out with JASS.

EDIT: Here is some sample code. It requires vJASS because of the globals block, but it can easily be translated to standard JASS by replacing the globals with your own globals. Basically, by using a hashtable, you can store things as time passes by. You just "attach" them to the timer by storing the data under the handle ID (in this case, I store the group), and then you retrieve it each time the timer ticks. View the code below. It is untested and uncompiled, so you may have to make tweaks here and there if there are issues:
JASS:
globals
	hashtable InnerV_Hash = InitHashtable()
	// This hashtable will store the group of allies as the timer loops

	group InnerV_tempGroup = null
	// temporary variable to pass the group across a function

	integer InnerV_tempInteger = 0
	// used to check if the group is empty
endglobals

function InnerV_Allies takes nothing returns boolean
    return not IsUnitEnemy(GetFilterUnit(), GetTriggerPlayer())
    // check if the filter unit is NOT an enemy of the owner of the casting unit
endfunction

function InnerV_Conditions takes nothing returns boolean
	return GetSpellAbilityId() == 'A00E'
endfunction

function InnerV_Buff takes nothing returns nothing 
	local unit enum = GetEnumUnit()

	// check if the buff is gone
	// or if the unit is dead/removed
	if (GetUnitAbilityLevel(enum, 'B017') < 1) or (GetWidgetLife(enum) < 0.405) or (GetUnitTypeId(enum) == 0) then
		call GroupRemoveUnit(InnerV_tempGroup, enum)
		call UnitRemoveAbility(enum, 'A000')
	endif

	// count the number of units in the group
	set InnerV_tempInteger = InnerV_tempInteger + 1
	set enum = null
endfunction

function InnerV_Check takes nothing returns nothing 
	local timer timerLoop = GetExpiredTimer() // timer that has just ran
	local group targets = LoadGroupHandle(InnerV_Hash, GetHandleId(timerLoop), 0)
	// group of units that were stored

	// set temporary variables 
	set InnerV_tempGroup = targets
	set InnerV_tempInteger = 0
	// go through group units in other function
	call ForGroup(targets, function InnerV_Buff)

	// if the number of units in the group is 0 then end timer
	if (InnerV_TempInteger == 0) then
		call FlushChildHashtable(InnerV_Hash, GetHandleId(timerLoop))
		call PauseTimer(timerLoop)
		call DestroyTimer(timerLoop)
		call DestroyGroup(targets)
	endif

	set timerLoop = null
	set targets = null
endfunction

function InnerV_Actions takes nothing returns nothing 
	local real targetX = GetSpellTargetX() // target x-coordinate of spell
	local real targetY = GetSpellTargetY() // target y-coordinate of spell

	local group targets = CreateGroup() // group to store allies
	local timer timerLoop = CreateTimer() // timer to periodically run

	// Enumerate allies/neutral within 325 of the target point
	call GroupEnumUnitsInRange(targets, targetX, targetY, 325, Filter(function InnerV_Allies))
	
	// Store the group that contains the units that were grouped under the timer
	call SaveGroupHandle(InnerV_Hash, GetHandleId(timerLoop), 0, targets)

	// Start the timer to check if the grouped units have the buff
	call TimerStart(timerLoop, 0.5, true, function InnerV_Check)

	set targets = null
	set timerLoop = null
endfunction

function InitTrig_Inner_Vitality_Aura takes nothing returns nothing 
	local trigger Inner_Vitality_Aura = CreateTrigger()
	call TriggerRegisterAnyUnitEventBJ(Inner_Vitality_Aura,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(Inner_Vitality_Aura,Condition(function InnerV_Conditions))
    call TriggerAddAction(Inner_Vitality_Aura,function InnerV_Actions)
    set Inner_Vitality_Aura = null
endfunction
 
Last edited:
Level 3
Joined
Aug 25, 2013
Messages
22
@PurgeandFire

Isn't that trigger missing the function to add the spell to the units in the AoE? where should I put it?
 
Status
Not open for further replies.
Top