HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Confusion Bug

09-15-2008, 07:11 PM#1
Flame_Phoenix
Hi guys, I have a problem with a spell I submitted, here -> confusion spell. Problem is that it bugs !
When you cast first time on the units, they change owner, get back, all works fine. If you cast 2nd time on 2nd units that were already victims ... it works correctly some times only, the victim actually looses the original player and never returns to him(only some times) ... weird question: If it malfunctions (it does) why doe the bug only happens some times, and not always ?
I have a replay from Bobo_the_Kodo so you all can understand the example. Please some one help me with this ?

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
//- Litany, the only guys that helped me unbugging this spell, when all others didn't care
//- My first teacher of vJASS: Blue_Jeans
//- All other people I forgot or ignored
//
//@version 1.4
//===========================================================================
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, Human player + computer players you use
        private constant integer MAX_LEVELS = 3 //the maximum amount of levels the ability will have
        private constant integer MAX_HUMAN_PLAYERS = 11 //the maximum number of human player you'll use
        private constant string EFFECT = "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl"
    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
        
        //here we set all human players with a nice loop
        set i = 0
        loop
            exitwhen(i == MAX_HUMAN_PLAYERS)
            set PlayerArray[i] = Player(i)
            set i = i + 1
        endloop
        
        //here we set computer controled creeps manually
        set PlayerArray[12] = Player(PLAYER_NEUTRAL_AGGRESSIVE)
        set PlayerArray[13] = Player(bj_PLAYER_NEUTRAL_VICTIM)
        set PlayerArray[14] = Player(PLAYER_NEUTRAL_PASSIVE)
        
        //here we set the chances all human players have of controlling the units
        //with a nice loop to fill our 2D array
        set i = 1
        loop
            exitwhen (i > MAX_LEVELS)
            set j = 0
            loop
                exitwhen(j == MAX_HUMAN_PLAYERS)
                set playerLevelChances[i][j] = .0666
                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
        //I this case, computer controled players have more chances of getting 
        //the units.
        set playerLevelChances[1][12] = .067
        set playerLevelChances[1][13] = .067
        set playerLevelChances[1][14] = .0668
        
        set playerLevelChances[2][12] = .067
        set playerLevelChances[2][13] = .067
        set playerLevelChances[2][14] = .0668
        
        set playerLevelChances[3][12] = .067
        set playerLevelChances[3][13] = .067
        set playerLevelChances[3][14] = .0668
        
        //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) and (GetWidgetLife(GetFilterUnit()) > 0.405) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false)
    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[ARRAY_SIZE]
        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
//===========================================================================
//RandomPlayer function made by Litany, adapted to spell by Flame_Phoenix
//===========================================================================
    private function RandomPlayer takes integer structure returns player
        local MyStruct data = structure
        local real chance = GetRandomReal(0, 1)
        local real playerChance = 0
        local integer i = 0
        
        loop
            exitwhen(i == ARRAY_SIZE )
            set playerChance = playerChance + playerLevelChances[data.level][i]
            if chance <= playerChance then 
                return Player(i)
            endif
            set i = i + 1
        endloop
        
        return Player(0)
    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 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)
            
            //with this line we keep track of the original owner
            call GroupAddUnit(data.allPlayers[GetPlayerId(GetOwningPlayer(f))], f)
            
            //here we change its player
            call SetUnitOwner(f, RandomPlayer(data), true)
            
            call DestroyEffect(AddSpecialEffect(EFFECT, GetUnitX(f), GetUnitY(f)))
        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)
        
        //We create our 2D array, so we can set if after
        set i = 0
        loop
            exitwhen(i == MAX_LEVELS)
            set playerLevelChances[i] = playerChances.create()
            set i = i + 1
        endloop
        
        //We set our 2D array xD
        call PlayersCallibration()
        
        //to prevent lag  the first time we use spell
        call Preload(EFFECT)
    endfunction
endscope

Here is map and replay, please help =S

EDIT EDIT EDIT
I found the problem, the member group array allPlayers[ARRAY_SIZE] is destroyed in the end of the spell. If two spells, with different levels, are cast the following scenario can happen:
1 - 1st cast on unit spell level 1 lasts for 10 seconds
2 - 2nd cast on unit spell level 3 lasts for 30 seconds
3 - level 1 duration ends, array destroyed, we lose original player for ever ...

To solve this bug I would need a global array, but then, I wouldn't be able to loop through the units like I do here:
Collapse JASS:
//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
because by removing the units, I would be removing the MUIness of the spell. I would also be removing units from the array, from other spells ...
I need a solution for this array problem, can some one aid me ?
Attached Files
File type: w3gREPLAY.w3g (11.5 KB)
File type: w3xConfusion 1.4.w3x (48.4 KB)
09-16-2008, 11:25 AM#2
Anitarf
First of all, I'd give every spell instance (the thing you call MyStruct) another group, a master group, that holds all affected units. Then, I'd sort the units in the groups not based on their previous owner, but on their new owner. Then, I'd create one struct at init that would be permanent and would be used to store the original owner of each affected unit. Then, I'd keep a sorted list of all instances based on when they were created, something like this:

Collapse JASS:
globals
    private MyStruct array instances
    private integer instanceCount=0
endglobals

private struct MyStruct
    static method create takes unit caster returns MyStruct
        ...
        set instances[instanceCount]=data
        set instanceCount=instanceCount+1
        ...
    endmethod
    method onDestroy takes nothing returns nothing
        ...
        local integer i=0
        local boolean b=false
        set instanceCount=instanceCount-1
        loop
            exitwhen i>=instanceCount
            if instances[i]==this then
                set b = true
            endif
            if b then
                set instances[i]=instances[i+1]
            endif
            set i=i+1
        endloop
        ...
    endmethod
endstruct

With a sorted list like that we can, whenever a spell instance ends, loop backwards through the list to find the newest instance that affects this unit (we check if the unit is in it's master group) and set the unit's owner to whatever player that instance changes it to; if however, there are no more instances affecting this unit, we go back to the original-owner-struct (we could just make that one be the first in the list) and set the unit's owner to the player set there (of course, we had to first store the unit there the first time a spell affected it).


A side note: don't create&destroy groups, reuse them:
Collapse JASS:
        static method create takes player caster returns MyStruct
            ...
            if data.allPlayers[i]==null then //only create new groups if this index hasn't been used before
                loop
                    exitwhen (i == ARRAY_SIZE)
                    set data.allPlayers[i] = CreateGroup()
                    set i = i + 1
                endloop
            endif
            ...
        endmethod
        method onDestroy takes nothing returns nothing
            ...
            loop
                exitwhen (i == ARRAY_SIZE)
                call GroupClear(.allPlayers[i]) //save the groups for the next time this index is used
                set i = i + 1
            endloop
            ...
        endmethod
09-16-2008, 06:22 PM#3
Flame_Phoenix
OMG, this is total chinese, I never saw anything like this before !
I will read this better and try to understand it !
Soon new posts !

EDIT EDIT EDIT

Quote:
First of all, I'd give every spell instance (the thing you call MyStruct) another group, a master group, that holds all affected units.
I assume you refer to all affected units of this instance of the spell right ?

Quote:
Then, I'd create one struct at init that would be permanent and would be used to store the original owner of each affected unit. Then, I'd keep a sorted list of all instances based on when they were created, something like this:
All this quote refers to your first example right ? All to the same array structure, right ?

Ok, I tried applying your suggestion, but I have problems. I need some concepts to be explained better and your code doesn't seem to compile.
(Btw, where the hell do you get such ideas ? This is totally from other world ! I can do system with this stuff ! xD)

Collapse JASS:
globals
        private SortedList array instances
        private integer instanceCount = 0
    endglobals
    
    private struct SortedList
        static method create takes nothing returns SortedList
            local SortedList anInstance = SortedList.allocate()
            
            set instances[instanceCount] = anInstance
            set instanceCount = instanceCount + 1
            
            return anInstance
        endmethod
    endstruct

Compile error:
- Undefined type: Sorted List (ya it should be down, but if I do so, I will have an undeclared variable called instances)

Can you enlight me better the quoted sections and the code(second example) ?
Is GroupClear some system ? Maybe it is a native I don't know, I don't have JNGP now, I will see it later. I assume it clears all units from a group xD
Wouldn't it be better to use a group recycling system ? I mean one of those made by Vexorian. What do you advice ?

PS: Also, I see you are taking special effort into this, I really thank that and appreciate it. Please don't be mad at me if I don't understand some of your stuff, I am still new at this, I don't have your experience, and mainly, we both know I am no genius xD
09-16-2008, 06:47 PM#4
Anitarf
Quote:
Originally Posted by Flame_Phoenix
I assume you refer to all affected units of this instance of the spell right ?
Since it's one group per instance, yes.

Quote:
Ok, I tried applying your suggestion, but I have problems. I need some concepts to be explained better and your code doesn't seem to compile.
We've been here before. You need to use keyword.

Quote:
Is GroupClear some system ? Maybe it is a native I don't know, I don't have JNGP now, I will see it later. I assume it clears all units from a group xD
GroupClear is a native.
Quote:
Wouldn't it be better to use a group recycling system ? I mean one of those made by Vexorian. What do you advice ?
It would be the exact same thing, except that you'd be using an extra system for no reason.
09-17-2008, 07:09 PM#5
Flame_Phoenix
Quote:
We've been here before. You need to use keyword.
Arrghh damn so basic, why didn't I see that before. Thx.

Quote:
It would be the exact same thing, except that you'd be using an extra system for no reason.
Avoiding coupling in systems is good, you do have a point...

I have lots of questions about the logic you implemented in this, also please answer my other questions when you have time.

EDIT EDIT EDIT

Quote:
Then, I'd sort the units in the groups not based on their previous owner, but on their new owner. Then, I'd create one struct at init that would be permanent and would be used to store the original owner of each affected unit.
You are telling me to save the new owner of the unit inside the member allPlayers[] and to create a permanent structure on Init that would keep the previous owner of the victim ???

Can you explain me how would this work ?? I don't get where this is going =S

EDIT EDIT EDIT

Anitarf, since you suggested a path for me to explore, but I need to know what goes exactly in your mind. Can you explain better please ?
Also, not I don NOT wan codes, I just want a little text that explains how things would work... if you could help, I would appreciate.
09-17-2008, 08:08 PM#6
Anitarf
Quote:
You are telling me to save the new owner of the unit inside the member allPlayers[] and to create a permanent structure on Init that would keep the previous owner of the victim ???
Not the previous owner, the original owner.
Quote:
Can you explain me how would this work ?? I don't get where this is going =S
The sorted list is the key. When a spell instance expires, the list allows you to find the newest instance that still affects each unit (unless none does, in which case your search through the list would eventually reach the origin struct with the original owner).
09-17-2008, 08:42 PM#7
Flame_Phoenix
Quote:
Not the previous owner, the original owner.
Arrghh this line is hell itself. So I will keep the orginal owner in a structure that never dies ?
I got the list part, you explained it quite well, however I am not seeing this work with the other stuff !
09-17-2008, 08:54 PM#8
Flame_Phoenix
PS: CAn you exemplify your idea with an example ? Or Pseudo code ?
PS2: I would really like to make this alone, I just need to know how would the master group and the structure at Init work together ... or the logic behind that ...
09-17-2008, 09:08 PM#9
Anitarf
Let's say the spell is cast three times. Each time it's cast, it checks for each unit it affects if it's already stored in the "origin" struct, if it isn't yet then it adds the unit there and stores who it's original owner was, if the unit is already there it does nothing. So, let's say we have units A,B,C and D belonging to player 1 affected by these three spell instances:
Situation:
spell instanceaffected units (player)
0 (origin)
1
2
3
A(1) B(1) C(1) D(1)
A(3) B(5)
B(6) C(2) D(7)
A(8) D(4)
Obviously, spells that were cast later override spells that were cast earlier, so at this point the owners of our units would be A(8) B(6) C(2) D(4). Now, let's say that the second instance was cast at a lower level than the other two and expires sooner. First, we remove it from the list, so it now looks like this:
Situation:
spell instanceaffected units (player)
0 (origin)
1
2
A(1) B(1) C(1) D(1)
A(3) B(5)
A(8) D(4)
Now, we check for each of the units that were affected by this instance (B, C and D) what to do with them. For each one, we loop through the instances from newest to oldest and stop looking the moment we find it. We find B in instance 1, and set it's owner to player 5, under who's control the unit will remain until spell instance 1 expires. We find D in instance 2 (formerly instance 3) and set it's owner to player 4, which doesn't change anything because that is the last instance cast to affect unit D so it's owner was already player 4. We don't find unit C in any struct except in the origin struct: this means that the instance that just expired was the only one affecting unit C so we return it to player 1, also, because we found it only in the origin struct, we now remove it from it, so the final situation is:
Situation:
spell instanceaffected units (player)
0 (origin)
1
2
A(1) B(1) D(1)
A(3) B(5)
A(8) D(4)
09-17-2008, 10:07 PM#10
moyack
Expand To be continued...:
09-18-2008, 11:35 AM#11
Flame_Phoenix
OMG I feel so crushed and overwhelmed by all this new complexity. I made no Idea making this spell would be so damn hard ! I am just a begginer and now I am learning all this kind of stuff !
I will try understanding Moyack's code (Thx btw, it will be helpful) because I believe it does what Anitarf has in mind. I never used cache before in all my life, this will be something new.... I just hope I can learn it.

I will post questions and codes soon, to prove you guys I am actually trying to understand and learn stuff.
If I ever finish this spell, it will be my jewel, but it will not be just mine, it will be from Anitarf and Moyack too. Thx.

EDIT EDIT EDIT

Ok question:

[jass]private struct olddata // a struct to store the old data, uses gamecache to do O(1) searchs
static gamecache GC = InitGameCache("Confusion.w3v")
player p
unit u

static method Add takes unit c returns nothing
local olddata OD = olddata.allocate()
set OD.p = GetOwningPlayer(c)
set OD.u = c
call StoreInteger(olddata.GC, "olddataindexes", I2S(h2i(c)), integer(OD))
endmethod

static method GetOldData takes unit u returns olddata
return olddata( GetStoredInteger(olddata.GC, "olddataindexes", I2S(h2i(u))) )
endmethod

method onDestroy takes nothing returns nothing
call FlushStoredInteger(olddata.GC, "olddataindexes", I2S(h2i(.u)))
endmethod
endstruct[jass]

Ok:
1 - static gamecache GC = InitGameCache("Confusion.w3v") , isn't this evil ? Shouldn't this structure have a create method where I would do this ?

2 - StoreInteger(cache, missionKey, key, integer), what is the difference between missionKey and key ? How will they be used ?

3 - call StoreInteger(olddata.GC, "olddataindexes", I2S(h2i(c)), integer(OD))
Ok so here we add an entire structure (an instance ?) to game cache right ?

4 - call FlushStoredInteger(olddata.GC, "olddataindexes", I2S(h2i(.u)))
Here we destroy the instance right ?

5 - This is the Origin structure I have to create on Init correct ?

Collapse JASS:
private struct data
    static group G = CreateGroup() // this group will store ALL the units which are affected by the spell
                                   // This group will ensure that units can't be affected twice by different spell casts
    group g // this one will store the ones that are affected per spell cast
    
    private static method Assign takes nothing returns nothing
        
    endstruct
    
    static method create takes unit c, location l returns data
        local data D = data.allocate()
        if D.g == null then
            set D.g = CreateGroup()
        endif
        call GroupEnumUnitsInRangeOfLoc(D.g, l, Radius(GetUnitAbilityLevel(c, AID)), Condition(function data.filter))
        call ForGroup(D.g, function data.Assign)
    endmethod
    
endstruct

Ok:
1 - This structure is the MyStruct structure correct ?

2 -
Collapse JASS:
private static method Assign takes nothing returns nothing
        
    endstruct
In this method I will add the units to group G.
What is group "g" for ?

3 -
Collapse JASS:
 static method create takes unit c, location l returns data
        local data D = data.allocate()
        if D.g == null then
            set D.g = CreateGroup()
        endif
        call GroupEnumUnitsInRangeOfLoc(D.g, l, Radius(GetUnitAbilityLevel(c, AID)), Condition(function data.filter))
        call ForGroup(D.g, function data.Assign)
    endmethod
MM I see you are using a Recycling thing like Anitarf suggested in first post.
Also, according to this line: call GroupEnumUnitsInRangeOfLoc(D.g, l, Radius(GetUnitAbilityLevel(c, AID)), Condition(function data.filter)) I should add a "filter" method correct ?
Finally call ForGroup(D.g, function data.Assign), I made no idea we could use methods in ForGroupBJ...


Ok, guys if this is what Anitarf had in mind, I am sorry to disappoint him, I would've never reach this code alone =S
I just wonder if this is "too much sand for my truck" but I must try !
Thx for posting code.

Can some now answer ?
PS: I know this seems a JASS class, sorry for that =S
09-19-2008, 01:53 AM#12
moyack
Before explaining anything, I'll talk about how I imagine this spell should work, I hope not to confuse and if it happens please let me know.

I'll resume in points my imaginary about what this spell should do:
  • A caster cast an AOE spell over units
  • the units in this AOE should change owner
  • this spell keeps that change for an amount of time
  • the units affected should return to the previous owner

Now the things to take into consideration when this spell should be developed:
  • Which ability should I use to obtain the desired target type?
  • This spell must be MUI, yeahhh!!
  • This spell can't be casted on heroes (ugly side effects could happen)
  • Should buildings be affected too?
  • Should this spell be stackable? if so, how this stackability should affect the affected unit? (very important IMO)

Now the technical information. What data should be saved about the affected units?
  • the units
  • the original owner player for each unit
  • The group of units affected by a spell cast
  • The group of units already affected by this type of spell

With this very clarified, we can now proceed with the spell development. following the spell steps we can relate what jass stuff we will require. I have to confess I'm a struct whore and for that reason my code tends to be "encapsulated" in structs. Why I do this? because structs help you to keep your code very organized, and they can take different roles in a code without changing them too much.

Ok, let's continue with the explanation about this spell. We need that this spell groups the units affected by the spell and then change their owning player to other players according a set of conditions and probabilities.

First, let's do a function that takes the group of units and store in each of them their original owning player.

Collapse JASS:
private struct Spell // this struct will manage the spell process
   group g // this group component will store all the units affected by the spell
endstruct

Because this spell is AOE and we need to catch units in a range, then we must base this spell on an ability that is normally used to affect cluster of units. My options goes to Blizzard or Rain of Fire. So this spells allow us to get the spell location and manages AOE, then... let's use any of them.

Ok, now we'll add to the struct a method to catch the units in the range of effect and process them properly.

Collapse JASS:
private struct Spell // this struct will manage the spell process
   group g // this group component will store all the units affected by the spell

   static method Add takes location l returns Spell
      local Spell S = Spell.allocate()
      if S.g == null then
         set S.g = CreateGroup()
      endif
      call GroupEnumUnitsInRangeOfLoc( // to be continued...
   endmethod
endstruct

To be continued... (I need to sleep)
09-19-2008, 02:37 PM#13
Flame_Phoenix
Quote:
I'll resume in points my imaginary about what this spell should do:
I also did that and I think I kinda explained it in some thread.
About the units affected, it really doesn't matter IMO, since if we don't like them, we just change the boolean function nice and easy.
And yes, my main problem is making this spell stackable and MUI ... sounds like impossible mission for me ...

Quote:
Now the technical information. What data should be saved about the affected units?
I see you are going by a different way, different from Anitarf's suggestion ... It looks I have to start from zero.
Quote:
Because this spell is AOE and we need to catch units in a range, then we must base this spell on an ability that is normally used to affect cluster of units. My options goes to Blizzard or Rain of Fire. So this spells allow us to get the spell location and manages AOE, then... let's use any of them.
I am using silence ... I believe it is better because it leaves a buff, but this isn't really important, the code is xD

I seriously believe you are complicating. I don't have a method to add units, and it is still very easy to understand.
Anyway, that is not important, this important thing is that the units in affected by this spells instance get to group "g", and I can do that without methods (lol).

I now how to do some of the stuff, however if you start talking about cache and all that stuff, I really get lost.
I find it most obvious I have to remake the spell now and that I won't be able to send it to the spell olympics, but it doesn't matter. I fel it is obvious I made some mistake in the planning stage and now the price for that mistake is starting again ... damn.

Quote:
To be continued... (I need to sleep)
Damn you people from the other side of the world, always doing stuff on the wrong time ! xD
It is still day where I live lol =P ...
09-22-2008, 02:15 PM#14
moyack
Sorry, I've been busy, so I decided to answer your questions directly...

Quote:
Originally Posted by Flame_Phoenix
1 - static gamecache GC = InitGameCache("Confusion.w3v") , isn't this evil ? Shouldn't this structure have a create method where I would do this ?
When you set a struct component as static is the same as if you define a global variable but inside the struct.

Quote:
2 - StoreInteger(cache, missionKey, key, integer), what is the difference between missionKey and key ? How will they be used ?
Game cache store the data as a table, mission key can be seen as the row name and key as the column name.

Quote:
3 - call StoreInteger(olddata.GC, "olddataindexes", I2S(h2i(c)), integer(OD))
Ok so here we add an entire structure (an instance ?) to game cache right ?
Correct :)

Quote:
4 - call FlushStoredInteger(olddata.GC, "olddataindexes", I2S(h2i(.u)))
Here we destroy the instance right ?
Correct, it deletes the value.

Quote:
5 - This is the Origin structure I have to create on Init correct ?
This is a structure only to save the previous data of the afected units. I use game cache because it's very fast for searching data regardless of the amount of data stored.

Quote:
Collapse JASS:
private struct data
    static group G = CreateGroup() // this group will store ALL the units which are affected by the spell
                                   // This group will ensure that units can't be affected twice by different spell casts
    group g // this one will store the ones that are affected per spell cast
    
    private static method Assign takes nothing returns nothing
        
    endstruct
    
    static method create takes unit c, location l returns data
        local data D = data.allocate()
        if D.g == null then
            set D.g = CreateGroup()
        endif
        call GroupEnumUnitsInRangeOfLoc(D.g, l, Radius(GetUnitAbilityLevel(c, AID)), Condition(function data.filter))
        call ForGroup(D.g, function data.Assign)
    endmethod
    
endstruct

Ok:
1 - This structure is the MyStruct structure correct ?
yes, it could be if you like my approach. My idea in general is doing this:
  • Caster cast
  • We group the units and store their data
  • A timer will check if the units in the group has the buff off, if so, we retrieve the data stored and we set that data to those units.
  • Voila!!

Quote:
2 -
Collapse JASS:
private static method Assign takes nothing returns nothing
        
    endstruct
In this method I will add the units to group G.
What is group "g" for ?
Now that I think this again, I can avoid this component, because we have the buff...

Quote:
3 -
Collapse JASS:
 static method create takes unit c, location l returns data
        local data D = data.allocate()
        if D.g == null then
            set D.g = CreateGroup()
        endif
        call GroupEnumUnitsInRangeOfLoc(D.g, l, Radius(GetUnitAbilityLevel(c, AID)), Condition(function data.filter))
        call ForGroup(D.g, function data.Assign)
    endmethod
MM I see you are using a Recycling thing like Anitarf suggested in first post.
Also, according to this line: call GroupEnumUnitsInRangeOfLoc(D.g, l, Radius(GetUnitAbilityLevel(c, AID)), Condition(function data.filter)) I should add a "filter" method correct ?
Correct, to select which units should be affected...
Quote:
Finally call ForGroup(D.g, function data.Assign), I made no idea we could use methods in ForGroupBJ...
I don't get it...
09-24-2008, 09:21 PM#15
Flame_Phoenix
Well, as we say in my country, better late than never. I just wish I could've delivered this spell into the Olympics.
Anyway, most this concepts you present here to me are new, some either confusing. I really start doubting my capabilities to build such a spell.
I will review this later once again.

It late in my country, and now, I must also rest my mind.
Thx for help though =)