• 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] Manipulating Groups

Status
Not open for further replies.
Level 14
Joined
Jul 26, 2008
Messages
1,009
Alright I am wondering if there's an easier or faster way to manipulate groups than my current method.

Lets say I want to damage every unit in a group once. Well the only method I know is to pick every unit in that group and do damage to them, then when I'm done I remove that unit from the group and repeat until the group is empty.

Well lets say I want to hit every unit in that group for damage then ping their location on a minimap and share vision of them for 3 seconds. I obviously wouldn't want them to be removed from the group.

So is there a method of counting every unit in a group once without removing them?

Oh and if someone could tell me how to transfer Data in vJASS outside of timers that'd be great.
Like say I want to check the targeted unit of a spell in a boolean from a group, like so:

JASS:
private function IsHero takes nothing returns boolean
    return IsUnitType(?, UNIT_TYPE_HERO) == true
endfunction
 
Level 8
Joined
Feb 15, 2009
Messages
463
Use the xe system xedamage is great for that . You can damage groups or even cast spells on them with just a single line then.

to the thing below:

just use a filter in the enum then u already have the heros in the group. otherwise use globals .
 
Level 14
Joined
Jul 26, 2008
Messages
1,009
Filter in the Enum? o_O

I'm using GetFilterUnit(), but not GetEnumUnit()

You mean when I GroupEnum and then put in a Filter?

And vJASS is still very foreign to me. I've only learned how to replace hashtables with vJASS. xe is run all in vJASS and is a bit intimidating, but I would really like to learn to use it, so we'll see.

Anyways, under the current setup the hero is hitting themselves. Obviously my Filter isn't doing what it's suppose to. Any help?

JASS:
 //GroupEnum
    call GroupEnumUnitsInRange(g, D.x, D.y, 450, Filter(function GroupConditions))

//Filter
private function GroupConditions takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) == true and GetWidgetLife(GetFilterUnit()) >= 1
endfunction

JASS:
scope AssassinInTheNight initializer InitTrig_AssassinInTheNight

globals
    private constant integer    SpellID = 'aitn'
    private constant damagetype dmg     = DAMAGE_TYPE_POISON
    private constant weapontype wpn     = WEAPON_TYPE_WHOKNOWS
    private constant attacktype atk     = ATTACK_TYPE_MAGIC
endglobals

private struct Data
    unit c
    real x
    real y
    real a
    real d

    static method create takes unit caster, real casterx, real castery, real abilvl, real duration returns Data
     local Data D = Data.allocate()
        set D.c = caster
        set D.x = casterx
        set D.y = castery
        set D.a = abilvl
        set D.d = duration
     return D
    endmethod
     
     
endstruct

private function GroupConditions takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())) == true and GetWidgetLife(GetFilterUnit()) >= 1
endfunction

private function AITN_Timer takes nothing returns nothing
 local timer tim = GetExpiredTimer()
 local Data D = Data(GetTimerData(tim))
 local unit t
 local group g = CreateGroup()
 local integer i = 0
    call GroupEnumUnitsInRange(g, D.x, D.y, 450, Filter(function GroupConditions))
    set t = GroupPickRandomUnit(g)
    call SetUnitPosition(D.c, GetUnitX(t), GetUnitY(t))
    call SetUnitAnimation( D.c, "attack" )
    call UnitDamageTarget(D.c, t, 35. + 10 * (D.a - 1.), true, false, atk, dmg, wpn)
    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Weapons\\BansheeMissile\\BansheeMissile.mdl", t, "origin"))
    set i = 1
    if D.d >= 2.0 then
        call ReleaseTimer(tim)
        call D.destroy()
    else
        set D.d = D.d + 0.4
    endif
    call DestroyGroup(g)
 set t = null
 set g = null
endfunction

private function AITN_Actions takes nothing returns nothing
 local timer tim = NewTimer()
 local Data D = Data.create(GetTriggerUnit(), GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), GetUnitAbilityLevel(GetTriggerUnit(), 'aitn'), 0.)
    call SetTimerData(tim, D)
    call TimerStart(tim, 0.4, true, function AITN_Timer)
 set tim = null
endfunction

private function AITN_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == SpellID
endfunction

//===========================================================================
public function InitTrig_AssassinInTheNight takes nothing returns nothing
 local trigger AITN = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(AITN, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction( AITN, function AITN_Actions )
    call TriggerAddCondition(AITN, function AITN_Conditions)
endfunction

endscope
 
For most simple spells, there's no need for xe.
GetTriggerUnit() is "null" in the timer callback, that doesn't work.
Use a global unit-variable and set it to "D.c", use it in the filter afterwards.
JASS:
set myUnit = D.c
call GroupEnumUnitsInRange(g, D.x, D.y, 450, Filter(function GroupConditions))
Also, you're using TimerUtils, get GroupUtils too (it's the same
but for groups). Also, GroupUtils use a single group called
ENUM_GROUP that can be used for any instant enum like
JASS:
local group g = NewGroup()/CreateGroup()
call GroupEnumUnitsInRange(g....)
call ReleaseGroup()/DestroyGroup()

JASS:
call GroupEnumUnitsInRange(ENUM_GROUP....)

By the way, I hate Enums.
GroupEnumUnits... uses GetFilterUnit in the condition, because it's a filter.
ForGroup uses GetEnumUnit, names are confusing me until today :D

Just another fact:
Conditions are faster then actions (for sure, they're executed ebfore).
JASS:
private function AITN_Actions takes nothing returns nothing
 local timer tim = NewTimer()
 local Data D = Data.create(GetTriggerUnit(), GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), GetUnitAbilityLevel(GetTriggerUnit(), 'aitn'), 0.)
    call SetTimerData(tim, D)
    call TimerStart(tim, 0.4, true, function AITN_Timer)
 set tim = null
endfunction

private function AITN_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == SpellID
endfunction

//===========================================================================
public function InitTrig_AssassinInTheNight takes nothing returns nothing
 local trigger AITN = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(AITN, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction( AITN, function AITN_Actions )
    call TriggerAddCondition(AITN, function AITN_Conditions)
endfunction
could be
JASS:
private function AITN_Actions takes nothing returns nothing
 local timer tim = NewTimer()
 local Data D = Data.create(GetTriggerUnit(), GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), GetUnitAbilityLevel(GetTriggerUnit(), 'aitn'), 0.)
    call SetTimerData(tim, D)
    call TimerStart(tim, 0.4, true, function AITN_Timer)
 set tim = null
endfunction

private function AITN_Conditions takes nothing returns boolean
    if GetSpellAbilityId() == SpellID then
        call AITN_Actions ()
    endif
    return false
endfunction

//===========================================================================
public function InitTrig_AssassinInTheNight takes nothing returns nothing
 local trigger AITN = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(AITN, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(AITN, function AITN_Conditions)
endfunction
 
Status
Not open for further replies.
Top