(SOLVED) Global progression of time, akin to Grand Theft Auto

Started by ty3194, Tue 13/12/2011 04:57:21

Previous topic - Next topic

ty3194

I have searched the forums for a thread that would help me with this, but all talk about room-based time and thus are unhelpful.

Basically, my game is going to be grand theft auto + the sims, and I want to create time within the game's global script so it is continuous throughout the entire game.

For every second = 1 minute, every minute = 1 hour and for every in-game hour I want the character's stats (need for hunger, sleep, bathroom, etc.) to change within a range of 1-10. Also, I want to make a digital clock GUI that progresses, along with the time script, from 12am (midnight) to 12pm (noon) and back to midnight.

So say the player is tired (sleep > 4) then they can sleep, which advances time 8 in-game hours and resets sleep counter to zero. but say the player stays up within game for a long time (by either sleep deprivation or use of stimulants), and sleep is 8+, then the next time they have to sleep it will last for more than 8 in game hours and leave the player groggy (sleep counter 3). Im sure the stats can be attributed to global variables easily.

Any help with this, specifically the global time scripting, would be great.

Gilbert

#1
Just create global variables like this:
Code: ags
int time_loop, time_min, time_hour, time_day;


And then in repeatedly_execute() of the global script (put it in repeatedly_execute_always() instead if you want it to count even when the game is paused):
Code: ags

time_loop++;
if (time_loop==40) {//Assuming under default settings where the game runs at 40 FPS
  time_loop=0;
  time_min++;
  if (time_min==60){
    time_min=0;
    time_hour++;
    if (time_hour==24){
      time_hour=0;
      time_day++;
    }
  }
}


The GUI part is simple. Just make one with a label that say, called lblClock . Then, in repeatedly_execute_always():
Code: ags

if (time_hour <12){
  if (time_hour==12)  lblClock.Text = String.Format("12:%02d a.m.", time_min);
  else lblClock.Text = String.Format("%02d:%02d a.m.", time_hour, time_min);
} else {
  lblClock.Text = String.Format("%02d:%02d p.m.", time_hour-12, time_min);
}


To make stuff happen at specify time just check in the script on whether the values of the time_* variables match your criteria. You may put the checking in say, repeatedly_execute(). If some of such events only happen in certain rooms, you may even check them in the room scripts, provided that the variables are exported.
You may need to add some more codes to say let an event happen only once and prevent it from happening continuously every game loop, etc., but that's becoming complicated for this post atm. I'd advise you to try doing the basis first, like making the clock work, before jumping into further codings.

ty3194

this is very helpful. i got all the global variables set (with names like vSec, vMin, vHour, vDay [for OCD reasons])

also, i put the code in global script

function repeatedly_execute()
{
 
  // put anything you want to happen every game cycle, even when
  // the game is paused, here
 
  if (IsGamePaused() == 1) return;
vSec++;
if (vSec==40)
{
  vSec=0;
  vMin++;
  if (vMin==60){
    vMin=0;
    vHour++;
    if (vHour==24){
      vHour=0;
      vDay++;
    }
  }
}
  // put anything you want to happen every game cycle, but not
  // when the game is paused, here
}

now i just need to make the GUI. i right clicked GUI, made new GUI with title lblClock, but how does one make a function under repeatedly_execute, because when I click the lightening bolt it just says On_Click

EDIT: about making a function under repeatedly_execute... I now understand that you mean within globalscript, not under GUI properties. Also, to avoid any confusion I made my script exactly as you stated.

Now it says there is an undefined symbol "hour" at line 59,60

57 function repeatedly_execute()
58 {
59  if (hour <12){
60  if (hour==12)  lblClock.Text = String.Format("12:%02d a.m.", time_min);
61  else lblClock.Text = String.Format("%02d:%02d a.m.", time_hour, time_min);
62 }
63 else
64{
65  lblClock.Text = String.Format("%02d:%02d p.m.", time_hour-12, time_min);
66 }
67  // put anything you want to happen every game cycle, even when
68  // the game is paused, here

I'm assuming it is because within that code there is a variable title hour rather than time_hour. after converting each hour (at 59,60) to time_hour, the error disappears but is replaced with this error:

GlobalScript.asc(60): Error (line 60): '.Text' is not a public member of 'GUI'. Are you sure you spelt it correctly (remember, capital letters are important)?

 

Gilbert

Quote from: ty3194 on Tue 13/12/2011 06:06:51
I'm assuming it is because within that code there is a variable title hour rather than time_hour. after converting each hour (at 59,60) to time_hour, the error disappears...
Yeah, right. I rushed my sample codes without testing. It should be fixed now.

Quote
...but is replaced with this error:
GlobalScript.asc(60): Error (line 60): '.Text' is not a public member of 'GUI'. Are you sure you spelt it correctly (remember, capital letters are important)?
Don't just make a GUI that is called lblClock, instead make a GUI and put a label on it. Name the label lblClock (you don't really need to use this name, it's just like some kind of convention to prefix a label's name with lbl for clarity's sake). You should now be able to change the text on that label with your scripts.

monkey0506

I'd also just like to mention that, although most people never change the FPS of their AGS games, you can use GetGameSpeed() in place of that static 40. Oh, and unless you intentionally changed it, you've miscopied some of the code. The way you have it written right now, 1 minute would pass every second, an hour every minute, and a day every 24 minutes.

Quote from: Iceboty V7000a on Tue 13/12/2011 05:41:21And then in repeatedly_execute() of the global script (put it in repeatedly_execute_always() instead if you want it to count even when the game is paused)

This is somewhat misleading as there's a difference between the game being paused and the game running a blocking function.

The game is paused when:

- You call PauseGame()
- You set a GUI to visible that has a display type of "Pause game when shown"

That's it.

The game is running a blocking function when:

- A character is speaking (other than using SayBackground)
- The Wait function is called
- You run any function with a BlockingStyle parameter passed as eBlock (such as Character.Animate or Character.Walk)
- Dialog options are being shown
- And maybe some other stuff that I can't think of off the top of my head!

Both repeatedly_execute and repeatedly_execute_always are called when the game is paused.

Only repeatedly_execute_always is called when the game is running a blocking function.

So unless time stops every time a character is speaking, you definitely want to change that to repeatedly_execute_always.

ty3194

That is exactly how I want the time to be, 1 IRL second= 1 IG minute, etc..

this is my code now


function repeatedly_execute() {
 
  // Put here anything you want to happen every game cycle, even when
  // the game is paused. This will not run when the game is blocked
  // inside a command like a blocking Walk()
 
  if (IsGamePaused() == 1) return;

  // Put here anything you want to happen every game cycle, but not
  // when the game is paused.
}

function repeatedly_execute_always() {
 
time_loop++;
if (time_loop==40) {
  time_loop=0;
  time_min++;
  if (time_min==60){
    time_min=0;
    time_hour++;
    if (time_hour==24){
      time_hour=0;
      time_day++;
      {
    if (time_hour <12){
    if (time_hour==12)  lblClock.Text = String.Format("12:%02d a.m.", time_min);
    else lblClock.Text = String.Format("%02d:%02d a.m.", time_hour, time_min);
    }
    else
    {
    lblClock.Text = String.Format("%02d:%02d p.m.", time_hour-12, time_min);
    }
    }
  }
}


my clock GUI is named gClock, with a label named lblClock, but it now says

GlobalScript.asc(83): Error (line 83): Undefined token 'lblClock'



and from 'monkey_05_06's post, I now understand the difference between the 2 functions repeatedly_execute & repeatedly_execute_always...

function repeatedly_execute()= continuously carries out a function even when the game is paused except while a blocking function is overriding

if (IsGamePaused() == 1) return;= same as above except the function is also not carried out even when paused

function repeatedly_execute_always()= continuously carries out a function, even when the game is paused and even when a blocking function is occuring


from that, could one put 'if (IsGamePaused() == 1) return' under 'function repeatedly_execute_always()' to make the function repeatedly execute during blocking functions but not during pausing? I dont want the player to pause the game and get up only to come back starving, fatigued, and on the verge of urinating

Khris

If there is a label named "lblClock", it is impossible for you to get that error. Double-check the label's name in the GUI editor.
Also, if you type "lbl" in the global script, the auto-complete-window should pop up and offer you all known objects starting with "lbl". If "lblClock" isn't among them, the label has the wrong name.

Regarding pausing the game: I'd show a GUI that says paused and put this in rep_ex_always:

Code: ags
  if (gPaused.Visible) return;

  // advance clock here

ty3194

Khris your right, i had the text as lblClock instead of the name. that is resolved, but now to the pause thing. this is my code


function repeatedly_execute_always() {

if (gPause.Visible) return;
{
time_loop++;
if (time_loop==40) {
  time_loop=0;
  time_min++;
  if (time_min==60){
    time_min=0;
    time_hour++;
    if (time_hour==24){
      time_hour=0;
      time_day++;
      {
    if (time_hour <12){
    if (time_hour==12)  lblClock.Text = String.Format("12:%02d a.m.", time_min);
    else lblClock.Text = String.Format("%02d:%02d a.m.", time_hour, time_min);
    }
    else
    {
    lblClock.Text = String.Format("%02d:%02d p.m.", time_hour-12, time_min);
    }
    }
  }
}
}
}


it gives the error GlobalScript.asc(71): Error (line 71): undefined symbol 'gPause'

pausing the game isnt my concern, its pausing the time when the game is paused that is.


also, when i run the game with the gClock GUI visible on the screen with a gray box and green txt, nothing is shown.



thanks for everyones help


Gilbert

Quote from: ty3194 on Wed 14/12/2011 01:04:00
it gives the error GlobalScript.asc(71): Error (line 71): undefined symbol 'gPause'
That means you have not created a GUI called gPause. KhrisMUC did mention:
Quote from: Khris on Wed 14/12/2011 00:17:52
I'd show a GUI that says paused...
But this is well hidden that normal readers may overlook.
Quote
also, when i run the game with the gClock GUI visible on the screen with a gray box and green txt, nothing is shown.
Can you elaborate on this? Do you mean the GUI doesn't appear in the game at all? Check that whether the GUI is set to 'always visible'.

Khris

Yeah, I didn't explicitly state that you also have to create a GUI called gPause(d). I thought that much is clear if you're going to check whether it is visible in rep_ex_always.
In on_key_press, add this at the top of the function:

Code: ags
  if (keycode == eKeySpace) {
    if (gPause.Visible) {
      UnpauseGame();
      gPause.Visible = false;
    } else {
      PauseGame();
      gPause.Visible = true;
    }
  }


Regarding the clock GUI, it sounds like its visibility is set to "pause game when shown". That's what you have to set the pauseGUI to, not the clock GUI though. Set it to "normal, initially on".

ty3194

Quote from: Khris on Wed 14/12/2011 01:53:51

Regarding the clock GUI, it sounds like its visibility is set to "pause game when shown". That's what you have to set the pauseGUI to, not the clock GUI though. Set it to "normal, initially on".

Actually the clock GUI, gClock, is already set to normal, initially on. The gray box appears as it should in the bottom right where I placed it. Tho, the green text doesnt appear. I think theres some  compatibility (for lack of a better word) issues between gClock and the global script for the GUI's label txt for the time_int variable's display. No numbers are showing.

Here is the code:

Code: ags

    if (time_hour <12){
    if (time_hour==12)  lblClock.Text = String.Format("12:%02d a.m.", time_min);
    else lblClock.Text = String.Format("%02d:%02d a.m.", time_hour, time_min);
    }
    else
    {
    lblClock.Text = String.Format("%02d:%02d p.m.", time_hour-12, time_min);
    } 



the game starts fine and there are no errors.


and on a side note, I am now debating whether or not to forbid pausing the game as to make it more like real life, as I want it to be. You should have to find a safeplace first before you can walk away from the game. though, some people might not like having to watch out for the cops all the time in real life and in game....

Gilbert

I don't have much idea, but make sure that the label's width is long enough to hold the text.

Also:
Code: ags

  if (time_hour <12){
    if (time_hour==12)  lblClock.Text = String.Format("12:%02d a.m.", time_min);
    else lblClock.Text = String.Format("%02d:%02d a.m.", time_hour, time_min);
  }
    else
  {
    lblClock.Text = String.Format("%02d:%02d p.m.", time_hour-12, time_min);
  } 

The second line 'if (time_hour) == 12)...' should be 'if (time_hour) == 0)...' .

ty3194


Code: ags

  if (time_hour <12){
    if (time_hour==0)  lblClock.Text = String.Format("12:%02d a.m.", time_min);
    else lblClock.Text = String.Format("%02d:%02d a.m.", time_hour, time_min);
  }
    else
  {
    lblClock.Text = String.Format("%02d:%02d p.m.", time_hour-12, time_min);
  } 


[/quote]

ok so does this go under global script too? or within the gClock GUI txt part? cause I was under the influence that it was the former, but it doesnt show up even if the onscreen GUI is huge. but, I put txt in the GUI property and it shows in game

Khris

That code is a snippet of the whole thing supposed to go in repeatedly_execute_always.
Iceboty just wanted to point out a small error and posted the surrounding lines so you can find it easier.

The problem is that you put the code that's supposed to update the label inside the block that advances the day counter, in other words, you only updated the label every 24 minutes.

Here's the complete function:
Code: ags
function repeatedly_execute_always() {

  if (gPause.Visible) return;

  // advance game clock
  time_loop++;
  if (time_loop == 40) { // advance game minutes
    time_loop = 0;
    time_min++;
    if (time_min == 60) { // advance game hours
      time_min = 0;
      time_hour++;
      if (time_hour == 24) { // advance game days
        time_hour = 0;
        time_day++;
      }
    }
  }

  // update clock label
  if (time_hour < 12) {
    if (time_hour == 0)  lblClock.Text = String.Format("12:%02d a.m.", time_min);
    else lblClock.Text = String.Format("%02d:%02d a.m.", time_hour, time_min);
  }
  else lblClock.Text = String.Format("%02d:%02d p.m.", time_hour-12, time_min);

}


You also had a few pointless {}'s in there which I have removed.

ty3194

Thanks Khris that worked, as compared to my old code. The clockGUI is going nice and smooth, and works fine with the  pause GUI (which I bound to eKeyP:every time P is pressed the whole screen is covered with a transparent GUI with label 'pause' in center; time pauses as it should), except that time stops when something talks. This is the exact time section of my globalscript:

Code: ags

function repeatedly_execute() {
  
  // Put here anything you want to happen every game cycle, even when
  // the game is paused. This will not run when the game is blocked
  // inside a command like a blocking Walk()
  
  if (IsGamePaused() == 1) return;

  // Put here anything you want to happen every game cycle, but not
  // when the game is paused.
}

function repeatedly_execute_always() {

if (gPause.Visible) return;

  // advance game clock
  time_loop++;
  if (time_loop == 40) { // advance game minutes
    time_loop = 0;
    time_min++;
    if (time_min == 60) { // advance game hours
      time_min = 0;
      time_hour++;
      if (time_hour == 24) { // advance game days
        time_hour = 0;
        time_day++;
      }
    }
  }

  // update clock label
  if (time_hour < 12) {
    if (time_hour == 0)  lblClock.Text = String.Format("12:%02d a.m.", time_min);
    else lblClock.Text = String.Format("%02d:%02d a.m.", time_hour, time_min);
  }
  else lblClock.Text = String.Format("%02d:%02d p.m.", time_hour-12, time_min);

}


Besides that, I believe this thread has fulfilled its purpose. Now all that is left for me to do is link the time_variables to the mood_variables (vSleep, vEat, vFun, etc.), which I'm supposing can be done within the globalscript here

Code: ags

time_loop++;
  if (time_loop == 40) { //
    time_loop = 0;
    time_min++;
    if (time_min == 60) { // MOOD_VARIABLES INCREASED OVER HOUR INTERVALS BY 1-10 POINTS [or even 1/2 points if possible- if not then I will do that within the above minutes interval].
      time_min = 0;
      time_hour++;
      if (time_hour == 24) { // 
        time_hour = 0;
        time_day++;


Thanks to anyone who has or will help me with this, and know that it will help other creators (whom may also possess creativity only hindered by a lack of technical knowledge) in the future.

SMF spam blocked by CleanTalk