HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

[OLY] Golem Invocation Remake

08-12-2008, 03:21 PM#1
Flame_Phoenix
Hi guys, I am remaking my spell Golem Invocation so I can enter the Spell Olympics. There is a chance this spell can't enter because it was previously made (but not accepted) but, no matter the decision of the judge, I just want to make the spell with all your help and to see this approved, so I can help the community as well with another hight quality spell.

I started remaking the spell as Pyrogasm suggested, using arrays. However, the moment you see my spell you will find a problem: I don't initialize the arrays because they depend on a level. If I initialize them, then the spell will not be MUI. I need some suggestion on how to end this. Can some one help me please ?

Btw, the spell uses TimerUtils.

Collapse JASS:
scope GolemInvocation initializer Init
//===========================================================================
//=============================SETUP START===================================
//===========================================================================

    globals
        private constant integer AID = 'A001'   //the rawcode of the ability
        private constant string ANIMATION = "birth" //the animation that will be played when the unit is created
        private constant integer MAX_GOLEM_TYPES = 3
        private integer array GOLEM_TYPES
        private real array GOLEM_CHANCES
    endglobals

    
//===========================================================================
//============================GOLEM SETUP====================================
//===========================================================================

    private function SetupGolemTypes takes integer level returns nothing
        set GOLEM_TYPES[0] = 'ngrk'
        set GOLEM_TYPES[1] = 'ngst'
        set GOLEM_TYPES[2] = 'nggr'
    endfunction
    
    private function GolemChances takes integer level returns nothing
        set GOLEM_CHANCES[0] = 1. - (level * 0.1)
        set GOLEM_CHANCES[1] = (level * 0.07) - 0.01
        set GOLEM_CHANCES[2] = 0.01 + (0.03 * level)
    endfunction


    private constant function golemLife takes integer level returns real
        return level * 20.  //the amount of time each golem will be alive live
    endfunction

    private constant function channelGolems takes integer level returns boolean
        //if true it will make all spawned golems die when the caster stops the channel
        //if false, it allows the golems to have golemLife seconds of life and they
        //will not die when the caster stops the channel
        //in this case my golems 20, 40 and 60 seconds of life for each leavel.
        return false
        
        //example of usage

//        if (level == 3) then
//            return false
//        endif
//        return true

        //in this example the golems will die when the channel ends in level 1 and 2
        //in level 3, the golems will live 60 seconds of life
    endfunction
    
    private constant function golemsPerCycle takes integer level returns integer
        //the number of golems that will be created each cycle
        return 1 + (level * 0)
    endfunction
    
    
    private constant function cycle takes integer level returns real
        //the cycle which will determine when we create golems
        //this means, golemsPerCycle golems are created every cycle
        //in this case, we create 1 golem per second (in this case a second 
        //is a cycle)
        return 1. + (level * 0) 
    endfunction
    
//===========================================================================
//============================DUST SETUP=====================================
//===========================================================================
    
    private constant function dummyEffectId takes integer level returns integer
        //the rawcode of the dummy unit that will be dust
        //this is in a function so you can have different effects in different
        //levels
        return 'h000'
    endfunction
    
    private constant function minRange takes integer level returns real
        //in this case we dont have a minimum range, which means we can 
        //create units at the center of the circle
        //the minimum range is smaller circle, inside the area of the spell
        //in which golems will not be created
        return 0.
    endfunction
    
    private constant function maxRange takes integer level returns real
        //this ensures golems are not created outside the AOE of the spell
        //this gives the AOE of the spell
        return 200. + (level * 100)
    endfunction
    
    private constant function circleCount takes integer level returns integer
        //the number of circles that will be created to give the illusion of the dust
        //effect. The more circles the more realistic, but more CPU will be needed.
        return 3 + level 
    endfunction
    
    private constant function innerCircleUnits takes integer level returns integer
        //the number of units that the most inner circle will have
        return level + 5
    endfunction
    
    private constant function innerCircleUnitsIncrease takes integer level returns integer
        //the increment of units per circle
        return level + 2
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================

    globals 
        private group GolemInvocationCasters
        private HandleTable activeTable 
    endglobals
    
    private struct MyStruct 
        unit caster
        integer level
        timer cycleTimer 
        real spellLocX
        real spellLocY
        group dummyEffects
        group golems
        
        static method create takes unit caster, real locX, real locY returns MyStruct
            local MyStruct data = MyStruct.allocate()
            
            //set variables about the caster
            set data.caster = caster
            set data.level = GetUnitAbilityLevel(data.caster, AID)
            
            //variables about the location
            set data.spellLocX = locX
            set data.spellLocY = locY
            
            //the timer which will determine when we create golems
            //creates a golem everytime it expires
            set data.cycleTimer = NewTimer()   
            
            //This groups will save the dumy dust effects, so we can kill them 
            //when the caster stops the channeling
            set data.dummyEffects = CreateGroup()
            
            //if we want the golems to die when the caster stops channel
            //then we create this group so we can add all golems to it
            //then we kill the golems when the caster stops the channel
            if (channelGolems(data.level)) then
                set data.golems = CreateGroup()
            endif
            
            return data
        endmethod
        
        method onDestroy takes nothing returns nothing
            
            //here we select all units from the group and we kill them all ! =P
            //thus meaning that the dust effects will disappear ! 
            local unit f
            loop
                set f = FirstOfGroup(.dummyEffects)
                exitwhen(f == null)
                call GroupRemoveUnit(.dummyEffects, f)
                call KillUnit(f)
            endloop
            
            //if the variable is true, then golems group was created and it has
            //units. Now we just kill all units it has and we release the group
            //for CSSafety to use one day later
            if (channelGolems(.level)) then
                loop
                    set f = FirstOfGroup(.golems)
                    exitwhen(f == null)
                    call GroupRemoveUnit(.golems, f)
                    call KillUnit(f)
            endloop
            
            call DestroyGroup(.golems)
            endif
            
            //since the spell is not active anymore, we clean the Table     
            call activeTable.flush(.caster) 
            
            //the units are not anymore in the active units group.
            call GroupRemoveUnit(GolemInvocationCasters, .caster) 
            
            //releasing the timer and group for CSSafety to use it one day later =D
            call ReleaseTimer(.cycleTimer)
            call DestroyGroup(.dummyEffects)
            
        endmethod
    endstruct
    
//===========================================================================
    private function onStop takes nothing returns boolean
        local MyStruct data
        local unit u = GetTriggerUnit()
        
        //when a unit stops the channel, we verify if that unit is inside the
        //catsers group. If so, than it is because it is a caster casting this spell
        //and so we recover information about him and we make the spell end
        if(IsUnitInGroup(u, GolemInvocationCasters)) then
            //recover the data from the caster
            set data = activeTable[u] 
            
            //now, time to clean the mess once again
            call data.destroy() 
        endif

        set u = null
        
        return false
    endfunction
//===========================================================================
    //Function made by Themerion and adapted by Flame_Phoenix
    //Creates circles of dummy units to give the illusion of the dust effect
    private function createDust takes integer aStruct returns nothing
        local MyStruct data = aStruct
        
        // forPlayer     -> Create the units for which player?
        local player forPlayer = GetOwningPlayer(data.caster)
        
        // innerRadius   -> The radius of the innermost circle
        // outerRadius   -> The radius of the outmost circle
        local real innerRadius = minRange(data.level)
        local real outerRadius = maxRange(data.level)
        
        // x and y       -> Center of circles
        local real x = data.spellLocX
        local real y = data.spellLocY

        local real radiusInc = (outerRadius - innerRadius) / I2R(circleCount(data.level)-1)
        
        //see functions they call
        local integer fxcount = innerCircleUnits(data.level)
        local integer fxcountinc = innerCircleUnitsIncrease(data.level)
        
        local real phi = 0
        local real phiInc

        loop
            exitwhen (innerRadius + 0.001 >= outerRadius)

            set phi = 0
            set phiInc = 2*bj_PI/I2R(fxcount)
            
            loop
                exitwhen (phi + 0.001 >= 2 * bj_PI)
                //we add the units to a group, so we can kill them when we want ! =P
                call GroupAddUnit(data.dummyEffects, CreateUnit(forPlayer, dummyEffectId(data.level), x + innerRadius * Cos(phi), y + innerRadius * Sin(phi), 180 + Rad2Deg(phi)))
                set phi = phi + phiInc
            endloop
            
            set innerRadius = innerRadius + radiusInc
            set fxcount = fxcount + fxcountinc
        
        endloop
        
        set forPlayer = null
    
    endfunction
//===========================================================================
    //Function made by Vexorian, it selects a random region in a disk. 
    //All regions have the same chance of beeing choosen
    private function GetRandomPointInDisk takes real centerx, real centery, real minradius, real maxradius returns location
        local real d = SquareRoot(GetRandomReal(minradius * minradius, maxradius * maxradius))
        local real a = GetRandomReal(0, 2 * bj_PI)
        return Location(centerx + d * Cos(a), centery + d * Sin(a))
    endfunction
//===========================================================================
    private function createGolems takes nothing returns nothing
        //we get the structure from the timer
        local MyStruct data = MyStruct(GetTimerData(GetExpiredTimer())) 
        
        //variables for us to know where the golems will born
        local location point  
        local real randomX  
        local real randomY 
        
        //the chances that each golem will have to be spawned
        local real aChance
        
        //just to keep count about how many golems we created
        local integer loopCounter = 0
        
        //variables about the golems
        local unit golem
        local real golemFacing = GetUnitFacing(data.caster)
        
        //Here we spawn the golems 
        loop 
            exitwhen(loopCounter >= golemsPerCycle(data.level))
                
            set point = GetRandomPointInDisk(data.spellLocX, data.spellLocY, minRange(data.level), maxRange(data.level))
            set randomX = GetLocationX(point)
            set randomY = GetLocationY(point)
            set aChance = GetRandomReal(0, 1)
            
            if (aChance <= 1 - GOLEM_CHANCES[0]) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), GOLEM_TYPES[0], randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                
                //if channelGolems(data.level) is true we add the golem to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelGolems(data.level)) then
                    call GroupAddUnit(data.golems, golem)
                else
                    call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
                endif
            elseif (aChance <= 1 - GOLEM_CHANCES[1]) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), GOLEM_TYPES[1], randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                
                //if channelGolems(data.level) is true we add the golem to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelGolems(data.level)) then
                    call GroupAddUnit(data.golems, golem)
                else
                    call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
                endif
            elseif (aChance <= 11 - GOLEM_CHANCES[2]) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), GOLEM_TYPES[2], randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                
                //if channelGolems(data.level) is true we add the golem to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelGolems(data.level)) then
                    call GroupAddUnit(data.golems, golem)
                else
                    call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
                endif
            endif   
            
            call RemoveLocation(point)
            set point = null
                
            set loopCounter = loopCounter + 1
        endloop
    
    set golem = null

    endfunction
//===========================================================================
    private function Conditions takes nothing returns boolean
        local MyStruct data
        local location spellLoc //the location of the spell
        
        if (GetSpellAbilityId() == AID) then
            //setting variables for the struct
            set spellLoc = GetSpellTargetLoc()
            set data = MyStruct.create(GetTriggerUnit(), GetLocationX(spellLoc), GetLocationY(spellLoc))
            
            //put the struct in the Table, we just use the caster's handle adress as 
            //the key which tells us where in the Table the struct is stored
            set activeTable[data.caster] = data 

            //  we add the casting unit to some sort of "pool"
            call GroupAddUnit(GolemInvocationCasters, data.caster)
            
            //now we create the dusty effect
            call createDust(data)
            
            //we attach the struct to the timer
            call SetTimerData(data.cycleTimer, integer(data))
            call TimerStart(data.cycleTimer, cycle(data.level), true, function createGolems)
            
            //cleaning up the mess
            call RemoveLocation(spellLoc)
        endif
        
        set spellLoc = null
        
        return false
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        local trigger GolemInvocationTrigger = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(GolemInvocationTrigger, Condition( function Conditions ) )
        
        set GolemInvocationTrigger = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddCondition(GolemInvocationTrigger,  Condition(function onStop))

        set GolemInvocationTrigger = null
        
        //set our globals
        set activeTable = HandleTable.create() 
        set GolemInvocationCasters = CreateGroup() 

        set GolemInvocationTrigger = null
    endfunction
endscope 

Ofc I will give credit and rep++ to those who help me.
I am following a suggestion to allow for any number of units to be spawned. Does any one else has other suggestions ?
08-12-2008, 07:42 PM#2
Veev
Quick question, why do you have:
Collapse JASS:
    private constant function golemsPerCycle takes integer level returns integer
        //the number of golems that will be created each cycle
        return 1 + (level * 0)
    endfunction

and
Collapse JASS:
    private constant function cycle takes integer level returns real
        //the cycle which will determine when we create golems
        //this means, golemsPerCycle golems are created every cycle
        //in this case, we create 1 golem per second (in this case a second 
        //is a cycle)
        return 1. + (level * 0) 
    endfunction

It seems kind of silly if you don't want it to increase based on level.
08-12-2008, 08:05 PM#3
Flame_Phoenix
It is my belief that people should learn when reading code. That is not there due efficiency, but in case that of some one needs to use the level, they have a clue on how they can do it.

I won't change that. Still thx for your reply.

So guys can anyone help me ?
08-12-2008, 09:26 PM#4
Fulla
Could you add the spell tooltip? i.e. what the spell does etc.
08-12-2008, 09:48 PM#5
Flame_Phoenix
Oh, sure, I explain the code.
When the caster start, we add him to a group (so we can use Table) and create the struct.
Then, we start a timer. This timer will create the golems in an area. The golems created are of several types and the weaker the golem the more chances it has to be spawned. Chances go from 0 to 1. When creating the golem we check if the user wants to kill all golems when spell stops channel (and in that case we add them to a group) or if the user wants to give them a life time. When the caster stops channel we kill the dust dummy units and, if the case, the golems.
Where is Table in all of this ? Well, Table makes sure everything works fine if our caster dies during the channeling.

The problem here is to allow the user to create any number of units, of any type with any chances. I can't find a solution for this... can some one help me ?? I would really like to see this approved. =S

If you have any more questions regarding the spell, say so I can help. I also want people to learn from my spells, that is also why I create them ! =)
08-13-2008, 06:36 AM#6
Pyrogasm
You entirely missed my point about using a 2-D array. I'll restate myself:
Collapse JASS:
private constant function GolemChances takes nothing returns Integer
    set GolemChances[MAX_GOLEM_TYPES*1+1] = 0.60 //It's a 2-D array, though I imagine it could be more efficient
    set GolemChances[MAX_GOLEM_TYPES*1+2] = 0.25 //The key here is "MAX_GOLEM_TYPES*<Level>+<Rank of Golem>"
    set GolemChances[MAX_GOLEM_TYPES*1+3] = 0.10 //Instead of all this manual setting, one could also use loops and that sort of stuff to set the array values properly, but I did it this way to easily show what I was doing
    set GolemChances[MAX_GOLEM_TYPES*1+4] = 0.05

    set GolemChances[MAX_GOLEM_TYPES*2+2] = 0.60 //The reason we're storing it in an array is to keep the user from having to figure out complex mathematic equations and/or having to set up branching if-then-else trees to return the proper chance
    set GolemChances[MAX_GOLEM_TYPES*2+3] = 0.25
    set GolemChances[MAX_GOLEM_TYPES*2+4] = 0.10
    set GolemChances[MAX_GOLEM_TYPES*2+5] = 0.05

    set GolemChances[MAX_GOLEM_TYPES*3+3] = 0.60
    set GolemChances[MAX_GOLEM_TYPES*3+4] = 0.25
    set GolemChances[MAX_GOLEM_TYPES*3+5] = 0.10
    set GolemChances[MAX_GOLEM_TYPES*3+6] = 0.05

   set GolemChances[0] = 0 //Also preventing crashes
endfunction

The arrays you have have nothing to do with the spell being MUI or not. All they do is store the generic data for the spells so that, say, the chance for a level 4 golem in the 2nd level of the spell doesn't have to be computed through a formula.
Quote:
Originally Posted by Flame_Phoenix
Collapse JASS:
    private function SetupGolemTypes takes integer level returns nothing
        set GOLEM_TYPES[0] = 'ngrk'
        set GOLEM_TYPES[1] = 'ngst'
        set GOLEM_TYPES[2] = 'nggr'
    endfunction
    
    private function GolemChances takes integer level returns nothing
        set GOLEM_CHANCES[0] = 1. - (level * 0.1)
        set GOLEM_CHANCES[1] = (level * 0.07) - 0.01
        set GOLEM_CHANCES[2] = 0.01 + (0.03 * level)
    endfunction
Those don't need to take level arguments. In fact, I have no clue what you thought you were doing with this because you never even call these functions....
08-13-2008, 09:15 AM#7
Flame_Phoenix
Quote:
Originally Posted by Pyrogasm
You entirely missed my point about using a 2-D array. I'll restate myself:
Collapse JASS:
private constant function GolemChances takes nothing returns Integer
    set GolemChances[MAX_GOLEM_TYPES*1+1] = 0.60 //It's a 2-D array, though I imagine it could be more efficient
    set GolemChances[MAX_GOLEM_TYPES*1+2] = 0.25 //The key here is "MAX_GOLEM_TYPES*<Level>+<Rank of Golem>"
    set GolemChances[MAX_GOLEM_TYPES*1+3] = 0.10 //Instead of all this manual setting, one could also use loops and that sort of stuff to set the array values properly, but I did it this way to easily show what I was doing
    set GolemChances[MAX_GOLEM_TYPES*1+4] = 0.05

    set GolemChances[MAX_GOLEM_TYPES*2+2] = 0.60 //The reason we're storing it in an array is to keep the user from having to figure out complex mathematic equations and/or having to set up branching if-then-else trees to return the proper chance
    set GolemChances[MAX_GOLEM_TYPES*2+3] = 0.25
    set GolemChances[MAX_GOLEM_TYPES*2+4] = 0.10
    set GolemChances[MAX_GOLEM_TYPES*2+5] = 0.05

    set GolemChances[MAX_GOLEM_TYPES*3+3] = 0.60
    set GolemChances[MAX_GOLEM_TYPES*3+4] = 0.25
    set GolemChances[MAX_GOLEM_TYPES*3+5] = 0.10
    set GolemChances[MAX_GOLEM_TYPES*3+6] = 0.05

   set GolemChances[0] = 0 //Also preventing crashes
endfunction
Well, I don't understand some stuff in your way of doing things, like, per example, how will I use that array and when ? ALso, what happens to the golems with rank 1 and 2 when we reach level 3 ?


Quote:
Originally Posted by Pyrogasm
The arrays you have have nothing to do with the spell being MUI or not. All they do is store the generic data for the spells so that, say, the chance for a level 4 golem in the 2nd level of the spell doesn't have to be computed through a formula.

Those don't need to take level arguments. In fact, I have no clue what you thought you were doing with this because you never even call these functions....
Well, That is the point. I was thinking of using storing the values in an array and then use it. However I don't call the function because I can0t do it, otherwise my spell will not be MUI. Therefore my solution will not be what I need and that is why I am posting here. My problem is that your solution is a new concept for me, and so I have problems either knowing how to understand it, and mainly how to and where to use it.

I'll need some more help Pyro =S
08-13-2008, 11:08 AM#8
Pyrogasm
Okay, so you don't really understand what I'm getting at here with the arrays. I'll try to explain it a bit differently this time.

So let's assume you have some spell (not this one) and in that spell there is a function that returns a different unit-type for each level of the spell. You might write this:
Collapse JASS:
constant function UnitType takes integer Level returns integer
    if Level == 1 then
        return 'e005'
    elseif Level == 2 then
        return 'h0af'
    elseif Level == 3 then
        return 'e0g2'
    endif

    return 0
endfunction

//Somewhere in a function that uses this:
local integer Type = UnitType(Level)
local unit U = CreateUnit(GetTriggerPlayer(), Type, X, Y, 0.00)
But that's not the only way to do this. Instead, one could use arrays to store the unit types and then access them that way:
Collapse JASS:
globals
    private integer array UnitTypes
endglobals

//Assuming this function is called with an initializer
function UnitType takes nothing returns nothing
    set UnitTypes[0] = 0       //This should actually be included in the init function, but you could do it here too
    set UnitTypes[1] = 'e005'  //See how the array index corresponds with the proper level of the spell?
    set UnitTypes[2] = 'h0af'
    set UnitTypes[3] = 'e0g2'
endfunction

//Somewhere in a function that uses this
local unit U = CreateUnit(GetTriggerPlayer(), UnitTypes[Level], X, Y, 0.00)
For all practical purposes, this isn't really a boost in efficiency or anything (sure, I guess you're saving function calls), but once things start getting more complicated it starts to make sense to move to arrays.

Taking the same situation, let's say you needed two unit-types for each level of the spell. Conventionally, this might be accomplished by doing this:
Collapse JASS:
constant function UnitType takes integer Level, integer Type returns integer
    if Level == 1 then
        if Type == 1 then
            return 'e005'
        elseif Type == 2 then
            return 'e006'
        endif
    elseif Level == 2 then
        if Type == 1 then
            return 'h0af'
        elseif Type == 2 then
            return 'h0gf'
        endif
    elseif Level == 3 then
        if Type == 1 then
            return 'e0g2'
        elseif Type == 2 then
            return 'e1f9'
        endif
    endif

    return 0
endfunction

//Somewhere in a function that uses this:
local integer Type1 = UnitType(Level, 1)
local integer Type2 = UnitType(Level, 2)
local unit U1 = CreateUnit(GetTriggerPlayer(), Type1, X, Y, 0.00)
local unit U2 = CreateUnit(GetTriggerPlayer(), Type2, X, Y, 0.00)
Things start to get more complicated now with the branching if-then-else trees. How would this be accomplished with 2-D arrays? Like this:
Collapse JASS:
globals
    private integer array UnitTypes
    private constant integer MAX_TYPES = 2 //2 because the max number of types we want per level is 2
endglobals

//Assuming this function is called with an initializer
function UnitType takes nothing returns nothing
    set UnitTypes[0] = 0
    set UnitTypes[MAX_TYPES*1+1] = 'e005' //Okay, so a 2-D array would be like saying UnitTypes[1][1], with the second array index being a subset of the first
    set UnitTypes[MAX_TYPES*1+2] = 'e006 //However, we can't do this in JASS, so we have to be a bit tricky about our 2-D arrays
    set UnitTypes[MAX_TYPES*2+1] = 'h0af'
    set UnitTypes[MAX_TYPES*2+2] = 'h0gf' //So if you want to access MyArray[A][b], the formula we use is:
    set UnitTypes[MAX_TYPES*3+1] = 'e0g2' //MyArray[MAX_NUMBER_OF_Bs*A+B], thus resulting in the formula you see to the left
    set UnitTypes[MAX_TYPES*3+2] = 'e1f9'
endfunction

//Somewhere in a function that uses this
local unit U1 = CreateUnit(GetTriggerPlayer(), UnitTypes[MAX_TYPES*Level+1], X, Y, 0.00)
local unit U2 = CreateUnit(GetTriggerPlayer(), UnitTypes[MAX_TYPES*Level+2], X, Y, 0.00)
Much cleaner and easier to modify, don't you think? Now imagine trying to accommodate any number of Bs (referring to the MyArray[A][b] 2-D arrays); its much simpler with a 2-D array. So what I'm telling you you should do is have two 2-D arrays: one for the unit-types for each level, and one for the chances for each unit-type for each level.

Now, for the "how am I going to apply this to the rest of my code" part: use unitpools. In fact, I made a handy-dandy tutorial on them already, which can be found here (I suggest you read it). Once you've read the tutorial, you'll understand what the "weight" for each unit in the unitpool means, and so this then becomes an easy way to turn "chance to spawn X golem" into a simple unitpool search.

What we need now is a unitpool array, with the index of the array corresponding to the level of the spell. We're going to do some precaching here and create all the needed unitpools right at map init so we can just create a random golem by picking a unit-type from the proper unitpool. Here's what I would do:
Collapse JASS:
globals
    private unitpool array GolemPools
    private constant integer MAX_GOLEM_TYPES = 3
    private constant integer TOTAL_LEVELS
    private integer array GolemTypes
    private real array GolemChances
endglobals

private function Init takes nothing returns nothing
    local integer A = 0
    local integer B = 0

    call GolemTypes()
    call GolemChances()

    loop
        set A = A+1
        exitwhen A > TOTAL_LEVELS

        set GolemPools[A] = CreateUnitPool()
        set B = 0
        loop
            set B = B+1
            exitwen B>MAX_GOLEM_TYPES

            call UnitPoolAddUnitType(GolemPools[A], GolemTypes[MAX_GOLEM_TYPES*A+B], GolemChances[MAX_GOLEM_TYPES*A+B])
        endloop
    endloop
endfunction
And then voilà! All you have to do to place the proper random Golem is: call PlaceRandomUnit(GolemPools[Level], GetOwningPlayer(Caster), X, Y, GetRandomReal(0.00, 360.00))!

Sweet, huh?
08-13-2008, 12:53 PM#9
Anitarf
You could also use multi-dimensional arrays to make the init code more readable, of course it takes some more code in the background to setup the arrays, but then you can do cool stuff like set UnitTypes[level][type] = 'e005'. You should read the dynamic arrays section of the vJass documentation.
08-13-2008, 01:28 PM#10
Flame_Phoenix
Mmm, Thx for your posts guys. I shall now make some research. I have a question though, what would be easier to use? Unit Pools or multidimensional arrays ??
Damn this things are far easier in JAVA ...
08-13-2008, 02:02 PM#11
Anitarf
Actually, you'd need to use both. Re-read what Pyro wrote, one thing is the calibration section where you define the unit types (here, multidimensional arrays would be used), the other is the spell code where you randomly pick the golems (here, unit pools would be used).

You could also use neither, there are different ways to do each part of the code, and I haven't thought about it enough to be able to tell you which one would result in cleaner and/or faster code, that's up to you to figure out, which you'll be able to do once you understand how and why different implementations work.
08-14-2008, 11:29 AM#12
Flame_Phoenix
Well, for me a multidimensional array has is more than 2D, although 2D can also be considered a multidimensional array in fact.
Well, anyway, thx for your help guys, a new version of the spell is now ready.

Collapse JASS:
//===========================================================================
//A spell that creates an Earthquake. This earthquake creates dust and spawns 
//golems inside the target area. Each golem has a period of life, and weaker
//golems have more chances to be spawned.
//
//Requires TimerUtils and Table
//
//@author Flame_Phoenix 
//
//@credits
//- the-thingy, Kyrbi0, Pyrogasm, Anitarf
//- My first teacher of vJASS: Blue_Jeans
//- All other people I forgot or ignored
//
//@version 1.3
//===========================================================================
scope GolemInvocation initializer Init

    //Gloabls for the spell's core, don't change
    globals 
        private integer array GOLEM_TYPES   
        private real array GOLEM_CHANCES
        private unitpool array GOLEM_POOLS
    endglobals
    
//===========================================================================
//=============================SETUP START===================================
//===========================================================================

    globals
        private constant integer AID = 'A001'   //the rawcode of the ability
        private constant string ANIMATION = "birth" //the animation that will be played when the unit is created
        private constant integer MAX_TYPES = 3  //The maximum number of unit types of the spell
        private constant integer MAX_LEVELS = 3 //the maximum number of levels of the spell
    endglobals
    
    
//===========================================================================
//============================GOLEM SETUP====================================
//===========================================================================

    private function GolemTypes takes nothing returns nothing
        //This is to prevent not innitialied arrays. 
        //It is also necessary for array indexing to work properly - don't change.
        set GOLEM_TYPES[0] = 0 
        
        //this sets the golem types. In this case we have 3 golem types
        //for level 1, 2 and 3; and the Golem types that can be spawned for 
        //each level are equal.
        
        //for level 1
        set GOLEM_TYPES[MAX_TYPES * 1 + 1] = 'ngrk'
        set GOLEM_TYPES[MAX_TYPES * 1 + 2] = 'ngst'
        set GOLEM_TYPES[MAX_TYPES * 1 + 3] = 'nggr'
        
        //for level 2
        set GOLEM_TYPES[MAX_TYPES * 2 + 1] = 'ngrk'
        set GOLEM_TYPES[MAX_TYPES * 2 + 2] = 'ngst'
        set GOLEM_TYPES[MAX_TYPES * 2 + 3] = 'nggr'
        
        //for level 3
        set GOLEM_TYPES[MAX_TYPES * 3 + 1] = 'ngrk'
        set GOLEM_TYPES[MAX_TYPES * 3 + 2] = 'ngst'
        set GOLEM_TYPES[MAX_TYPES * 3 + 3] = 'nggr'
        
        //Note that the formula being used is:
        //MAX_TYPES * level + NumberOfGolemType
        //this simulates a 2D array for the Golem Types we can have
    endfunction
    
    private function GolemChances takes nothing returns nothing
        //This is to prevent not innitialied arrays. 
        //It is also necessary for array indexing to work properly - don't change.
        set GOLEM_CHANCES[0] = 0
        
        //this sets the chances each golem has to be spawned.
        //In this case the chances will depend on level. Keeping in mind that
        //NumberOfGolemType 1 is the weaker, we will make him the most commun 
        //golem, and NumberOfGolemType 3 the most rare golem because he is the 
        //strongest. As you will see, chances will depend on the level, we will 
        //increase the chances of have a NumberOfGolemType 3 and decrease the chances
        //of having NumberOfGolemType 1.
        //NOTE: NumberOfGolemType1 + NumberOfGolemType2 + NumberOfGolemType3 = 1.0
        //This is very important for things to work properly.
        
        //for level 1
        set GOLEM_CHANCES[MAX_TYPES * 1 + 1] = 0.5
        set GOLEM_CHANCES[MAX_TYPES * 1 + 2] = 0.3
        set GOLEM_CHANCES[MAX_TYPES * 1 + 3] = 0.2
        
        //for level 2
        set GOLEM_CHANCES[MAX_TYPES * 2 + 1] = 0.4
        set GOLEM_CHANCES[MAX_TYPES * 2 + 2] = 0.4
        set GOLEM_CHANCES[MAX_TYPES * 2 + 3] = 0.2
        
        //for level 3
        set GOLEM_CHANCES[MAX_TYPES * 3 + 1] = 0.4
        set GOLEM_CHANCES[MAX_TYPES * 3 + 2] = 0.3
        set GOLEM_CHANCES[MAX_TYPES * 3 + 3] = 0.3
        
        //Note that the formula being used is:
        //MAX_TYPES * level + NumberOfGolemType
        //this simulates a 2D array for the chances each Golem Type has at each level
    endfunction
    
    private constant function GolemLife takes integer level returns real
        //the amount of time each golem will have, if ChannelGolems() is false
        return level * 20.  
    endfunction

    private constant function ChannelGolems takes integer level returns boolean
        //if true it will make all spawned golems die when the caster stops the channel
        //if false, it allows the golems to have GolemLife() seconds of life and they
        //will not die when the caster stops the channel
        //in this case my golems 20, 40 and 60 seconds of life for each level.
        return false
        
        //example of usage

//        if (level == 3) then
//            return false
//        endif
//        return true

        //in this example the golems will die when the channel ends in level 1 and 2
        //in level 3, the golems will live 60 seconds of life
    endfunction
    
    private constant function GolemsPerCycle takes integer level returns integer
        //the number of golems that will be created each cycle
        return 1 + (level * 0)
    endfunction
    
    private constant function Cycle takes integer level returns real
        //the cycle which will determine when we create golems
        //this means, GolemsPerCycle() golems are created every cycle
        //in this case, we create 1 golem per second (in this case a second 
        //is a cycle)
        return 1. + (level * 0) 
    endfunction
    
//===========================================================================
//============================DUST SETUP=====================================
//===========================================================================
    
    private constant function DummyEffectId takes integer level returns integer
        //the rawcode of the dummy unit that will be dust
        //this is in a function so you can have different effects in different
        //levels
        return 'h000'
    endfunction
    
    private constant function MinRange takes integer level returns real
        //in this case we dont have a minimum range, which means we can 
        //create golems at the center of the circle
        //the minimum range is smaller circle, inside the area of the spell
        //in which golems will not be created
        return 0.
    endfunction
    
    private constant function MaxRange takes integer level returns real
        //this ensures golems are not created outside the AOE of the spell
        //this gives the AOE of the spell
        return 200. + (level * 100)
    endfunction
    
    private constant function CircleCount takes integer level returns integer
        //the number of circles that will be created to give the illusion of the dust
        //effect. The more circles the more realistic, but more CPU will be needed.
        return 3 + level 
    endfunction
    
    private constant function InnerCurcleUnits takes integer level returns integer
        //the number of units that the most inner circle will have
        return level + 5
    endfunction
    
    private constant function InnerCurcleUnitsIncrease takes integer level returns integer
        //the increment of units per circle
        return level + 2
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================

    globals 
        private group GolemInvocationCasters
        private HandleTable activeTable 
    endglobals
    
    private struct MyStruct 
        unit caster
        integer level
        timer cycleTimer 
        real spellLocX
        real spellLocY
        group dummyEffects
        group golems
        
        static method create takes unit caster, real locX, real locY returns MyStruct
            local MyStruct data = MyStruct.allocate()
            
            //set variables about the caster
            set data.caster = caster
            set data.level = GetUnitAbilityLevel(data.caster, AID)
            
            //variables about the location
            set data.spellLocX = locX
            set data.spellLocY = locY
            
            //the timer which will determine when we create golems
            //creates a golem everytime it expires
            set data.cycleTimer = NewTimer()   
            
            //This groups will save the dumy dust effects, so we can kill them 
            //when the caster stops the channeling
            set data.dummyEffects = CreateGroup()
            
            //if we want the golems to die when the caster stops channel
            //then we create this group so we can add all golems to it
            //then we kill the golems when the caster stops the channel
            if (ChannelGolems(data.level)) then
                set data.golems = CreateGroup()
            endif
            
            return data
        endmethod
        
        method onDestroy takes nothing returns nothing
            
            //here we select all units from the group and we kill them all ! =P
            //thus meaning that the dust effects will disappear ! 
            local unit f
            loop
                set f = FirstOfGroup(.dummyEffects)
                exitwhen(f == null)
                call GroupRemoveUnit(.dummyEffects, f)
                call KillUnit(f)
            endloop
            
            //if the variable is true, then golems group was created and it has
            //units. Now we just kill all units it has and we release the group
            //for CSSafety to use one day later
            if (ChannelGolems(.level)) then
                loop
                    set f = FirstOfGroup(.golems)
                    exitwhen(f == null)
                    call GroupRemoveUnit(.golems, f)
                    call KillUnit(f)
            endloop
            
            call DestroyGroup(.golems)
            endif
            
            //since the spell is not active anymore, we clean the Table     
            call activeTable.flush(.caster) 
            
            //the units are not anymore in the active units group.
            call GroupRemoveUnit(GolemInvocationCasters, .caster) 
            
            //releasing the timer and group for CSSafety to use it one day later =D
            call ReleaseTimer(.cycleTimer)
            call DestroyGroup(.dummyEffects)
            
        endmethod
    endstruct
    
//===========================================================================
    private function onStop takes nothing returns boolean
        local MyStruct data
        local unit u = GetTriggerUnit()
        
        //when a unit stops the channel, we verify if that unit is inside the
        //catsers group. If so, than it is because it is a caster casting this spell
        //and so we recover information about him and we make the spell end
        if(IsUnitInGroup(u, GolemInvocationCasters)) then
            //recover the data from the caster
            set data = activeTable[u] 
            
            //now, time to clean the mess once again
            call data.destroy() 
        endif

        set u = null
        
        return false
    endfunction
//===========================================================================
    //Function made by Themerion and adapted by Flame_Phoenix
    //Creates circles of dummy units to give the illusion of the dust effect
    private function createDust takes integer aStruct returns nothing
        local MyStruct data = aStruct
        
        // forPlayer     -> Create the units for which player?
        local player forPlayer = GetOwningPlayer(data.caster)
        
        // innerRadius   -> The radius of the innermost circle
        // outerRadius   -> The radius of the outmost circle
        local real innerRadius = MinRange(data.level)
        local real outerRadius = MaxRange(data.level)
        
        // x and y       -> Center of circles
        local real x = data.spellLocX
        local real y = data.spellLocY

        local real radiusInc = (outerRadius - innerRadius) / I2R(CircleCount(data.level)-1)
        
        //see functions they call
        local integer fxcount = InnerCurcleUnits(data.level)
        local integer fxcountinc = InnerCurcleUnitsIncrease(data.level)
        
        local real phi = 0
        local real phiInc

        loop
            exitwhen (innerRadius + 0.001 >= outerRadius)

            set phi = 0
            set phiInc = 2*bj_PI/I2R(fxcount)
            
            loop
                exitwhen (phi + 0.001 >= 2 * bj_PI)
                //we add the units to a group, so we can kill them when we want ! =P
                call GroupAddUnit(data.dummyEffects, CreateUnit(forPlayer, DummyEffectId(data.level), x + innerRadius * Cos(phi), y + innerRadius * Sin(phi), 180 + Rad2Deg(phi)))
                set phi = phi + phiInc
            endloop
            
            set innerRadius = innerRadius + radiusInc
            set fxcount = fxcount + fxcountinc
        
        endloop
        
        set forPlayer = null
    
    endfunction
//===========================================================================
    //Function made by Vexorian, it selects a random region in a disk. 
    //All regions have the same chance of beeing choosen
    private function GetRandomPointInDisk takes real centerx, real centery, real minradius, real maxradius returns location
        local real d = SquareRoot(GetRandomReal(minradius * minradius, maxradius * maxradius))
        local real a = GetRandomReal(0, 2 * bj_PI)
        return Location(centerx + d * Cos(a), centery + d * Sin(a))
    endfunction
//===========================================================================
    private function createGolems takes nothing returns nothing
        //we get the structure from the timer
        local MyStruct data = MyStruct(GetTimerData(GetExpiredTimer())) 
        
        //variables for us to know where the golems will born
        local location point  
        local real randomX  
        local real randomY 
        
        //just to keep count about how many golems we created
        local integer loopCounter = 0
        
        //variables about the golems
        local unit golem
        local real golemFacing = GetUnitFacing(data.caster)
        
        //Here we spawn the golems 
        loop 
            exitwhen(loopCounter >= GolemsPerCycle(data.level))
                
            set point = GetRandomPointInDisk(data.spellLocX, data.spellLocY, MinRange(data.level), MaxRange(data.level))
            set randomX = GetLocationX(point)
            set randomY = GetLocationY(point)
            
            set golem = PlaceRandomUnit(GOLEM_POOLS[data.level], GetOwningPlayer(data.caster), randomX, randomY, golemFacing)
            call SetUnitAnimation( golem, ANIMATION )
            
            //if ChannelGolems(data.level) is true we add the golem to it 
            //so we can keep track of it and kill it later in the "onDestroy"
            //method
            //else if the variable is false, it means that the group was not
            //created, and we ant the units to have a LifeTime
            if (ChannelGolems(data.level)) then
                call GroupAddUnit(data.golems, golem)
            else
                call UnitApplyTimedLife(golem, 'BTLF', GolemLife(data.level))
            endif
            
            call RemoveLocation(point)
            set point = null
                
            set loopCounter = loopCounter + 1
        endloop
    
    set golem = null

    endfunction
//===========================================================================
    private function Conditions takes nothing returns boolean
        local MyStruct data
        local location spellLoc //the location of the spell
        
        if (GetSpellAbilityId() == AID) then
            //setting variables for the struct
            set spellLoc = GetSpellTargetLoc()
            set data = MyStruct.create(GetTriggerUnit(), GetLocationX(spellLoc), GetLocationY(spellLoc))
            
            //put the struct in the Table, we just use the caster's handle adress as 
            //the key which tells us where in the Table the struct is stored
            set activeTable[data.caster] = data 

            //  we add the casting unit to some sort of "pool"
            call GroupAddUnit(GolemInvocationCasters, data.caster)
            
            //now we create the dusty effect
            call createDust(data)
            
            //we attach the struct to the timer
            call SetTimerData(data.cycleTimer, integer(data))
            call TimerStart(data.cycleTimer, Cycle(data.level), true, function createGolems)
            
            //cleaning up the mess
            call RemoveLocation(spellLoc)
        endif
        
        set spellLoc = null
        
        return false
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        //these integers are counters for a loop and will be used later
        local integer i
        local integer j
        
        //here we set up the triggers we will need
        local trigger GolemInvocationTrigger = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(GolemInvocationTrigger, Condition( function Conditions ) )
        
        set GolemInvocationTrigger = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddCondition(GolemInvocationTrigger,  Condition(function onStop))

        set GolemInvocationTrigger = null
        
        //set our globals
        set activeTable = HandleTable.create() 
        set GolemInvocationCasters = CreateGroup() 

        //now we will Create UnitPools using loops and the
        //counters. 
        
        //we fill the arrays, so we can use them in the loop
        call GolemTypes()
        call GolemChances()
        
        set i = 0   //The outer counter
        set j = 0   //The inner counter
        
        //in the outer loop, we create an UnitPool for each level
        loop
            exitwhen(i > MAX_LEVELS)
            set GOLEM_POOLS[i] = CreateUnitPool()
            
            //this inner loop adds a unit to the units pool array and gives it a "weight".
            //"weights" are the chances a unit has to be choosen, the bigger the weight the 
            //chances you'll have to pick that unit
            set j = 0
            loop
                exitwhen(j > MAX_TYPES)
                call UnitPoolAddUnitType(GOLEM_POOLS[i], GOLEM_TYPES[MAX_TYPES * i + j], GOLEM_CHANCES[MAX_TYPES * i + j])
                set j = j + 1
            endloop
            
            set i = i + 1
        endloop
        
    endfunction
endscope 

This is one of the most complex spells I have ever made, I am proud of it and I can say I am very surprised with the outcome. The SETUP is in fact cleaner and, in my opinion, easier to use as well.

I hope now this can get approved. If you guys have more suggestions, than go ahead.
And yes, I know I don't like to use "CreateGroup()" and "DestroyGroup()" but let's face the fact it is a pretty easy way of doing things and it works (well, I was using NewGroup() and ReleaseGroup() but now I can't so I replaced them xD)

I hope this is ready, There is a chance I add another detail or something, but something small.

PS: Now I noticed I won't be able to enter with this spell into the Olympics because I use a dust imported model =(. Wac3 didn't had any, so I used one from Rising Dusk knoackback system.
No problem, I shall change this into a fire spell. Please continue to help !

EDIT EDIT EDIT

Ok guys, I am now trying to make dynamic arrays using vJASS, but I am kind of lost. Can some one please tell me if I am going in the right direction or if I need to fix something ?
Also, Why doesn't the code compile when I use [Golbal + 1] ??

Collapse JASS:
scope GolemInvocation initializer Init

    //Gloabls for the spell's core, don't change
    globals 
        private integer array GOLEM_TYPES   
        private real array GOLEM_CHANCES
        private unitpool array GOLEM_POOLS
    endglobals
    
//===========================================================================
//=============================SETUP START===================================
//===========================================================================

    globals
        private constant integer AID = 'A001'   //the rawcode of the ability
        private constant string ANIMATION = "birth" //the animation that will be played when the unit is created
        private constant integer MAX_TYPES = 3  //The maximum number of unit types of the spell
        private constant integer MAX_LEVELS = 3 //the maximum number of levels of the spell
    endglobals
    
    private type levels extends integer array[MAX_LEVELS + 1]   //compile error, wrong size definition !
    private type golem_types extends levels array[MAX_TYPES + 1]
    private type golem_chances extends levels array[MAX_TYPES + 1]
//===========================================================================
//============================GOLEM SETUP====================================
//===========================================================================
    
    private function GolemTypes2 takes nothing returns nothing
        local golem_types types = golem_types.create()
        
        //This is to prevent not innitialied arrays. 
        //It is also necessary for array indexing to work properly - don't change.
        set types[0] = levels.create()
        set types[0][0] = 0
        set types[0][1] = 0
        set types[0][2] = 0
        set types[0][3] = 0
        
        //for level 1
        set types[1] = levels.create()
        set types[1][0] = 0
        set types[1][1] = 'ngrk'
        set types[1][2] = 'ngst'
        set types[1][3] = 'nggr'
        
        //for level 2
        set types[2] = levels.create()
        set types[2][0] = 0
        set types[2][1] = 'ngrk'
        set types[2][2] = 'ngst'
        set types[2][3] = 'nggr'
        
        //for level 3
        set types[3] = levels.create()
        set types[3][0] = 0
        set types[3][1] = 'ngrk'
        set types[3][2] = 'ngst'
        set types[3][3] = 'nggr'
        
        
        //I am lost with the loops !
        //this is the example in vJASS documentation, can some one 
        //tell me if I did things correctly ?
        
//        type iar extends integer array[3]
//        type iar_ar extends iar array[3]
//        function test takes nothing returns arsample
//            local iar_ar r=iar_ar.create()
//            local integer i=0
//            local integer j
//            loop
//                exitwhen i==iar_ar.size //holds size of the array type
//                set r[i]=iar.create()
//                set j=0
//                loop
//                    exitwhen j==iar.size
//                    set r[i][j]=j*i
//                    set j=j+1
//                endloop
//
//            set i=i+1
//        endloop
//    return r
//    endfunction

    endfunction
    
    private function GolemTypes takes nothing returns nothing
        //This is to prevent not innitialied arrays. 
        //It is also necessary for array indexing to work properly - don't change.
        set GOLEM_TYPES[0] = 0 
        
        //this sets the golem types. In this case we have 3 golem types
        //for level 1, 2 and 3; and the Golem types that can be spawned for 
        //each level are equal.
        
        //for level 1
        set GOLEM_TYPES[MAX_TYPES * 1 + 1] = 'ngrk'
        set GOLEM_TYPES[MAX_TYPES * 1 + 2] = 'ngst'
        set GOLEM_TYPES[MAX_TYPES * 1 + 3] = 'nggr'
        
        //for level 2
        set GOLEM_TYPES[MAX_TYPES * 2 + 1] = 'ngrk'
        set GOLEM_TYPES[MAX_TYPES * 2 + 2] = 'ngst'
        set GOLEM_TYPES[MAX_TYPES * 2 + 3] = 'nggr'
        
        //for level 3
        set GOLEM_TYPES[MAX_TYPES * 3 + 1] = 'ngrk'
        set GOLEM_TYPES[MAX_TYPES * 3 + 2] = 'ngst'
        set GOLEM_TYPES[MAX_TYPES * 3 + 3] = 'nggr'
        
        //Note that the formula being used is:
        //MAX_TYPES * level + NumberOfGolemType
        //this simulates a 2D array for the Golem Types we can have
    endfunction
08-14-2008, 02:15 PM#13
Anitarf
Ok, here's the deal: I believe this will look a lot less messy if we just have a single one-dimensional array for golem types. "But how can we have different golems on different levels?" you ask? Easy, we just store all the golems from all the levels into the array and those who don't appear at level one simply get a 0% chance of spawning at that level. The spawn chances will thus still be a two dimensional array.

Collapse JASS:
    globals
        private constant integer MAX_TYPES=3
        private constant integer MAX_LEVELS=3
    endglobals

    private keyword golemType
    private keyword golemChance
    private function Calibrate takes nothing returns nothing
        set golemType[0]='ngrk'
        set golemType[1]='ngst'
        set golemType[2]='nggr'

        //level 1 chances
        set golemChance[1][0]=1.0
        set golemChance[1][1]=0.0
        set golemChance[1][2]=0.0
        //level 2 chances
        set golemChance[2][0]=0.75
        set golemChance[2][1]=0.25
        set golemChance[2][2]=0.0
        //level 3 chances
        set golemChance[3][0]=0.25
        set golemChance[3][1]=0.50
        set golemChance[3][2]=0.25
    endfunction

//end of calibration section

    private type chancePerType extends real array[MAX_TYPES]
    globals
        private integer array golemType
        private chancePerType array golemChance
    endglobals

    private function Init takes nothing returns nothing
        local integer i = 1 //we don't init index 0
        loop
            exitwhen i> MAX_LEVELS
            set golemChance[i]=chancePerType.create()
            set i = i+1
        endloop
        call Calibrate()
    endfunction
08-14-2008, 05:28 PM#14
Flame_Phoenix
Ok, here is another version. This one doesn't compile and I don't know why, but still I want to know if I am on the right path.

Collapse JASS:
scope GolemInvocation initializer Init

//Gloabls for the spell's core, don't change
    globals 
        private integer array golemType   
        private real array golemChances
        private unitpool array GOLEM_POOLS
    endglobals
//===========================================================================
//=============================SETUP START===================================
//===========================================================================

    globals
        private constant integer AID = 'A001'   //the rawcode of the ability
        private constant string ANIMATION = "birth" //the animation that will be played when the unit is created
        private constant integer MAX_TYPES = 3  //The maximum number of unit types of the spell
        private constant integer MAX_LEVELS = 3 //the maximum number of levels of the spell
    endglobals
    
//    private keyword golemType
//    private keyword golemChance
    
    private type chancesPerType extends real array[MAX_TYPES]
//===========================================================================
//============================GOLEM SETUP====================================
//===========================================================================
    
    private function Calibrate takes nothing returns nothing
        set golemType[0] = 'ngrk'
        set golemType[1] = 'ngst'
        set golemType[2] = 'nggr'
        
        //level 1 chances
        set golemChances[1][0] = 0.5    //syntax error !!
        set golemChances[1][1] = 0.3    //syntax error !!
        set golemChances[1][2] = 0.2    //syntax error !!
        
        //level 2 chances
        set golemChances[2][0] = 0.4    //syntax error !!
        set golemChances[2][1] = 0.4    //you get the point...
        set golemChances[2][2] = 0.2
        
        //level 3 chances
        set golemChances[3][0] = 0.4
        set golemChances[3][1] = 0.3
        set golemChances[3][2] = 0.3
    endfunction
    
    private constant function GolemLife takes integer level returns real
        //the amount of time each golem will have, if ChannelGolems() is false
        return level * 20.  
    endfunction

    private constant function ChannelGolems takes integer level returns boolean
        //if true it will make all spawned golems die when the caster stops the channel
        //if false, it allows the golems to have GolemLife() seconds of life and they
        //will not die when the caster stops the channel
        //in this case my golems 20, 40 and 60 seconds of life for each level.
        return false
        
        //example of usage

//        if (level == 3) then
//            return false
//        endif
//        return true

        //in this example the golems will die when the channel ends in level 1 and 2
        //in level 3, the golems will live 60 seconds of life
    endfunction
    
    private constant function GolemsPerCycle takes integer level returns integer
        //the number of golems that will be created each cycle
        return 1 + (level * 0)
    endfunction
    
    private constant function Cycle takes integer level returns real
        //the cycle which will determine when we create golems
        //this means, GolemsPerCycle() golems are created every cycle
        //in this case, we create 1 golem per second (in this case a second 
        //is a cycle)
        return 1. + (level * 0) 
    endfunction

//INSIDE THE INIT FUNCION

//now we will Create UnitPools using loops and the counters. 
        set i = 1   //The outer counter
        
        //in the outer loop, we create an UnitPool for each level
        loop
            exitwhen(i > MAX_LEVELS)
            set golemChances[i] = chancesPerType.create()
            set GOLEM_POOLS[i] = CreateUnitPool()
            set i = i + 1
        endloop
        
        call Calibrate()
        
        set i = 0
        loop
            exitwhen( i > MAX_TYPES)
            call UnitPoolAddUnitType(GOLEM_POOLS[i + 1], golemType[i], golemChances[i])
            set i = i + 1
        endloop

Any tips ?
08-14-2008, 05:51 PM#15
Themerion
Collapse JASS:
        set golemChances[1][0] = 0.5    //syntax error !!
        set golemChances[1][1] = 0.3    //syntax error !!
        set golemChances[1][2] = 0.2    //syntax error !!
        
        //level 2 chances
        set golemChances[2][0] = 0.4    //syntax error !!
        set golemChances[2][1] = 0.4    //you get the point...
        set golemChances[2][2] = 0.2
        
        //level 3 chances
        set golemChances[3][0] = 0.4
        set golemChances[3][1] = 0.3
        set golemChances[3][2] = 0.3

As mentioned above, [][] won't "compile" in JASS. Let's try again to explain what Pyro meant :P

This array would look like this:

The Array:
( [1][0] ) ( [1][1] ) ( [1][2] )
( [2][0] ) ( [2][1] ) ( [2][2] )
( [3][0] ) ( [3][1] ) ( [3][2] )

However, what Java would do in this case is to actually transform this into a single dimension array:

The Array (1 index):
( [0] ) ( [1] ) ( [2] )
( [3] ) ( [4] ) ( [5] )
( [6] ) ( [7] ) ( [8] )

Thus, the index [X][Y] becomes [X*3 + Y]
( well, mabye (X-1)*3 instead of X)