• 🏆 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] Unit refuses to be added to Group

Status
Not open for further replies.
Level 13
Joined
Jul 26, 2008
Messages
1,009
Alright, I have a spell that's pretty simple. The unit Wind Walks, and the units he passes through take damage (but only once per cast).

Problem is when they're added to the group, they don't get added. This causes the ForGroup to have nothing to remove from the group.

I've tried this with just a CreateGroup type of group. Same results.

I've tested to see if the group was over-written or wiped some how; it's not because if I set the bottom return to true it returns some units (No detectable pattern for which units).

The problem seems to be in this block:

JASS:
        if IsUnitEnemy(target, GetOwningPlayer(.caster)) and not(hit[GetUnitId(target)])and not(IsUnitType(target, UNIT_TYPE_DEAD) and IsUnitType(target, UNIT_TYPE_STRUCTURE))then
            call BJDebugMsg(GetUnitName(GetFilterUnit()))
            set d = xedamage.create()
            set d.dtype = DAMAGE_TYPE_NORMAL
            set d.atype = ATTACK_TYPE_PIERCE
            call d.useSpecialEffect(GetAbilityEffectById(SPELLID, EFFECT_TYPE_TARGET, 0), "origin")
            call d.damageTarget(.caster, target, 40+10*lvl)
            set hit[GetUnitId(target)] = true
            call d.destroy()
            return true
        endif

If someone knows a better way to do this let me know and I can just do that.

Full Code:
JASS:
struct RushOfTerror

    private static integer SPELLID  = 'RuoT'
    private static integer BUFFID   = 'BOwk'
    private static real tick = 0.05
    static boolean array hit
    static unit caster
    group grp
    real dur = 0

    private static method RemHit takes nothing returns nothing
        call BJDebugMsg(GetUnitName(GetEnumUnit()))
        set hit[GetUnitId(GetEnumUnit())] = false
    endmethod

    private static method GroupEm takes nothing returns boolean
     local unit target = GetFilterUnit()
     local integer lvl = GetUnitAbilityLevel(.caster, SPELLID)
     local xedamage d
        if IsUnitEnemy(target, GetOwningPlayer(.caster)) and not(hit[GetUnitId(target)])and not(IsUnitType(target, UNIT_TYPE_DEAD) and IsUnitType(target, UNIT_TYPE_STRUCTURE))then
            call BJDebugMsg(GetUnitName(GetFilterUnit()))
            set d = xedamage.create()
            set d.dtype = DAMAGE_TYPE_NORMAL
            set d.atype = ATTACK_TYPE_PIERCE
            call d.useSpecialEffect(GetAbilityEffectById(SPELLID, EFFECT_TYPE_TARGET, 0), "origin")
            call d.damageTarget(.caster, target, 40+10*lvl)
            set hit[GetUnitId(target)] = true
            call d.destroy()
            return true
        endif
     return false
    endmethod

    private static method Timer takes nothing returns nothing
     local thistype this = GetTimerData(GetExpiredTimer())
        call GroupEnumUnitsInArea(.grp, GetUnitX(.caster), GetUnitY(.caster), 110, Filter(function thistype.GroupEm))
        if GetUnitAbilityLevel(.caster, BUFFID) == 0 then
            call ForGroup(.grp, function thistype.RemHit)
            call ReleaseGroup(.grp)
            call ReleaseTimer(GetExpiredTimer())
            call .destroy()
        endif
        set .dur = .dur + tick
    endmethod

    private static method create takes unit caster returns thistype
     local thistype this = thistype.allocate()
        set .caster = caster
        set .grp = NewGroup()
        call TimerStart(NewTimerEx(this), tick, true, function thistype.Timer)
     return this
    endmethod

    private static method Actions takes nothing returns nothing
        if GetSpellAbilityId() == SPELLID then
            call thistype.create(GetTriggerUnit())
        endif
    endmethod

//===========================================================================
    private static method onInit takes nothing returns nothing
        set gg_trg_RushOfTerror = CreateTrigger(  )
        call TriggerRegisterPlayerUnitEvent(gg_trg_RushOfTerror, GetLocalPlayer(), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        call TriggerAddAction( gg_trg_RushOfTerror, function thistype.Actions )
    endmethod

endstruct
 
You have no instance of "this" in the enum callback. To pass it between the functions, just have a global variable of the struct and set it to the instance, then do the enum. Then use the global as the instance:
JASS:
globals
    MyStruct A 
endglobals

function ex takes nothing returns nothing
    local thistype this = A
    set .caster // blah blha
endfunction

function enum takes nothing returns nothing
    local thistype this = thistype.allocate()
    set A = this
    // enum
endfunction
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
Is there a reason this:

globals
MyStruct A
endglobals

Would give this error:

Undefined type Mystruct

EDIT: Tried it by setting my struct to a Table using Vexorian's Table and this same method, but it still didn't work at all like intended. The units weren't added to the group or at least were immediately flushed.
 
Well in your case it would be "RushOfTerror A" instead of "MyStruct A". Structs can act as the "type" portion when making globals. Or you can use thistype if you are declaring it within the struct:
JASS:
struct RushOfTerror
    static thistype temp = 0

    private static integer SPELLID  = 'RuoT'
    private static integer BUFFID   = 'BOwk'
    private static real tick = 0.05
    static boolean array hit
    static unit caster
    group grp
    real dur = 0

    private static method RemHit takes nothing returns nothing
        call BJDebugMsg(GetUnitName(GetEnumUnit()))
        set hit[GetUnitId(GetEnumUnit())] = false
    endmethod

    private static method GroupEm takes nothing returns boolean
     local thistype this = temp
     local unit target = GetFilterUnit()
     local integer lvl = GetUnitAbilityLevel(.caster, SPELLID)
     local xedamage d
        if IsUnitEnemy(target, GetOwningPlayer(.caster)) and not(hit[GetUnitId(target)])and not(IsUnitType(target, UNIT_TYPE_DEAD) and IsUnitType(target, UNIT_TYPE_STRUCTURE))then
            call BJDebugMsg(GetUnitName(GetFilterUnit()))
            set d = xedamage.create()
            set d.dtype = DAMAGE_TYPE_NORMAL
            set d.atype = ATTACK_TYPE_PIERCE
            call d.useSpecialEffect(GetAbilityEffectById(SPELLID, EFFECT_TYPE_TARGET, 0), "origin")
            call d.damageTarget(.caster, target, 40+10*lvl)
            set hit[GetUnitId(target)] = true
            call d.destroy()
            return true
        endif
     return false
    endmethod

    private static method Timer takes nothing returns nothing
     local thistype this = GetTimerData(GetExpiredTimer())
        set temp = this
        call GroupEnumUnitsInArea(.grp, GetUnitX(.caster), GetUnitY(.caster), 110, Filter(function thistype.GroupEm))
        if GetUnitAbilityLevel(.caster, BUFFID) == 0 then
            call ForGroup(.grp, function thistype.RemHit)
            call ReleaseGroup(.grp)
            call ReleaseTimer(GetExpiredTimer())
            call .destroy()
        endif
        set .dur = .dur + tick
    endmethod

    private static method create takes unit caster returns thistype
     local thistype this = thistype.allocate()
        set .caster = caster
        set .grp = NewGroup()
        call TimerStart(NewTimerEx(this), tick, true, function thistype.Timer)
     return this
    endmethod

    private static method Actions takes nothing returns nothing
        if GetSpellAbilityId() == SPELLID then
            call thistype.create(GetTriggerUnit())
        endif
    endmethod

//===========================================================================
    private static method onInit takes nothing returns nothing
        set gg_trg_RushOfTerror = CreateTrigger(  )
        call TriggerRegisterPlayerUnitEvent(gg_trg_RushOfTerror, GetLocalPlayer(), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        call TriggerAddAction( gg_trg_RushOfTerror, function thistype.Actions )
    endmethod

endstruct
 
Last edited:
Whoops I put the variable in the wrong area. Fixed.

Anyway, I assume that the bj debug messages are showing up, correct? The reason why it is flushing is because each GroupEnum call will clear the group. It doesn't preserve members. If you want to keep the members, you have to have a separate group. Have one global group that is just used for enumeration and then one that is a struct member (.grp). When you enumerate (using the global group as the enumerating group) and the if/then/else is passed, add the units to .grp. (call GroupAddUnit(GetFilterUnit(), .grp))
 
Status
Not open for further replies.
Top