• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[vJASS] arrays within struct array; override?

Status
Not open for further replies.
Level 3
Joined
Jan 7, 2010
Messages
37
Edit: no longer necessary; got around that error (though, didn't solve it.)
//--------------------------------------------------------------------------

*full trigger at the bottom*
I have problems with arrays within struct arrays; somehow I override data in one array, when cleaning up another...

I'm working on a FF like battle zone and want store all creep data of an "enemy wave" in an struct, which itself is an struct array.

I want to spawn up to 5 units, store them in an struct array "EnemyWaves[]" of struct "EnemyData". Within that struct I have several arrays that
keep track of all the data for every unit within that wave.

So, I want to spawn the first wave: EnemyWaves[0], that contains 1 unit of type A; after that wave, I want to remove that wave EnemyWaves[0] and spawn the next wave EnemyWaves[1], which contains 1 unit of Type A and 2 units of Type B; ...

Now the problem is: when setting up or removing a wave, somehow the data gets overriden, and I have no idea what I'm doing wrong.

Through testing I always get down to these functions: "SetupWave", "SpawnNextWave" and the method ".reset"; but I can't figure it out.

JASS:
function SetupWave takes integer whatWave, integer creepId, integer Min, integer Max returns nothing
    local integer amount
    local integer i = 0
    local integer max
    local integer min
    local integer rand
		...
        // fills the array with the creepUnitTypeId, starting at the next empty slot.
        set rand = GetRandomInt(min,max)
        set amount = rand + EnemyWaves[whatWave].currentCreepSlot
        set i = EnemyWaves[whatWave].currentCreepSlot
        loop
            exitwhen i >= amount
            exitwhen i > I          // can't get bigger than 'I' itself.
                set EnemyWaves[whatWave].creepTypeId[i] = creepId
            set i = i + 1
        endloop
        set EnemyWaves[whatWave].currentCreepSlot = i
        ...
    endfunction
JASS:
function SpawnNextWave takes nothing returns nothing
    local integer i = 0

        // clear up the wave that came before! (doesn't run on first wave).
        if currentWave >= 0 then
            //call EnemyWaves[currentWave].reset()        //<<<<<<<<<<<<<<<<<<<<<< problem?
            set iWavesRemaining = iWavesRemaining - 1
        endif
        set currentWave = currentWave + 1

        // creates units.
        set i = 0
        loop
            exitwhen i >= EnemyWaves[currentWave].currentCreepSlot
            exitwhen i >= EnemyWaves[currentWave].waveMaxUnits
            //exitwhen EnemyWaves[currentWave].creepTypeId[i] == 0
                call CreateCreep(EnemyWaves[currentWave].creepTypeId[i])
            set i = i + 1
        endloop
    endfunction
JASS:
        method reset takes nothing returns nothing
        local integer i = 0
            loop
                exitwhen i > I
                    call .destroyCreep(i)
                    set .creepTypeId[i] = 0//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< problem?????
                set i = i + 1
            endloop
            set .currentCreepSlot = 0
            set .waveMaxUnits = 1
            set iEnemiesAlive = 0
        endmethod


This is the enemy setup that I'm calling
JASS:
    call SetupWave(0, 'c001', 1, 1)
    //call SetWaveMaxUnits(0,1)
    
    call SetupWave(1, 'c000', 1, 1)
    call SetupWave(1, 'c001', 2, 2)
    call SetWaveMaxUnits(1,5)
    
    call SetupWave(2, 'c001', 5, 5)
    
    call SetupWave(3, 'c000', 1, 1)
So it should come up:
First wave, 1 unit of type c001
Second wave, 1 unit of type c000, 2 units of type c001, 5 units max (there will be only 3 though)
Third wave, 5 units of type c001
Fourth wave, 1 unit of type c000

But what happens is:
First wave, 1 unit of type c001 (works)
Second wave, 2 units of type c001 (doesn't work); the first unit ".creepTypeId[0]" gets overriden/set to 0 in the ".reset" call of the PREVIOUS wave! so a unit is spawned of UnitType "0"

Now I leave out the ".reset" call and this happens:
First wave, works
Second wave, works
Third wave, doesn't work; instead of 5 units of type c001 there are 4 of c001 and 1 of c000
Fourth wave, works

Another weird thing (picture below):
-The picture on the left shows the unitType for every unit; the units slot within its wave; and the wave itself => this is all correct
-Now in the center picture there is the output of all the creepTypeIds of the second wave (EnemyWaves[1]); in the green box are the 3 units that will be spawned (which is correct), the "0" underneath would be the fourth unit (but I only set up 3 units; so this is correct, too). But the number underneath, the fifth unit, should be 0 as well! But it isn't. And I've never set it up. And I couldn't figure out where it does get setup.
-The picture on the right shows again the creepTypeId of the second wave; I gave out the creepId before the ".reset" call of the previous wave, and after. After the previous wave(&unit) gets destroyed, the first unit of the second wave gets also reset!
i dont get it wc3.png


JASS:
/***************************************************************
*   creates, spawns && handles enemies and enemy groups!
***************************************************************/
library EnemySystem initializer Init requires UnitDataList, FadeInFadeOut

    globals
        private constant real FACING = 270. // 
        private constant real X = -15000    // an empty spot to spawn units.
        private constant real Y = -15000    // an empty spot to spawn units.
        //-----------------------------
        private constant integer I = 4      // the maximum number (starting to count at 0) of enemies on the field.
    endglobals
    
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-    
    
    struct EnemyData// Enemy as a whole, not as a single creep.
        CreepData array creepData[I]        // keeps track of the invidiual CreepData.
		TempoData array tempoData[I]		// keeps track of the individual tempodata for this Creep.
        unit array  creeps[I]               // stores the actual creeps within this wave.
        integer array creepTypeId[I]        // stores the creepTypeId of the creep to be spawned.
        integer currentCreepSlot = 0        // used for setting up creeps
        integer waveMaxUnits = 1            // max units per wave.
        
        method createUnit takes integer uId, integer i returns nothing
            set .creepData[i] = createCreep(uId,X,Y,FACING)
			set .tempoData[i] = createTempoData(.creepData[i].Unit)
            set .creeps[i] = .creepData[i].Unit
	
            set iEnemiesAlive = iEnemiesAlive + 1   // global call, header.
        endmethod
		
        method createUnitFadeIn takes integer uId, integer i returns nothing
        local Fade f
            call .createUnit(uId, i)
            set f = Fade.create(true, .creepData[i].Unit)
        endmethod     	

		method destroyCreep takes integer i returns nothing
			//call killTempoData(this.tempoData[i])
            call killTempoDataUnit(.creeps[i])
            if CheckUnitIsAlive(.creeps[i]) then
                set iEnemiesAlive = iEnemiesAlive - 1
            endif
			call .creepData[i].destroy()
            set .creeps[i] = null
            set .tempoData[i] = -1              
            set .creepData[i] = -1
		endmethod        
        
        method reset takes nothing returns nothing
        local integer i = 0
            loop
                exitwhen i > I
                    call .destroyCreep(i)
                    set .creepTypeId[i] = 0//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< problem?????
                set i = i + 1
            endloop
            set .currentCreepSlot = 0
            set .waveMaxUnits = 1
            set iEnemiesAlive = 0
        endmethod
        
        method onDestroy takes nothing returns nothing
            call .reset()
        endmethod
    endstruct
    
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-    
    
    globals
        EnemyData array     EnemyWaves  // all waves to come are stored in here in chronological order
        private integer     iWavesAmount = 0
        integer             iWavesRemaining = 0 // keeps track of how many to come
        private integer     currentWave = -1
    endglobals
    
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
    
	private function getFreeSlot takes nothing returns integer
			/**
				we first check if ANY slot is free;
				if there is none we run again and check if ANY
				unit is dead! if so: we will remove that
				unit and replace it with the new one!
            **/
	local integer i = 0
		loop
			exitwhen i > 4
				if EnemyWaves[currentWave].creeps[i] == null then
					return i
				endif
			set i = i + 1
		endloop
		set i = 0
		loop
			exitwhen i > 4
				if not CheckUnitIsAlive(EnemyWaves[currentWave].creeps[i]) then
					call EnemyWaves[currentWave].destroyCreep(i)
					return i
				endif
			set i = i + 1
		endloop
		return 5	//0 is lowest, 4 is highest; 5 is "null" or "false".
	endfunction    
    
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
    
    function CreateCreep takes integer uId returns unit
	local real x
	local real y
    local integer i
    local unit u
        //  we first check if there is a free slot on the battle field.
		set i = getFreeSlot()
		if i >= 0 and i <= 4 then
			set x = GetLocationX(EnemyFormationSetup[CurrentFormation].location[i])
			set y = GetLocationY(EnemyFormationSetup[CurrentFormation].location[i])		
            // create unit and setup position.
			call EnemyWaves[currentWave].createUnitFadeIn(uId, i)
            set u = EnemyWaves[currentWave].creeps[i]
			call SetUnitPosition(u, x, y)
			set BLocDefaultX[GetUnitId(u)] = GetUnitX(u)
			set BLocDefaultY[GetUnitId(u)] = GetUnitY(u)	
            //  outside reference.
			set TempoSystem_tempoDataEnemy[i].owningUnit    = u
			set TempoSystem_tempoDataEnemy[i].owningUnitId  = GetUnitId(u)
            //  Yarr!! Harr!!
			call SetUnitAnimation(u, "stand ready")
            //-----------------
            set u = null
            return u
		endif
        //-----------------
        set u = null
        return null
    endfunction   
    
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
    
    function SetWaveMaxUnits takes integer whatWave, integer max returns nothing
        set EnemyWaves[whatWave].waveMaxUnits = max
    endfunction
    
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
    
    function SetupWave takes integer whatWave, integer creepId, integer Min, integer Max returns nothing
    local EnemyData ed = EnemyWaves[whatWave]
    local integer amount
    local integer i = 0
    local integer max
    local integer min
    local integer rand
        // makes sure the input values are within boundaries.
        if Max > 5 then
            set max = 5
        else 
            set max = Max
        endif
        if Min < 0 then
            set min = 0
        else
            set min = Min
        endif

        // fills the array with the creepUnitTypeId, starting at the next empty slot.
        set rand = GetRandomInt(min,max)
        set amount = rand + EnemyWaves[whatWave].currentCreepSlot
        set i = EnemyWaves[whatWave].currentCreepSlot
        loop
            exitwhen i >= amount
            exitwhen i > I          // can't get bigger than 'I' itself.
                set EnemyWaves[whatWave].creepTypeId[i] = creepId		// ???????????????????????????????????????????????????????
            set i = i + 1
        endloop
        set EnemyWaves[whatWave].currentCreepSlot = i
        
        // sets the number of max units automatically.
        // can be set manually, too (SetWaveMaxUnits).
        if rand > EnemyWaves[whatWave].waveMaxUnits then
            set EnemyWaves[whatWave].waveMaxUnits = rand
            if rand > 5 then
                set EnemyWaves[whatWave].waveMaxUnits = 5
            endif
        endif
        
        // sets the number of maximum waves to come.
        if iWavesAmount < whatWave then
            set iWavesAmount = whatWave
            set iWavesRemaining = whatWave
        endif
    endfunction
    
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
    
    function CleanUpWaves takes nothing returns nothing
    local integer i = 0
        loop
            exitwhen i > 99
                call EnemyWaves[i].reset()
            set i = i + 1
        endloop
        set iWavesAmount = 0
        set iWavesRemaining = 0
        set currentWave = -1
    endfunction
    
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
    
    function SpawnNextWave takes nothing returns nothing
    local integer i = 0

        // clear up the wave that came before! (doesn't run on first wave).
        if currentWave >= 0 then
            call EnemyWaves[currentWave].reset()        //<<<<<<<<<<<<<<<<<<<<<< problem?
            set iWavesRemaining = iWavesRemaining - 1
        endif
        set currentWave = currentWave + 1

        // creates units.
        set i = 0
        loop
            exitwhen i >= EnemyWaves[currentWave].currentCreepSlot
            exitwhen i >= EnemyWaves[currentWave].waveMaxUnits
            //exitwhen EnemyWaves[currentWave].creepTypeId[i] == 0
                call CreateCreep(EnemyWaves[currentWave].creepTypeId[i])
            set i = i + 1
        endloop
    endfunction    
    
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    private function Init takes nothing returns nothing        
    local integer i = 0
    local integer j = 0
        loop
            exitwhen i > 99
                set EnemyWaves[i] = EnemyData.create()
                set j = 0
                loop
                    exitwhen j > I
                        set EnemyWaves[i].creepTypeId[j] = 0
                    set j = j + 1
                endloop
            set i = i + 1
        endloop
    endfunction
endlibrary
 
Last edited:
I haven't read everything here, but there's a thing you need to remember when using struct arrays:

Each arrayed member of a struct array is limited in its amount of instances as the maximum array size is 8190.


This practically means that when you got 90 arrayed structs, each array member inside the struct can only hold up to 90 values (90x90 = 8100).

What you can do to avoid this problem is using hashtables, which are unlimited.
 
Status
Not open for further replies.
Top