HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Get track of units

09-10-2008, 03:48 PM#1
Flame_Phoenix
Hi guys, I am going to make a mind mastery spell. This spell affects all enemy units inside a region and changes their owner for a period of time.
However I have a problem ....
Changing their owner is kinda easy ... problem is, how do I get him back ?
I saw people using "SetUserData" but that is definitely something I don't want to use.
I also though of adding the units to a group, but then I wouldn't be able to know their original owners ....
Finally I though, maybe I can place units and their player in two parallel arrays, but then I remembered I would never know the amount of units inside the AOE of the spell.

Can some one help me find a solution for this problem ?
09-10-2008, 04:53 PM#2
Anitarf
Have you considered using a different group for each original owner?
09-10-2008, 05:11 PM#3
Flame_Phoenix
So, there are 12 different players, I can use a group array and than I just move unit in/out of those groups. Sounds a better solution than using dinamic arrays !
Thx xD

PS:this will be my next submitted spell !
09-10-2008, 05:37 PM#4
Ammorth
Make sure you make the spell support multiple instances so that units are not given back tithe wrong player on multiple casts.
09-10-2008, 05:43 PM#5
moyack
Quote:
Originally Posted by Flame_Phoenix
So, there are 12 different players, I can use a group array and than I just move unit in/out of those groups. Sounds a better solution than using dinamic arrays !
Thx xD

PS:this will be my next submitted spell !
What kind of spell is this? aura based? or AOE casted in a place??
09-10-2008, 08:12 PM#6
Flame_Phoenix
Quote:
Make sure you make the spell support multiple instances so that units are not given back tithe wrong player on multiple casts.
Don't worry, my spells are always MUI !

Quote:
What kind of spell is this? aura based? or AOE casted in a place??
I give a brief description:
- Selects all enemy units in the target AOE and confuses them, by changing their owners for an amount of time.

This sounds simple doesn't it ?
Well, but it's not ! I am going to make of this a fun spell, so every player in game has a chance of controlling the unit !
like Player 1 has 10% chance, player 2 has 10% ... you get the point. Then when you cast the spell, total confusion is spread ! xD

However I am having trouble in changing the owners of the units when I cast the spell. When it ends is easy, problem is when I cast it ...

I am going to make another thread, asking for an opinion, because making vJASS spells is easy, but making them JESP ... is another story xD
09-10-2008, 11:15 PM#7
Anitarf
Quote:
Originally Posted by Flame_Phoenix
I am going to make another thread, asking for an opinion, because making vJASS spells is easy, but making them JESP ... is another story xD
What are you talking about? That's pretty much the same thing now.
09-10-2008, 11:20 PM#8
Flame_Phoenix
Doing something static and something versatile is never the same thing, and it will never be. Statics are always easier.
A JESP spell is not static, it can not be, because it must support change without allowing the user to enter the spell's core.
09-11-2008, 01:23 AM#9
Zerzax
If you use structural data for each unit (assign all this stuff in a create method) and associate said struct instance to the unit (I like PUI for it) your spell will be versatile and 8191 units can be affected at the same time. All the data you will need will be in that struct instance.
09-11-2008, 04:34 AM#10
Av3n
Wouldn't just be easier to assign a struct per unit (Like Zerzax)? Then reset the necessary variables it if the spell has already affected the unit?

So you would group the units in the AoE then loop through the units assign the struct if they don't have one and chuck them in a global group. If the units are in that global group when the spell is cast again array search up... then like I stated before change the necessary variables. And when the buff or whatever finishes just remove them from that global group

-Av3n
09-11-2008, 05:06 AM#11
Pyrogasm
Quote:
Originally Posted by Litany
This would be bad for MUI. A different group per player per cast would be necessary for groups. Issues with multiple players casting it on the same units at the same time would also crop up though, so you'd have to make sure the logic supported being at several removes from the original owner--and if there's anything in the map that can alter the "real" owner of a unit, you need to take that into account. (I suppose you could disallow it from affecting units that are already mind mastered to simplify some of this, but that would be pretty lame.)

Ultimately some combination of groups and Id attaching is probably going to be necessary.
Nope: if he had a group array, with indexes 0-11 corresponding to the player that the units originally belonged to (and, say, 12 holding all units currently affected by the spell), there's no conflict. Upon casting the spell, he would check to see if any of the affected units were already group 12, and if so he just wouldn't add them to any group (meaning: he wouldn't change the group they were in).

Then, at the end of any cast of the spell, the original owner is preserved.
09-11-2008, 09:17 AM#12
Anitarf
Well, the best way to implement it can in that case vary a lot depending on how exactly he wants the spell to work, so I guess he'd first have to explain that in more detail. Is it a one-time-cast buf spell, a cloud-type channeling spell or what?
09-11-2008, 10:04 AM#13
Flame_Phoenix
No channel spells, Moyack is angry at me because he says I only do channel spells (lol).
The spells has no conflicts in his logic afaik, I am using the fact that 2 things don't happen exactly at the same time (thread stuff).

Don't worry guys, I will very soon post the code here, once I finish the player thing, and you'll all be able to see it.
09-11-2008, 12:06 PM#14
Flame_Phoenix
Quote:
Say unitA has your ability at level 3, which steals control for 60 seconds. Now say unitB has it at level 1, which only steals control for 20 seconds. What happens when unitA steals control, then unitB immediately steals control again, then unitB's control expires after 20 seconds while unitA's is still active? Does control revert to unitA, or does it go back to the original owner? This is something to consider even if the ability isn't channeling.

In this case UnitA gets control of unit, and then UnitB (level 1) gets control right after right ?
Well, if, so, UnitB will control the first 20 seconds, then UnitA will control the 40 seconds after, and then the poor guy will return to his owner, if I am not mistaken.

Anyway, many people need to know what this spell is, so here it is.
The spell is AOE instant. The target units don't get any buff, although I could add one, the whole thing is triggered.

Here is the code I made so far.
If you have any CONSTRUCTIVE criticism or suggestion that you think can help me solve the players problem, or improve the code, go ahead.

Collapse JASS:
//===========================================================================
//A spell that selects all units inside the target AOE and confuses them, 
//changing their owner by an amount of time.
//
//Requires TimerUtils
//
//@author Flame_Phoenix 
//
//@credits
//- Rafael Br, the original creator of the spell and idea
//- Anitarf, the guy with ideas about how to solve problems
//- My first teacher of vJASS: Blue_Jeans
//- All other people I forgot or ignored
//
//@version 1.0
//===========================================================================
scope Confusion initializer Init

    //This will be needed for spell's core, don't change
    private keyword tmpPlayer
    private keyword PlayerArray
    private keyword playerLevelChances
    
//===========================================================================
//=============================SETUP START===================================
//===========================================================================
    globals 
        private constant integer AID = 'A003'   //the rawcode of the ability
        private constant integer ARRAY_SIZE = 15 //the maximum number of players
        private constant integer MAX_LEVELS = 3
    endglobals
    
    private constant function Duration takes integer level returns real
        return 20. + (level * 10)   //the duration of the spell on the units
    endfunction
    
    private constant function Radius takes integer level returns real
        return 125. + (level * 75)  //the radius the spell will have
    endfunction
    
    private function PlayersCallibration takes nothing returns nothing
        local integer i 
        local integer j
        
        //these are all human players the game has
        set i = 0
        loop
            exitwhen(i == 11) 
            set PlayerArray[i] = Player(i)
            set i = i + 1
        endloop
        
        //Neutral Computer controlled players
        set PlayerArray[12] = Player(PLAYER_NEUTRAL_AGGRESSIVE)
        set PlayerArray[13] = Player(PLAYER_NEUTRAL_PASSIVE)
        set PlayerArray[14] = Player(bj_PLAYER_NEUTRAL_VICTIM)
        
        //now we set the chances for all our human players for all levels
        //here, each human player has a 6.66% chance of controling the unit
        set i = 0
        loop
            exitwhen( i == 3)
            
            set j = 0
            loop
                exitwhen(j == 11)
                set playerLevelChances[i][j] = .666
                set j = j + 1
            endloop
            
            set i = i + 1
        endloop
        
        //if you prefer, you can avoid loops and set the levels and chances 
        //manually, like I do in this example
        set playerLevelChances[1][12] = .67
        set playerLevelChances[1][13] = .67
        set playerLevelChances[1][14] = .668
        
        set playerLevelChances[2][12] = .67
        set playerLevelChances[2][13] = .67
        set playerLevelChances[2][14] = .668
        
        set playerLevelChances[3][12] = .67
        set playerLevelChances[3][13] = .67
        set playerLevelChances[3][14] = .668
        
        //PS: Note that this takes a lot more text however xD
    endfunction
    
    private function Targets takes nothing returns boolean
    //the units that will be affected by the spell
        return IsUnitEnemy(GetFilterUnit(), tmpPlayer)
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================
    
    //small array
    type playerChances extends real array[ARRAY_SIZE]
    
    globals
        //BIG array
        private playerChances array playerLevelChances[MAX_LEVELS]
        
        private player array PlayerArray[15]
        private group g
        private boolexpr b
        private player tmpPlayer
    endglobals
//===========================================================================
    private struct MyStruct 
        unit caster
        integer level
        timer dur
        group array allPlayers[ARRAY_SIZE]
        
            static method create takes unit caster returns MyStruct
                local MyStruct data = MyStruct.allocate()
                local integer i
                
                //setting variables
                set data.caster = caster
                set data.level = GetUnitAbilityLevel(caster, AID)
                set data.dur = NewTimer()
                
                set i = 0
                loop
                    exitwhen (i == ARRAY_SIZE)
                    set data.allPlayers[i] = CreateGroup()
                    set i = i + 1
                endloop
                
                return data
            endmethod
            
            method onDestroy takes nothing returns nothing
                local integer i = 0
                loop
                    exitwhen (i == ARRAY_SIZE)
                    call DestroyGroup(.allPlayers[i])
                    set i = i + 1
                endloop
                
                call ReleaseTimer(.dur)
            endmethod
    endstruct
//===========================================================================
    private function EndEffect takes nothing returns nothing
        //here we catch the timer
        local MyStruct data = MyStruct(GetTimerData(GetExpiredTimer()))
        local unit f
        local integer i
        
        //here we walk trhough the group array
        set i = 0
        loop
            exitwhen(i == ARRAY_SIZE)
            
            //here we walk through every single unit inside the group
            loop
                set f = FirstOfGroup(data.allPlayers[i])
                exitwhen(f == null)
                call GroupRemoveUnit(data.allPlayers[i], f)
                call SetUnitOwner(f, Player(i), true)
            endloop
            
            set i = i + 1
        endloop
        
        call data.destroy()
    endfunction
//===========================================================================
    private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == AID
    endfunction
//===========================================================================
    private function Actions takes nothing returns nothing
        local MyStruct data = MyStruct.create(GetTriggerUnit())
        local location spellLoc = GetSpellTargetLoc()
        local real spellX = GetLocationX(spellLoc)
        local real spellY = GetLocationY(spellLoc)
        local unit f

        //here we select the units we will affect
        set tmpPlayer = GetOwningPlayer(data.caster)
        call GroupEnumUnitsInRange(g, spellX, spellY, Radius(data.level), b)
        
        //and now we change their owners
        loop
            set f = FirstOfGroup(g)
            exitwhen(f == null)
            call GroupRemoveUnit(g, f)
            call GroupAddUnit(data.allPlayers[GetPlayerId(GetOwningPlayer(f))], f)
            
            //Problem, how do I change the players here?
            //how do I make it random ?
            call SetUnitOwner(f, Player(3), true)
        endloop
        
        //start the timer
        call SetTimerData(data.dur, integer(data))
        call TimerStart(data.dur, Duration(data.level), true, function EndEffect)
        
        call RemoveLocation(spellLoc)
        set spellLoc = null
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        local integer i 
        local trigger ConfusionTrg = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(ConfusionTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(ConfusionTrg, Condition( function Conditions)) 
        call TriggerAddAction(ConfusionTrg, function Actions )
        
        set ConfusionTrg = null
        
        //setting globals
        set g = CreateGroup()
        set b = Condition(function Targets)
        
        //calling functions
        call PlayersCallibration()
        
        //setting out globals array
        set i = 0
        loop
            exitwhen(i == MAX_LEVELS)
            set playerLevelChances[i] = playerChances.create()
            set i = i + 1
        endloop
    endfunction
endscope

I wish there could be something like a "Players" pool, it would really make my life easier, but since I am using dynamic arrays, there may be a better way out, I hope.
09-11-2008, 08:38 PM#15
Flame_Phoenix
Quote:
You mean like a force?
Not like that. You see, the same way there are Unit and Items pools, I wish there could be also "Player Pools". It would make my job a lot easier.

EDIT EDIT EDIT

Ok guys, since no one answers, I decided to try fixing it myself. I managed to do some loop and if stuff, but is is bugged, it always goes for the last player.
Can some one please help me fix this ?
Oh, btw, can some mod also change the title to [OLY]Confusion ??

Collapse JASS:
//===========================================================================
//A spell that selects all units inside the target AOE and confuses them, 
//changing their owner by an amount of time.
//
//Requires TimerUtils
//
//@author Flame_Phoenix 
//
//@credits
//- Rafael Br, the original creator of the spell and idea
//- Anitarf, the guy with ideas about how to solve problems
//- My first teacher of vJASS: Blue_Jeans
//- All other people I forgot or ignored
//
//@version 1.0
//===========================================================================
scope Confusion initializer Init

    //This will be needed for spell's core, don't change
    private keyword tmpPlayer
    private keyword PlayerArray
    private keyword playerLevelChances
    
//===========================================================================
//=============================SETUP START===================================
//===========================================================================
    globals 
        private constant integer AID = 'A003'   //the rawcode of the ability
        private constant integer ARRAY_SIZE = 15 //the maximum number of players
        private constant integer MAX_LEVELS = 3
    endglobals
    
    private constant function Duration takes integer level returns real
        return 20. + (level * 10)   //the duration of the spell on the units
    endfunction
    
    private constant function Radius takes integer level returns real
        return 125. + (level * 75)  //the radius the spell will have
    endfunction
    
    private function PlayersCallibration takes nothing returns nothing
        local integer i 
        local integer j
        
        //these are all human players the game has
        set i = 0
        loop
            exitwhen(i == 11) 
            set PlayerArray[i] = Player(i)
            set i = i + 1
        endloop
        
        //Neutral Computer controlled players
        set PlayerArray[12] = Player(PLAYER_NEUTRAL_AGGRESSIVE)
        set PlayerArray[13] = Player(PLAYER_NEUTRAL_PASSIVE)
        set PlayerArray[14] = Player(bj_PLAYER_NEUTRAL_VICTIM)
        
        //now we set the chances for all our human players for all levels
        //here, each human player has a 6.66% chance of controling the unit
        set i = 0
        loop
            exitwhen( i == 3)
            
            set j = 0
            loop
                exitwhen(j == 11)
                set playerLevelChances[i][j] = .666
                set j = j + 1
            endloop
            
            set i = i + 1
        endloop
        
        //if you prefer, you can avoid loops and set the levels and chances 
        //manually, like I do in this example
        set playerLevelChances[1][12] = .67
        set playerLevelChances[1][13] = .67
        set playerLevelChances[1][14] = .668
        
        set playerLevelChances[2][12] = .67
        set playerLevelChances[2][13] = .67
        set playerLevelChances[2][14] = .668
        
        set playerLevelChances[3][12] = .67
        set playerLevelChances[3][13] = .67
        set playerLevelChances[3][14] = .668
        
        //PS: Note that this takes a lot more text however xD
    endfunction
    
    private function Targets takes nothing returns boolean
    //the units that will be affected by the spell
        return IsUnitEnemy(GetFilterUnit(), tmpPlayer)
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================
    
    //small array
    type playerChances extends real array[ARRAY_SIZE]
    
    globals
        //BIG array
        private playerChances array playerLevelChances[MAX_LEVELS]
        
        private player array PlayerArray[15]
        private group g
        private boolexpr b
        private player tmpPlayer
    endglobals
//===========================================================================
    private struct MyStruct 
        unit caster
        integer level
        timer dur
        group array allPlayers[ARRAY_SIZE]
        
            static method create takes unit caster returns MyStruct
                local MyStruct data = MyStruct.allocate()
                local integer i
                
                //setting variables
                set data.caster = caster
                set data.level = GetUnitAbilityLevel(caster, AID)
                set data.dur = NewTimer()
                
                set i = 0
                loop
                    exitwhen (i == ARRAY_SIZE)
                    set data.allPlayers[i] = CreateGroup()
                    set i = i + 1
                endloop
                
                return data
            endmethod
            
            method onDestroy takes nothing returns nothing
                local integer i = 0
                loop
                    exitwhen (i == ARRAY_SIZE)
                    call DestroyGroup(.allPlayers[i])
                    set i = i + 1
                endloop
                
                call ReleaseTimer(.dur)
            endmethod
    endstruct
//===========================================================================
    private function EndEffect takes nothing returns nothing
        //here we catch the timer
        local MyStruct data = MyStruct(GetTimerData(GetExpiredTimer()))
        local unit f
        local integer i
        
        //here we walk trhough the group array
        set i = 0
        loop
            exitwhen(i == ARRAY_SIZE)
            
            //here we walk through every single unit inside the group
            loop
                set f = FirstOfGroup(data.allPlayers[i])
                exitwhen(f == null)
                call GroupRemoveUnit(data.allPlayers[i], f)
                call SetUnitOwner(f, Player(i), true)
            endloop
            
            set i = i + 1
        endloop
        
        call data.destroy()
    endfunction
//===========================================================================
    private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == AID
    endfunction
//===========================================================================
    private function Actions takes nothing returns nothing
        local MyStruct data = MyStruct.create(GetTriggerUnit())
        local location spellLoc = GetSpellTargetLoc()
        local real spellX = GetLocationX(spellLoc)
        local real spellY = GetLocationY(spellLoc)
        local unit f
        local real chance
        local integer i
        //here we select the units we will affect
        set tmpPlayer = GetOwningPlayer(data.caster)
        call GroupEnumUnitsInRange(g, spellX, spellY, Radius(data.level), b)
        
        //and now we change their owners
        loop
            set f = FirstOfGroup(g)
            exitwhen(f == null)
            call GroupRemoveUnit(g, f)
            call GroupAddUnit(data.allPlayers[GetPlayerId(GetOwningPlayer(f))], f)
            
            set chance = GetRandomReal(0, 1)
            
            //if chance is lower than the first case, than we must treat it in special way
            if chance <= playerLevelChances[data.level][0] then
                call SetUnitOwner(f, Player(0), true)
                
            //this is for the middle cases
            elseif (chance > playerLevelChances[data.level][0]) and (chance <= playerLevelChances[data.level][ARRAY_SIZE - 1]) then
                set i = 1
                loop
                    exitwhen (i == ARRAY_SIZE - 1)
                    if (chance > playerLevelChances[data.level][i]) and (chance <= playerLevelChances[data.level][i + 1]) then
                        call SetUnitOwner(f, Player(i), true)
                    endif
                    set i = i + 1
                endloop
                
                //and now for the last case
            elseif (chance > playerLevelChances[data.level][ARRAY_SIZE - 1]) then
                call SetUnitOwner(f, Player(bj_PLAYER_NEUTRAL_VICTIM), true)
            endif
        endloop
        
        //start the timer
        call SetTimerData(data.dur, integer(data))
        call TimerStart(data.dur, Duration(data.level), true, function EndEffect)
        
        call RemoveLocation(spellLoc)
        set spellLoc = null
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        local integer i 
        local trigger ConfusionTrg = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(ConfusionTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(ConfusionTrg, Condition( function Conditions)) 
        call TriggerAddAction(ConfusionTrg, function Actions )
        
        set ConfusionTrg = null
        
        //setting globals
        set g = CreateGroup()
        set b = Condition(function Targets)
        
        //calling functions
        call PlayersCallibration()
        
        //setting out globals array
        set i = 0
        loop
            exitwhen(i == MAX_LEVELS)
            set playerLevelChances[i] = playerChances.create()
            set i = i + 1
        endloop
    endfunction
endscope