• 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.

[vJASS] Problem with units in Group?

Status
Not open for further replies.
Level 2
Joined
Mar 14, 2011
Messages
9
[SOLVED] Problem with units in Group?

[SOLVED]

Hi everyone,

I'm very nooby at vJASS and this is my very first try of creating a spell with it.

Spell background:
Increase Agility of all Heroes by an amount of 10% of the intelligence of the caster.

This is my try:
I Added some Debug Texts to see at which position the script is, in game it shows me that, when i activate the spell:

In function Conditions
In function create
In function GroupFilter
TRUE
In function GroupFilter
TRUE
In function BonusAdd
In function BonusAdd
[12 sec]
In function BonusSub

Only the SpecialEffect In function create works, the rest does nothing.
I really think the problem is after the line
"call BJDebugMsg("In function BonusAdd")"
because i'm not really understanding the UnitGroups in JASS..
And why the fuck GroupFilter and BonusAdd are called 2 times? :(

Hope you can help! :D
Thanks

JASS:
scope RuneDerMentalenStaerke initializer init

globals
    private constant integer SpellID           = 'A003'
    private constant real    Duration          = 12.00

    private constant string  CasterEffect      = "Objects\\InventoryItems\\runicobject\\runicobject.mdl"
    private constant string  TargetEffect      = "Abilities\\Spells\\NightElf\\FaerieFire\\FaerieFireTarget.mdl"  
    private          effect array dmgEffects[5]
    private          effect  casterEffect

    private          unit array TempUnit[5]
    private          player  TempPlayer        = null
endglobals

private struct Spell
    real BonusAgi
    real TargetAgi
    timer Timer
    unit caster
    group targets
    static Spell tempthis
 
 
    static method BonusAdd takes nothing returns nothing
        local Spell tempthis
        local integer i = 1
        
        call BJDebugMsg("In function BonusAdd")
            
        set i = 0
        loop
            exitwhen i > 5
            set TempUnit[i] = GetEnumUnit()
            call ModifyHeroStat( bj_HEROSTAT_AGI, TempUnit[i] , bj_MODIFYMETHOD_ADD, R2I( tempthis.BonusAgi ) )
            //set dmgEffects[i] = AddSpecialEffectTargetUnitBJ("head",TempUnit[i],TargetEffect)
            set dmgEffects[i] = AddSpecialEffectTarget(TargetEffect,TempUnit[i],"head")
            set i = i + 1
        endloop
    endmethod
    
    static method BonusSub takes nothing returns nothing
        local Spell tempthis
        local integer i = 1
        
        call BJDebugMsg("In function BonusSub")
        
        set i = 1
        loop
            exitwhen i > 5
            call ModifyHeroStat( bj_HEROSTAT_AGI, TempUnit[i] , bj_MODIFYMETHOD_SUB, R2I( tempthis.BonusAgi ) )
            call DestroyEffect(dmgEffects[i])
            set i = i + 1
        endloop
    endmethod
    
    static method GroupFilter takes nothing returns boolean
        local unit u = GetFilterUnit()
        
        call BJDebugMsg("In function GroupFilter")
        
        if (u == UNIT_TYPE_HERO) then
            call BJDebugMsg("TRUE")
            return TRUE
        endif
        
        call BJDebugMsg("FALSE")
        return FALSE
    endmethod
    
    static method create takes unit u returns Spell
        local Spell this = Spell.allocate()
        local integer i = 1

        set .caster = u
        set .targets = CreateGroup()
        set .BonusAgi = GetHeroAgi( caster,TRUE ) * 0.10
        set .Timer = CreateTimer()

        call BJDebugMsg("In function create")

        call GroupEnumUnitsInRect(.targets, bj_mapInitialPlayableArea, Filter(function Spell.GroupFilter))
        
        //set casterEffect = AddSpecialEffectTargetUnitBJ("overhead", .caster ,CasterEffect)
        set casterEffect = AddSpecialEffectTarget(CasterEffect,.caster,"overhead")
        
        call ForGroup( .targets, function Spell.BonusAdd )
        
        call TimerStart( .Timer, Duration, false, function Spell.BonusSub )       
        
        return this
    endmethod
    
    method onDestroy takes nothing returns nothing
        call DestroyTimer( .Timer )
        call DestroyEffect( casterEffect )
    endmethod
endstruct

private function Conditions takes nothing returns boolean
    call BJDebugMsg("In function Conditions")
    
    if ( GetSpellAbilityId() == SpellID ) then
        call Spell.create(GetTriggerUnit())
    endif
    return false
endfunction

private function init takes nothing returns nothing
    local trigger t = null
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, Condition( function Conditions ) )
endfunction

endscope
 
Last edited:
Level 9
Joined
Apr 23, 2011
Messages
460
When doing GroupEnumUnits, change the last parameter to
JASS:
Filter(function YourFunction)
instead of Condition and use
JASS:
GetFilterUnit()
instead of
JASS:
GetEnumUnit()
.

Also in your init function you didn't null the local trigger and you don't need that expansive name, a simple "t" will suffice. There are also SEVERAL places in which you use the horrid red text (BJ functions). Please change them to be natives, it saves you some time and in the end, most BJ natives are time wasters as you'll just end up calling the function anyways. Some of them simplify several lines of code so using them makes more sense, but here
JASS:
GetPlayableMapRect()
can be replaced with...
JASS:
bj_mapInitialPlayableArea
. Just some suggestions.
 
Level 2
Joined
Mar 14, 2011
Messages
9
Hey thanks for your suggestions.

But the changes with Filter doesnt work, it doesnt go into the true case:

JASS:
call GroupEnumUnitsInRect(.targets, bj_mapInitialPlayableArea, Filter(function Spell.GroupFilter))
JASS:
    static method GroupFilter takes nothing returns boolean
        local unit u = GetFilterUnit()
        
        if (u == UNIT_TYPE_HERO) then
            return TRUE
        endif
        return FALSE
    endmethod

This is now my init, is it now just as you suggested?
JASS:
private function init takes nothing returns nothing
    local trigger t = null
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, Condition( function Conditions ) )
endfunction

I updated the JASS at the first post
 
And why the fuck GroupFilter and BonusAdd are called 2 times? :(

Because there are 2 units in range I presume including the actual caster.

Here's one solution to a problem:
In BonusAdd, you're looping from 0 to 5.
In BonusSub, you're looping from 1 to 5.

Solution to all problems:
In both of those functions, you're using an instance of the Spell struct that isn't set to anything.
How would the function know which instance you're talking about?
When you reference variables in Warcraft III that aren't set to anything, you would end up stopping the thread from running. (well, the trigger technically speaking.)

To fix this, you should set a global variable to "this" in your create function and use it in BonusAdd (meaning you need a global Spell variable that's set to this right before you call ForGroup. You wouldn't need to use tempthis in BonusAdd, you would need to use the global you set)

And for BonusSub, you would need to use a hashtable to store "this" using GetHandleId(.Timer) and 0 as the keys.

In BonusSub, you would set tempthis to the value you load from the hashtable using the handle id of the expiring timer and 0 as keys.

Also, don't forget to call tempthis.deallocate() at the end of the BonusSub function.
 
Level 2
Joined
Mar 14, 2011
Messages
9
Heho, thanks for the help!

As I'm a beginner in Jass I don't know how I can create a global variable of "Spell" right before ForGroup. Can you tell me how it works?

Okay, and the next thing is too complicated for me ~.~
And for BonusSub, you would need to use a hashtable to store "this" using GetHandleId(.Timer) and 0 as the keys.

In BonusSub, you would set tempthis to the value you load from the hashtable using the handle id of the expiring timer and 0 as keys.
Im Very desperated ..

And tempthis.deallocate() is a parse error!

In method BonusSub:
JASS:
local Spell tempthis = LoadTimerHandle(ht,0,0)
In function create:
JASS:
set ht = InitHashtable()
call SaveTimerHandle(ht, 0, 0, .Timer)
Globals:
JASS:
globals  
    private          hashtable ht
endglobals

EDIT:
Forget this shitty Jass, I now really learned how Jass works. It's very easy if you know how it works. For everyone who wants to know how I Created this Spell, here is the code:

Spell background:
Increase Agility of all Heroes (including Caster) by an amount of 10% of the intelligence of the caster.

JASS:
scope RuneDerMentalenStaerke initializer init

globals
    private unit casterunit
    private unit TempUnit
    private real DURATION = 12.00
    private boolean COOLDOWN_FLAG = FALSE
    private integer SPELL_ID = 'R003'
    private integer currentTech
    private integer bonusMK
    private timer duration = CreateTimer()
endglobals

private function Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityUnit() == udg_RM_0_Runenmeister ) ) then
        return false
    endif
    if ( not ( GetSpellAbilityId() == 'A003' ) ) then
        return false
    endif
    return true
endfunction

private function SubInt takes nothing returns nothing
    set TempUnit = GetEnumUnit()
    call SetHeroAgi(TempUnit, GetHeroAgi(TempUnit,FALSE) - bonusMK, TRUE)
endfunction

private function SubInt_Init takes nothing returns nothing
    call ForGroup( udg_HeroGroup, function SubInt)
endfunction

private function AddInt takes nothing returns nothing
    call TimerStart(duration,DURATION,FALSE,function SubInt_Init)
        
    set TempUnit = GetEnumUnit()
    call SetHeroAgi(TempUnit, GetHeroAgi(TempUnit,FALSE) + bonusMK, TRUE) 
endfunction

private function Actions takes nothing returns nothing
    set casterunit = GetSpellAbilityUnit()
    set bonusMK = R2I(GetHeroInt(casterunit,TRUE) * 0.1)
    
    call ForGroup( udg_HeroGroup, function AddInt)

endfunction

//===========================================================================
private function init takes nothing returns nothing
    set gg_trg_RM_Rune_der_mentalen_Staerke = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_RM_Rune_der_mentalen_Staerke, EVENT_PLAYER_UNIT_SPELL_CAST )
    call TriggerAddCondition( gg_trg_RM_Rune_der_mentalen_Staerke, Condition( function Conditions ) )
    call TriggerAddAction( gg_trg_RM_Rune_der_mentalen_Staerke, function Actions )
endfunction

endscope
 
Last edited:
Status
Not open for further replies.
Top