Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: bx83 on Sat 17/07/2021 04:57:06

Title: game_start not working in room 52
Post by: bx83 on Sat 17/07/2021 04:57:06
I have a script (header/code) for my little Tankman module. In room52, where I have the graphics for the game, I have a game_start() function.
In game_start(), I've put all the initialisation code, and the code for 'theGrid', an array which represents my game-map:

Tankman.ash
Tile *theGrid[];    //dynamic array of pointers

Room52.asc
function game_start()
{
...
theGrid=new Tile[numRows*numCols];  //define it as a new Tile array of size rows*colums
Display("rgarghath");
SetupGridValues();    <------Display output for testing, sets up grid values now it's been properly instantiated
GetTargetRed();   <----- function than generates Display output
}


Nothing displays output, nothing runs.
If I put SetupGridValues() in room_Load(), it runs it, and then says theGrid is a null pointer (obviously never instantiated).

I would've thought that game_start() would be the first and foremost thing to run?

How and where do I run 'theGrid=new Tile[numRows*numCols];' to set it as a global variable (within game/room52), then run all 'setup' code, and then just get to the actual game-loop in room_RepExec()?
Title: Re: game_start not working in room 52
Post by: Crimson Wizard on Sat 17/07/2021 04:59:31
game_start is not run in the room scripts, because no room is loaded at the game start yet.

You may only have these in script modules, but not in room scripts.

Quote from: bx83 on Sat 17/07/2021 04:57:06
How and where do I run 'theGrid=new Tile[numRows*numCols];' to set it as a global variable (within game/room52), then run all 'setup' code, and then just get to the actual game-loop in room_RepExec()?

room_Load ("room before fade-in") event is meant for setting a room up, have you tried putting everything there?
Title: Re: game_start not working in room 52
Post by: bx83 on Sat 17/07/2021 05:17:03
Okay, that explains that.
Now I've got:

Room52.asc:
function room_Load()
{
...

  theGrid=new Tile[numRows*numCols];  //define it as a new Tile array of size rows*colums
  Display("%d %d",numRows, numCols);
  theGrid[0].x=25;   theGrid[0].y=25;    theGrid[0].up=0;  theGrid[0].right=1;  theGrid[0].down=1;  theGrid[0].left=0;  theGrid[0].content=0;
  theGrid[1].x=75;   theGrid[1].y=25;    theGrid[1].up=0;  theGrid[1].right=1;  theGrid[1].down=0;  theGrid[1].left=1;  theGrid[1].content=0;
  theGrid[2].x=125;  theGrid[2].y=25;    theGrid[2].up=1;  theGrid[2].right=1;  theGrid[2].down=0;  theGrid[2].left=1;  theGrid[2].content=0;
 
 
  Display("rgarghath");
  SetupGridValues();
  GetTargetRed();


It displays:
8 10
'Runtime error: null pointer referenced'

The first line, theGrid[0].x=25, etc etc is the null pointer. So instantiation is right, but then 'theGrid' drops from memory. Or something. :/
Title: Re: game_start not working in room 52
Post by: Crimson Wizard on Sat 17/07/2021 05:39:20
Quote from: bx83 on Sat 17/07/2021 05:17:03
It displays:
8 10
'Runtime error: null pointer referenced'

Well, that's weird. May you try printing theGrid value as well?
Code (ags) Select

Display("%p %d %d", theGrid, numRows, numCols);


How and where is theGrid declared?

EDIT: oh I see in your first post:
Quote
Tankman.ash

Code (ags) Select
Tile *theGrid[];    //dynamic array of pointers

This is a wrong thing to put into a header. The variables should be put in the script body, and headers should have import declarations.
https://adventuregamestudio.github.io/ags-manual/TheScriptHeader.html
https://adventuregamestudio.github.io/ags-manual/ImportingFunctionsAndVariables.html
Title: Re: game_start not working in room 52
Post by: bx83 on Sat 17/07/2021 05:54:00
Tankman.ash
// new module header
struct __Tankman
{
  import function Enable();
  import function Disable();
};
import __Tankman Tankman;


#define numRows     8
#define numCols     10
#define tankLoop  314

managed struct Tile {
  int x;  //x centre of tile
  int y;  //y centre of tile
  bool up;      //has up direction
  bool right;   //has right direction
  bool down;    //has down direction
  bool left;    //has left direction
  int content;  //is it a free tile or blocked space?
};

#define numCrowds   4


managed struct Crowd {
  int aX;     //actual x eg. 312
  int aY;     //actual y eg. 472
  int tX;     //target x - x centre of target tile
  int tY;     //target y - y centre of target tile
 
  int mode;   //mode, 0=chase, attack=1, scatter=2, scared=3, regen=4
 
  int timer1; //timer to stay in mode
  int timer2; //timer to stay aggressive
  int waittimer;  //timer for wait between attacks/cooldown time
  int timercontrol; //a timer is on=1/off=0
 
  int dir;    //0=up, 1=right, 2=down, 3=left  Never Eat Soggy Wheatbix
  int nogo;   //opposite direction to where your pointed; dir/nogo 0/2 1/3 2/0 3/1
  int moving; //1=moving to next coord, 0=not moving, decision/action time
  bool attack;  //are they programmed to be aggressive? 0-no 1-yes
  int id;     //object ID, leads to control of object loop/position
  bool dead;  //0=alive, 1=dead
 
  import void ResetTimers(Crowd *crowd);
  import void FindTargetBasedOnMode(Crowd *crowd, int mode);
  import void MoveCrowdToTarget(Crowd *crowd);
  import int CleanUpDeadCrowd(Crowd *crowd);
};

managed struct TM {
  int tileX;  //tm's current tile
  int tileY;
  int dir;  //tm's current dir
  int nogo; //diametric opposite to dir
  int mode;
  int id;   //object id
};

import int SetNogo(int dir);
import int DirToLoop(int dir);
import int LoopToDir(int loop);
import Tile* GetTile(int x=-1, int y=-1);


Tankman.asc
__Tankman Tankman;
export Tankman;

bool gEnabled = false;
export gEnabled;


function __Tankman::Enable()
{
  gEnabled = true;
}

function __Tankman::Disable()
{
  gEnabled = false;
}


Tile *theGrid[];    //dynamic array of pointers
Crowd* rabble[4];    //4 crowds: red, yellow, green, purple
TM* TMan;

...


Room52
...

function room_Load()
{
  Tankman.Enable();
 
  gIconbar.Visible=false;

  oTM.Baseline=768;
 
 
  cJulius.x=2000;   //the main character of the game; he's here, but off-screen
  cJulius.y=2000;
 
  AG_playing=true;
  AG_gameover=false;
 
  newdirection=eKeyboardMovement_Up;

  //set crowd views
  oC0.SetView(330); //red
  oC1.SetView(332); //yellow
  oC2.SetView(331); //green
  oC3.SetView(329); //purple
  oTM.SetView(314); //tankman
 
 
 
  theGrid=new Tile[numRows*numCols];  <------ Error: Undefined token 'theGrid'



EDIT: added these to the bottom of Tankman.ash:

import Tile *theGrid[];
import Crowd* rabble[4];    //4 crowds: red, yellow, green, purple
import TM* TMan;


Gets through compile, but then has a runtime error on startup in room52:

Error: unable to create local script: Runtime error: unresolved import 'theGrid'
Title: Re: game_start not working in room 52
Post by: Crimson Wizard on Sat 17/07/2021 05:59:01
Quote from: bx83 on Sat 17/07/2021 05:54:00

  theGrid=new Tile[numRows*numCols];  <------ Error: Undefined token 'theGrid'

[/code]

Well, you need to declare an import for this variable.

https://adventuregamestudio.github.io/ags-manual/ImportingFunctionsAndVariables.html

In the script body:
Code (ags) Select

Tile *theGrid[];    //dynamic array of pointers
...
export theGrid;


In the script header:
Code (ags) Select

import Tile *theGrid[];
Title: Re: game_start not working in room 52
Post by: bx83 on Sat 17/07/2021 06:06:47
Alrighty, that worked, exports were the missing piece (which I... should have remembered. I need lunch).

Now, it gets back in room 52 to:

function room_Load()
{
  Tankman.Enable();
 
gIconbar.Visible=false;

  oTM.Baseline=768;
 
 
  cJulius.x=2000;   //the main character of the game; he's here, but off-screen
  cJulius.y=2000;
 
  AG_playing=true;
  AG_gameover=false;
 
  newdirection=eKeyboardMovement_Up;

  //set crowd views
  oC0.SetView(330); //red
  oC1.SetView(332); //yellow
  oC2.SetView(331); //green
  oC3.SetView(329); //purple
  oTM.SetView(314); //tankman
 
 
 
  theGrid=new Tile[numRows*numCols];  //define it as a new Tile array of size rows*colums
 
  Display("%p %d %d",theGrid, numRows, numCols);    <---------displays "<8 random hex characters> 8 10"
  theGrid[0].x=25;              <---------------------------------Error: null pointer referenced, PROGRAM STOPS HERE
  Display("%p %d %d",theGrid, numRows, numCols);
 
  Display("rgarghath");
  SetupGridValues();
  GetTargetRed();
Title: Re: game_start not working in room 52
Post by: Crimson Wizard on Sat 17/07/2021 06:10:11
Ah, I got it.

"theGrid" is an array of Tiles, but Tile is a managed struct, so each tile should also be created.

It's not theGrid which is the null pointer, it's theGrid[0] which is a null pointer.

So you have to do this:

Code (ags) Select

int size = numRows*numCols;
theGrid=new Tile[size ];
for (int i = 0; i < size; i++)
    theGrid[i] = new Tile;
Title: Re: game_start not working in room 52
Post by: bx83 on Sat 17/07/2021 07:02:16
It all works now, thank you :)

....except TMan. As usual I will try all combinations of definition before complaining.

*does this over 20 minutes*

Okay, I'm out of ideas.

Tankman.ash
...
import Tile *theGrid[];
import Crowd* rabble[numCrowds];    //4 crowds: red, yellow, green, purple
import TM* TMan;


Tankman.asc
__Tankman Tankman;
export Tankman;

bool gEnabled = false;
export gEnabled;


function __Tankman::Enable()
{
  gEnabled = true;
}

function __Tankman::Disable()
{
  gEnabled = false;
}


Tile *theGrid[];    //dynamic array of pointers
Crowd* rabble[4];    //4 crowds: red, yellow, green, purple
TM* TMan;
export theGrid;
export rabble;
export TMan;
...


Room52.asc
function room_Load()
{
  Tankman.Enable();
 
  gIconbar.Visible=false;

  oTM.Baseline=768;
 
 
  cJulius.x=2000;   //the main character of the game; he's here, but off-screen
  cJulius.y=2000;
 
  AG_playing=true;
  AG_gameover=false;
 
  newdirection=eKeyboardMovement_Up;

  //set crowd views
  oC0.SetView(330); //red
  oC1.SetView(332); //yellow
  oC2.SetView(331); //green
  oC3.SetView(329); //purple
  oTM.SetView(314); //tankman
 
 
  //fill out theGrid with Tile objects
  int size = numRows*numCols;
 
  theGrid=new Tile[size]; //instantiate theGrid
  for (int i = 0; i < size; i++) {
    theGrid[i] = new Tile;
  }
  SetupGridValues();
 
  for (int j=0; j<numCrowds;j++) {
    rabble[j]=new Crowd;
  }
 
  //now, setup crowds:
 
  ///////////
  // 0 RED //
  ///////////
  rabble[0].mode=Random(1);       //chase or scatter
 
  //get random start tile
  Tile *rt0 = GetTile();
  rabble[0].aX=rt0.x;

....

else if (rt3.left==1)  rabble[3].dir=3;
 
  //set nogo based on dir
  rabble[3].nogo=SetNogo(rabble[3].dir);
 

  //setup tankman:
 
  /////////////
  // Tankman //
  /////////////
 
 
  TMan.tileX=6;  <----NULL POINTER REFERENCED


so you know :(
TMan is still not acting as a nice global.
Title: Re: game_start not working in room 52
Post by: Crimson Wizard on Sat 17/07/2021 07:05:30
Well, it's the exactly same reason, you have a "TM* TMan;" which is a pointer, but do you create the actual object anywhere with "new"?
Title: Re: game_start not working in room 52
Post by: bx83 on Sat 17/07/2021 07:20:57
...

//fill out theGrid with Tile objects
  int size = numRows*numCols;
 
  theGrid=new Tile[size]; //instantiate theGrid
  for (int i = 0; i < size; i++) {
    theGrid[i] = new Tile;
  }
  SetupGridValues();
 
  for (int j=0; j<numCrowds;j++) {
    rabble[j]=new Crowd;
  }

  TMan=new TM;



...and it works :P
Title: Re: game_start not working in room 52
Post by: Cassiebsg on Sat 17/07/2021 09:19:54
OT: You can make your code look like AGS code in your posts, instead of [ code ] use [ code=ags ] (without the spaces).  ;)