RestartGame problem (FIXED)

Started by hedgefield, Sun 29/01/2006 18:41:24

Previous topic - Next topic

hedgefield

I'm having a bit of a problem getting the restartgame(); function to work properly...

When I restart the game, the code in '(first time) player enters screen' doesn't run again. So, I figured, I have to reset the rooms. Makes sense right? I found out you can't reset the room you are IN, so I made a new room where the player would go when they restart the game. And in there, the game resets every room, and THEN restarts the game. Alas, that didn't work either.

So now I'm out of ideas. You guys have any?


*I run 2.6, just so you know...

DoorKnobHandle

Dirty hack: Save the game at the beginning to some saveslot that isn't used by regular saving and then restore that savegame when you want to restore.

This way everything should be really restored.

hedgefield

#2
Unfortunately that doesn't work either. Maybe it's just the complexity of the code.

For instance, I start in room 0, play some music, change a background frame, then go to room 1, move the player character around, make him talk a bit, do some stuff, you know.

Then I hit restartgame, and it goes to room 1, ignoring the intro and any cutscene-ish stuff from room 1.

So I tried your way, and made the game save before fade in in room 0. Then, when I 'restart' after I've played a bit, it does go back to room 0, but doesn't play music, and keeps looping the two background frames forever. And 0 doesnt use the 'first time player enters screen' option at all.

Gilbert

Another way, is not to use the "player enters room for the first time" event. Instead, use "(after fade-in)" or any other event which was not "for the first time" according to your need.
For those rooms, just add on top of room script:
int firsttimerun=0;

Then in the "(after fade-in)" script add:
if (firsttimerun==0){
  \\put whatever you want to happen here
  firsttimerun=1;
}


This is not tested, but I hope it may work as a workaround. (provided that RestartGame() can reset those variables back to 0)

Scorpiorus

The thing is, the RestartGame() function works exactly the same way by loading a temporary saved game that's saved when you run the game (agssave.999). The problem, however, is that it doesn't save it immediately, but rather after a second call (or so) into room's repeatedly execute.

A workaround would probably be to have a dummy room (with a black foreground GUI?) that's loaded at game start. It must have a single repeatedly execute interaction with the following script:

// at the top of a dummy room script

int counter = 0;


// repeatedly execute

function room_*() {
// script for Room: Repeatedly execute

   if (counter < 2) // "< 1" may possibly also work
   {
      counter++;
   }
   else
   {
      player.ChangeRoom(0); // goto the INTRO room
   }

}


RestartGame() should reset it correctly after that.
So see whether it works that way.

strazer

Quote from: Scorpiorus on Thu 02/02/2006 16:32:13The problem, however, is that it doesn't save it immediately, but rather after a second call (or so) into room's repeatedly execute.

Interesting.
Do you think it's something that can be fixed and should we make CJ aware of this by moving this thread to the main tech forum? At least it should be documented, if it isn't already.

Scorpiorus

#6
I agree. I figured it out by trial but I think we should let him know and see if it's possible to do something about it.

I remember, awhile back somebody had a similar problem when RestartGame() isn't actually reseting variables to initial state -- can be caused by the very same reason if they had any code that modifies them in repeatedly execute etc.

Edit: I just tried putting SetRestartPoint() in several places but it didn't help either.

Edit: I fiddled with it a little bit more, so the problem is that the "restart point" is saved sometime after the room's repeatedly execute function finished running unless there is a "room change" request queued within this RepExec. In which case saving is postponed to the next room's repeatedly execute having finished ... etc.

Note that it would not even have a chance to save if "room change" is called from within one of the player enters room events (that's for AGS 2.71 at least). But the author of the topic said he is using AGS v2.6.



Please, could a moderator move this topic to the Technical Forums?


Thanks Ashen!

RickJ

#7
I have the same issues with the Save/RestoreGameSlot functions.   I describe the problem and then make some suggestions in this thread.

My suggestion was essentially to create a way of synchronizing the Save/Restore/Restart operation with subsequent instructions.   This would work similar to the "blocking" option available in other built-in functions (idea courtrsey monkey_05_06).   Alternatively an anothe rversion of Wait() could be created, via either a seperate wait command or an optional parameter, or add some type of  "Queue" or "Spawn" keyword that would allow a collection of instructions, containing Save, Restore, Restart, etc to be executed sequentially.


Scorpiorus

Yeah, since AGS v2.70 SaveGame is also made a delayed-response function just like RestoreGame. If I recall correctly, it was changed to assist the object-based scripting; to ensure the game can't be saved during function run in order to avoid problems with pointers. So, I'm not sure how much feasible it would be to do saving while any of script functions is running.

RickJ

#9
Yeah, I suspected something like that but there must be a practical way of accomplishing this.  I guess in my way of thinking the eBlock option would terminate the current script or thread when the Save or Restore instruction is encountered.  When the operation is complete you could just restart the thread at the place just after the Save or Restore operation was initiated. 

I suppose there could ne some promblems with losing context in "if" or "while" code blocks.  If so why couldn't we just use a keyword to associate a code block with the Save/Restore operation something like the following.

QueueAfterScript {

    // Do something before Save/Restore operation

    // Do Save/Restore operation
    SaveGameSlot(....)

    // Do something after Save/Restore operation
}

The engine and the user would know that the instructions within the braces are to executed after the current script is complete.  The current script would complete as normally, pointers and such would get cleaned up etc.  before the Save/Restore operation was initiated.  The "QueueAfterScript" instructions could be handled so that pointer problems do not arise and the compiler could enforce any necessary restrictions on what could be included in the delayed code block.

The problem I and other people have is that it's nearly impossible to add any kind of logic around these operations.  In some cases it can be done with guile, trickery, and cleverness which are not usually considered to be good programming practices. ;)   

I suppose I'm an optimist for believing there is a simple and practical solution out there. 

Scorpiorus

Quote from: RickJI guess in my way of thinking the eBlock option would terminate the current script or thread when the Save or Restore instruction is encountered.Ã,  When the operation is complete you could just restart the thread at the place just after the Save or Restore operation was initiated.

It's my guess that the engine just doesn't save the stack. RestoreGame always restores a game to state set somewhere after the script in which SaveGame was initially invoked, even if SaveGame saves game immediately (AGS v2.62 and pre), hence it could cause problems with objects dynamically created in that script, like:

function dummy() {

   // create new instance (refCount becomes 1)
   DynamicSprite *sprite = DynamicSprite.CreateFromFile(...);

   // new instance gets saved (reference count = 1)
   SaveGameSlot(...); // suppose saves immediately

   // reference count = 0
   sprite = null; // it's done automatically when dummy() finishes
}

Dynamic sprite is saved in that case, and saved with refCount = 1.
When game is restored the sprite is recreated and its ref count is 1 but there is nothing pointing to it since *sprite got out of scope.


QuoteThe engine and the user would know that the instructions within the braces are to e executed after the SaveGameSlot operation is completed.

So, is there a need to run some script after save finishes? Then how about an extra PostSave event for the on_event function? Could be easier to implement than adding the QueueAfterScript functionality?
Or simply set up a (SaveGameCalled==true) flag to check later within repeatedly execute and do rest of the work (I believe it's that kind of tricks you're talking about ;))


Anyway I think we should wait for Chris to make things clear here :)

Pumaman

The default restart point should be set after the first time repeatedly_execute runs when there are no blocking scripts or pending room changes going on.

So if for example your first screen was a title screen with a 5-second delay timer done with SetTimer, it would successfully save the restart point at the start of this room.

However if you did a 5-second delay timer with a Wait(200) call in Player Enters Screen, it would not manage to save the restart point in that room.

Scorpiorus is correct about the reasoning for the delayed save. The question is, whether it would be possible for AGS to change its save game behaviour in order that it would save the stack (and therefore do an instant save), and then when you called RestoreGame() it would terminate the current script, restore the state of the previous script and continue running from the instruction after the Save. In that case you'd have a script like:

Code: ags

function dummy() {
  
  Display("Before save");
  SaveGameSlot(...);
  Display("After save OR After restore");

}


There are various technical issues associated with this, but it's certainly worth me looking into because the behaviour at the moment can be a bit difficult to deal with when scripting games.

Traveler

I'm not sure if I understand the problem correctly, so just ignore this if not. :)

Wouldn't it be a solution to this if the game engine would provide events before and after save/restore/restart? Then the game source would have a chance to set variables to whatever values it needs to. So there would be a BeforeRestoreGame and an AfterRestoreGame event for which scripts could be written.

The game source thus would have a clear notification that a restore is going to happen at that point. The other (After...) could be used to initialize default values to all variables. It wouldn't even matter what the game engine saves, because the game "constructor" would take care of setting all defaults.

This could work well for save and restart as well and the game engine could still do these operations in a delayed fashion.

I hope this is not too confusing... :)

hedgefield

Seems I unearthed quite the problem then.

For now I've used the setrestartpoint(); command in the first idle moment after the intro, as CJ suggested. Albeit not perfect, this will do for now. That was also the problem with the saving, the fact that it was done during running commands.

Scorpiorus

Quote from: TravelerWouldn't it be a solution to this if the game engine would provide events before and after save/restore/restart?

Yeah, as I mentioned, some kind of an "after save" event in the on_event() function would probably make things consistent in case saving would remain a delayed-response operation; just like we have eEventRestoreGame for the restore. But I'm not sure whether there is a need for "before" events then.

However, although it's all related to the original problem questioned in this thread I somehow think it still is a little bit different. So I'd like to ask CJ the following question:

Quote from: PumamanThe default restart point should be set after the first time repeatedly_execute runs when there are no blocking scripts or pending room changes going on.

But would it be possible to additionally set the restart point (and maybe do any other save game work) just after the Player enters room (before fade-in) event? As it appears there are not any scripts running at that moment and room changes have a little sense in the before fade-in event (so there is no room change request either).

This way the RestartGame() could restore the state just before Player enters room (first time/after fade-in) which would exactly look like it's restarting at the very beginning, couldn't it?

Pumaman

#15
Something like that would be quite useful -- I'll look into how easy it would be to do.

Edit by strazer:

AGS v2.72 Beta 3:
* Changed the default restart point to be just before the first room is loaded, in order to avoid problems with the restart point not working properly in some games.

SMF spam blocked by CleanTalk