[SOLVED] How to ChangeRoom in a loop without hanging AGS ?

Started by js, Wed 04/01/2023 09:32:16

Previous topic - Next topic

js

Hello,

In debug build, i'd like to gather objects in all the room to check some relations between them, in their custom properties.

As objects are linked to rooms, i have made a shortcut key which start the check in the AGS game loop. The check changes room, gather objects and repeat until last room is reached.

At game startup, i fill the array (liste_room[]) with all the rooms index (when there are no more rooms, i put -1 as a value to indicate it's over).

Then, the keyboard shortcut initializes ask_for_objects_testing boolean to true.

And in the function repeatedly_execute() , i've put

Code: ags
  if (ask_for_objects_testing == true) {
    int initial_room = player.Room;
    for (int i=0; liste_room[i]>=0; i++) {
      log(String.Format("parsing room: %d", liste_room[i]));
      player.ChangeRoom(liste_room[i]);
    }
    // go back to initial room
    player.ChangeRoom(initial_room);
  }

But it hangs at the second call of player.ChangeRoom

I get this error:

NewRoom : Cannot run this command since there was a NewRoom command already queued to run in "GlobalScript.asc

So i think it's related a re-entrance issue in the internal loop of AGS, but i don't know how to handle this.

Thank you.

Matti

I think you can't accomplish this with a blocking/looping function.

Quote from the manual:
QuoteFor player character this command does not change the room immediately; instead, it will schedule the room change, and perform it only once your script function has finished (This is to avoid problems with unloading the script while it is still running). This means that you should not use any other commands which rely on the new room (object positionings, and so on) after this command within the same function.

What you could do is something like this (in the global script's repeatedly execute function):

Code: ags
// call these lines once after the key combination was pressed:    
    ask_for_objects_testing == true
    int initial_room = player.Room; 
    i = 0;

  if (ask_for_objects_testing == true) {
    if (liste_room[i]>=0)
    {  
      i++;
      log(String.Format("parsing room: %d", liste_room[i]));
      player.ChangeRoom(liste_room[i]);
    }
    // go back to initial room
    else 
    {
      ask_for_objects_testing = false;
      player.ChangeRoom(initial_room);
    }
  }

Not sure if this really works, it's untested and off the top of my head.

Khris

A player.ChangeRoom() call gets queued and only runs after the current function finishes. You need to change the entire approach.

You need to
1. move any loop variables outside the function so they retain their value
2. use a function that gets called each time the player enters a room

Like this:
Code: ags
int i = 0;

function on_event(EventType event, int data) {
  if (event == eEventEnterRoomBeforeFadein) {
    // do stuff inside the current room
    // ...
    // finally, schedule room change
    if (i < ARRAY_SIZE && liste_room[i] > 0) {
      player.ChangeRoom(liste_room[i]);
      i++;
    }
  }
}

js

Thank you ! After a bit of experimentations, i finally manage this with your help.

The « challenge » for me was to returrn to the start room at the end, without cluttering event loop with tests and variables (like it_is_the_last_room_now_return).

Finally, i just added the start room at the end of the list, before the ending number
I'm doing this at game startup:

Code: ags
  int index_room = 0;
  int initial_room = player.Room;
  for (int i = 0; i < MAX_ROOM; i++) {
    if (Room.Exists(i))
    {
      /* Note: si cette boucle trouve des pièces qui n'existent pas ou plus, vérifier que
               le fichier CRM correspondant ne traine pas dans les fichiers du jeu.
               Ce problème ne concerne à priori que l'exécution directe avec F5 (pas l'exec avec le moteur).
               Ex: trouve un index de room 10, qui n'existe plus dans l'éditeur : effacer le fichier room10.crm
      */
      log(String.Format("room: %d exists", i));
      liste_room[index_room]=i;
      index_room = index_room+1;
    }
  } // i < MAX_ROOM ?
  liste_room[index_room] = initial_room; // retourne sur la première pièce
  index_room++;
  liste_room[index_room] = -1; // indique la dernière pièce
  index_parcours_room=index_room; // se place sur la dernière pièce
  log(String.Format("max rooms : %d", index_room));
 

SMF spam blocked by CleanTalk