• 🏆 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] Using forgroup in a struct

Status
Not open for further replies.
Level 6
Joined
Jul 25, 2005
Messages
221
So, I've come across an interesting theory, and I was wondering if it can be executed.

What if you want to get a random unit in a group inside struct A, then place that random unit in a unit variable in struct A?

I tried this but, the Forgroup doesn't take the word method for function, so is there any approach for this?
Using function as method in a struct is not allowed! so don't try giving me an evasive answer :p

Maybe there's another way of getting a unit in a group?

Since it's hard explaining with words, let's just look at my code (doesn't compile because I use the word Method not Function)

JASS:
    struct dat
        integer speed = 40                                                                                                              
        unit target                                                                                                                 
     
        unit spawn
        
        unit caster
        
        group randomunit = CreateGroup()
        
        boolean go = false
        
        //! textmacro spawnmethod takes MOD
        method Spawn$MOD$ takes nothing returns real
            return GetModified$MOD$( GetUnitX(this.spawn), GetUnitY(this.spawn), GetUnitX(this.target), GetUnitY(this.target) )
        endmethod                                                                                                                   
        //! endtextmacro
        
        //! runtextmacro spawnmethod("Dist")
        //! runtextmacro spawnmethod("Angle")
        
        method SpawnMove takes nothing returns nothing
        local real x = GetUnitX(this.spawn)+this.speed*Cos(this.SpawnAngle()* bj_DEGTORAD)
        local real y = GetUnitY(this.spawn)+this.speed*Sin(this.SpawnAngle()* bj_DEGTORAD)
            call SetUnitX(this.spawn, x)
            call SetUnitY(this.spawn, y)
        endmethod
        //Getting random unit enum
        method newtarget takes nothing returns nothing
            set this.target = GetEnumUnit()
        endmethod
        //Get random unit
        method GetNewTarget takes nothing returns nothing
            //get some group within range or something and then get the random unit
            call GetRandomSubGroup( 1, this.randomunit)
            //and lets assing target = random unit
            call Forgroup(this.randomunit, method newtarget )
        endmethod 
    endstruct
Don't mind the textmacro, for some reason, the [ jass ] text acts oddly

EDIT: after some testing, and some native search, I found that FirstOfGroup(group) takes care of my problem, if I only need one target, but the question remains.
Is it possible to use a Forgroup in a struct?

EDIT: also, filters?

don't know how to add a filter either, here's the new code

JASS:
struct dat
        integer speed = 40                                                                                                              //
        unit target                                                                                                                 //
     
        unit spawn
        
        unit caster
        
        boolean go = false
        
        //! textmacro spawnmethod takes MOD
        method Spawn$MOD$ takes nothing returns real
            return GetModified$MOD$( GetUnitX(this.spawn), GetUnitY(this.spawn), GetUnitX(this.target), GetUnitY(this.target) )
        endmethod                                                                                                                   //
        //! endtextmacro
        
        //! runtextmacro spawnmethod("Dist")
        //! runtextmacro spawnmethod("Angle")
        
        method SpawnMove takes nothing returns nothing
        local real x = GetUnitX(this.spawn)+this.speed*Cos(this.SpawnAngle()* bj_DEGTORAD)
        local real y = GetUnitY(this.spawn)+this.speed*Sin(this.SpawnAngle()* bj_DEGTORAD)
            call SetUnitX(this.spawn, x)
            call SetUnitY(this.spawn, y)
        endmethod
        
        
        
        method GetNewTarget takes nothing returns unit
        local group tempg = CreateGroup()   
            call GroupEnumUnitsInRange(tempg, GetUnitX(this.spawn), GetUnitY(this.spawn), 1000, Condition(method?) )
            call GetRandomSubGroup( 1, tempg)
            return FirstOfGroup(tempg)
        endmethod 
    endstruct

EDIT: Wow, lots of edits... sorry about that, I tested to use a conditional function outside the struct, and obviously that worked, but since i need the unit member inside the struct... Can you attach handles to a condition?

Anyway, the forgroup issue stated earlier. The filter can be applied outside of the struct, but the forgroup callback uses a struct member, so is there a way?
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
JASS:
struct A
    private static boolexpr filterExpr
    private group g = CreateGroup()
    
    method foo takes nothing returns nothing
        call GroupEnumUnitsInRect(.g, bj_mapInitialPlayableArea, A.filterExpr)
        call ForGroup(.g, function A.callback)
    endmethod

    static method callback takes nothing returns nothing
    endmethod

    static method filter takes nothing returns boolean
    endmethod

    static method onInit takes nothing returns nothing
        set A.filterExpr = Condition(function A.filter)
    endmethod
endstruct

You can do something like that. Static methods in structs are the same as functions.
 
Level 6
Joined
Jul 25, 2005
Messages
221
Eleandor, yeah, I solved the firstofgroup thing, I did it sort of quick. I just create two groups where i store all of them, and then store the randomized unit in another group after that.

JASS:
        method GetNewTarget takes nothing returns unit
        local group tempg = CreateGroup() 
        local group randg = CreateGroup()
        local unit u  
            call GroupEnumUnitsInRange(tempg, GetUnitX(this.spawn), GetUnitY(this.spawn), 1000, Condition(function cond) )
            set randg = GetRandomSubGroup( 1, tempg)
            set u = FirstOfGroup(randg)
            return u
        endmethod

aznricepuff, I'll try it out! :)
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Arghhh, I had the same exact problem, but I forgot how I solved it, damn!

Btw, it's ForGroup, not Forgroup (notice the case).

Well, now we wait for someone to help. I'll see if PurplePoot knows.

EDIT: Ok, I was WAY late :D
 
Level 6
Joined
Jul 25, 2005
Messages
221
Silvenon, don't get technical, I know it's ForGroup() (luckily, JassCraft fills it in no matter how you use your cases)
Cursed be your memory!

aznricepuff, I tried your method, but as soon as i tried giving it an expression using a struct member it said it needed a static member. what's up wit' that?

JASS:
        static method filter takes nothing returns boolean
            return this.target != GetEnumUnit()
        endmethod
Error message: This is not of a type that allows . syntax

Hm, I'm guessing that when you make methods static, it won't recognize this. ?
changing this to struct name did however give a different filter error


JASS:
        static method filter takes nothing returns boolean
            return structname.target != GetEnumUnit()
        endmethod
Error message: Target is not a static member of structname
Don't think I want to make target static tho, that would screw up all the other statements

If structs keep doing this, I don't see how they're better than gamecache. All they've done for me so far is taking more time! -.-

Progress so far: the only thing I need explained is why last above code doesn't work, and how can I access the struct's members if they're not static?

Code:
JASS:
    struct scourge_dat
        integer speed = 10                                                                                                              //
        unit target                                                                                                                 //
     
        unit spawn
        
        unit caster
        
        boolean go = false
        
        static boolexpr filterExpr
        
        //! textmacro spawnmethod takes MOD
        method Spawn$MOD$ takes nothing returns real
            return GetModified$MOD$( GetUnitX(this.spawn), GetUnitY(this.spawn), GetUnitX(this.target), GetUnitY(this.target) )
        endmethod                                                                                                                   //
        //! endtextmacro
        
        //! runtextmacro spawnmethod("Dist")
        //! runtextmacro spawnmethod("Angle")
        
        method SpawnMove takes nothing returns nothing
        local real x = GetUnitX(this.spawn)+this.speed*Cos(this.SpawnAngle()* bj_DEGTORAD)
        local real y = GetUnitY(this.spawn)+this.speed*Sin(this.SpawnAngle()* bj_DEGTORAD)
            call SetUnitX(this.spawn, x)
            call SetUnitY(this.spawn, y)
        endmethod
        
        static method filterr takes nothing returns boolean
            return true
        endmethod
        
        static method onInit takes nothing returns nothing
            set scourge_dat.filterExpr = Condition(function scourge_dat.filterr)
        endmethod
        
        method GetNewTarget takes nothing returns unit
        local group tempg = CreateGroup() 
        local group randg = CreateGroup()
        local unit u  
            call GroupEnumUnitsInRange(tempg, GetUnitX(this.spawn), GetUnitY(this.spawn), 1000, this.filterExpr )
            set randg = GetRandomSubGroup( 1, tempg)
            set u = FirstOfGroup(randg)
            call DestroyGroup(tempg)
            call DestroyGroup(randg)
            return u
        endmethod 
    endstruct
EDIT: Read up on the manual, and tried to create a struct inside the expression, but alas, no success.
EDIT: come on, no one knows how to add a filter in a struct? help! it's the only thing i need to know

EDIT: Ok watch this, THIS IS WHAT I NEED HELP WITH, can anyone please for the love of god help me? -.-

JASS:
        static method filterr takes nothing returns boolean
            return scourge_dat.spawn != GetEnumUnit()
        endmethod
spawn is not a static member of scourge_dat (see above scripts for more information)

Why?
 
Last edited:
Level 11
Joined
Feb 22, 2006
Messages
752
Ok, you should really read up on some OOP (object oriented programming) concepts. Static methods cannot access instance variables because they are static, i.e. they are defined the exact same way for ALL instances of the struct type, so it makes no sense to give them access to instance variables that change depending on the specific struct instance. Static methods only have access to static variables because static variables are defined the same for all instances of a struct (think of them as globals...cuz they basically behave identically except they are tied to a struct type).

If you want to pass a struct instance variable (or a struct instance, which is probably easier to do) into a callback function or a filter function, u can save whatever you need to a global (or a static variable) and access it that way. So like:

JASS:
struct A
    private static A temp
    group g = CreateGroup()
    
    method foo takes nothing returns nothing
        set A.temp = this
        call ForGroup(.g, function A.callback)
    endmethod

    static method callback takes nothing returns nothing
        local A this = A.temp
        // now use the variable "this" to access the struct instance
    endmethod
endstruct
 
Level 6
Joined
Jul 25, 2005
Messages
221
I am a bit rusty with OOP only because there are so many options for OOP. Anyway, thanks for increasing my knowledge on the subject further :)

PS: It works!

JASS:
    struct scourge_dat
        static scourge_dat sd
        integer speed = 10                                                                                                              //
        unit target                                                                                                                 //
     
        unit spawn
        
        unit caster
        
        boolean go = false
        
        static boolexpr filterExpr
        
        //! textmacro spawnmethod takes MOD
        method Spawn$MOD$ takes nothing returns real
            return GetModified$MOD$( GetUnitX(this.spawn), GetUnitY(this.spawn), GetUnitX(this.target), GetUnitY(this.target) )
        endmethod                                                                                                                   //
        //! endtextmacro
        
        //! runtextmacro spawnmethod("Dist")
        //! runtextmacro spawnmethod("Angle")
        
        method SpawnMove takes nothing returns nothing
        local real x = GetUnitX(this.spawn)+this.speed*Cos(this.SpawnAngle()* bj_DEGTORAD)
        local real y = GetUnitY(this.spawn)+this.speed*Sin(this.SpawnAngle()* bj_DEGTORAD)
            call SetUnitX(this.spawn, x)
            call SetUnitY(this.spawn, y)
        endmethod
        
        static method filterr takes nothing returns boolean
            local scourge_dat this = scourge_dat.sd
            return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(this.caster) )
        endmethod
        
        static method onInit takes nothing returns nothing
            set scourge_dat.filterExpr = Condition(function scourge_dat.filterr)
        endmethod
        
        method GetNewTarget takes nothing returns unit
        local group tempg = CreateGroup() 
        local group randg = CreateGroup()
        local unit u 
            set scourge_dat.sd = this
            call GroupEnumUnitsInRange(tempg, GetUnitX(this.spawn), GetUnitY(this.spawn), 1000, this.filterExpr )
            set randg = GetRandomSubGroup( 1, tempg)
            set u = FirstOfGroup(randg)
            call DestroyGroup(tempg)
            call DestroyGroup(randg)
            return u
        endmethod 
    endstruct

Also, isn't that method pretty much the same way like returning 'this' in a function?
like in php when you create classes you can make a dynamic code by returning this for every method
because I tried doing that in this case, but your way was much better
 
Last edited:
Status
Not open for further replies.
Top