Strange problem with SetTimer...

Started by Bandersnatch, Wed 11/09/2013 21:33:11

Previous topic - Next topic

Bandersnatch

I have recently come back to a tech demo I left alone a while back, and seem to have hit a snag concerning the SetTimer function. Each part of the timed tutorial has a character repeat a couple of lines in the background with a 10 second interval between repeating phrases. Once the tutorial reaches a certain point however, the character repeats the same line over and over without any 10 second interval despite it being written in the EXACT same way it has been previously. Any ideas?

Khris

The first thing that comes to mind is that you have reused the same timer.
If you want to add another timer to the game, you have to use SetTimer(2, time); and IsTimerExpired(2), otherwise you'll interfere with the first one.

Also, show us your code and tell us which tutorial you are using.

Bandersnatch

Thanks Khris, I may well be making that mistake. I'll have a play around with use of timers and the aforementioned booleans for a few functions which could probably be simplified using them.

Another quick question...

After a particular dialogue tree, there is a scripted exchange in which the player character walks to a different spot for some brief dialogue. As soon as I regain control however, she walks back to the spot she was in during the original dialogue tree. How do I stop that happening?

I have an enquiry or two about putting my tutorial coding in the global script rather than the room script and then importing it as it's causing some issues with executing commands at the right time. However, use of booleans might help. I can picture it in my head so I'll give that a shot first.

Khris

Again, show us the code you're using.

Bandersnatch

This is the script for the room so far, with the tutorial I've put together. Let's not worry about the whole 'reusing Timer 1' thing as I'm working on that. Where we have "tutorialState" as 5, I want this to be activated when a dialogue has happened but I have no idea how to make that work. Obviously there's bits of coding from dialogues and things as well, and I'll upload these in a sec.

Code: ags

//MANCOMB DISMISS BOOL

import function mancomb_dismiss;

function room_FirstLoad()
{
hDoorway.Enabled = false;
}
//TUTORIAL CODING
int tutorialState = 0;
function room_AfterFadeIn(){
  if(tutorialState == 0){ //BEGINNING OF TUTORIAL
  Wait(40);
  cWhitfield.Say("Welcome to the tutorial, shit potatoes!");
  Wait(40);
  cWhitfield.Say("Now go look at the coffee pot!");
  tutorialState = 1;
  SetTimer(1, 400); //10 SECOND TIMER
  set_door_state(0, 0);
  if(mancomb_dismiss==1){
  tutorialState = 5;
  }
  }
}

function room_RepExec(){
  if(IsTimerExpired(1)){
    if(tutorialState==0){
    Display("Reminder");}
    else if(tutorialState==1){
    cWhitfield.SayQueued("Are you even listening?");
    cWhitfield.SayQueued("Look at the coffee pot!");
    SetTimer(1, 400);
    }
    else if(tutorialState==2){
    cWhitfield.SayQueued("I said open the goddamned door!");
    SetTimer(1, 400);
    }
    else if(tutorialState==3){
    cWhitfield.SayQueued("Close the door, there's nothing there!");
    SetTimer(1, 400);
    }
    else if(tutorialState==4){
    cWhitfield.SayQueued("Talk to the customer or you're fired!");
    SetTimer(1, 400);
    }
    else if(tutorialState==5){
    }
  }
}

//END OF TUTORIAL CODING

function hPortrait_Look()
{
  cEleanor.FaceDirection(eDir_Up);
  cEleanor.Say("I wonder if he's got a painting of himself above his bed as well.");
}

function hCoffeePot_Look()
{
  QueuedSpeech.SkipCurrentMessage();
  cEleanor.Say("The coffee isn't ready yet.");
  if(tutorialState==1){
    cWhitfield.SayQueued("Good!");
    cWhitfield.SayQueued("Now go open the door on the left!");
    tutorialState = 2;
    SetTimer(1, 400); //10 SECONDS
    }
}
function oDoor_AnyClick()
{
  if (MovePlayer(53, 88)) {
  }
    // LOOK AT
    if(UsedAction(eGA_LookAt)) {
      player.Say("That door is so poorly fitted.");
    }
    // USE
    else if(UsedAction(eGA_Use)) {
      player.Say("Please be more specific, Sir Graham.");
    }
    // Push
    else if(UsedAction(eGA_Push)) {
      player.Say("It might break.");
    }
    // Pull
    else if(UsedAction(eGA_Pull)) {
    player.Say("Nah.");
    }  
    // PICKUP
    else if(UsedAction(eGA_PickUp)) {
      player.Say("Pick up a door?!");
    }
    // OPEN
    else if(UsedAction(eGA_Open)) {
      if (get_door_state(0)==1)
      player.Say("It's already open.");
      if (get_door_state(0)==0)
      player.Say("Maybe if it had a second sprite...");
      oDoor.Graphic=244;
      oDoor.X=40;
      oDoor.Y=85;
      hDoorway.Enabled = true;
      set_door_state(0, 1);
      Wait(40);
      cWhitfield.SayQueued("Bah! The useless developer of this stupid game hasn't even drawn the next room!");
      cWhitfield.SayQueued("So what are you waiting for?! Close it again!");
      tutorialState = 3;
      SetTimer(1, 400);

    }
    // CLOSE
    else if(UsedAction(eGA_Close)) {
      if (get_door_state(0)==0)
      player.Say("It's already closed.");
      if (get_door_state(0)==1)
      oDoor.Graphic=245;
      oDoor.X=12;
      oDoor.Y=87;
      hDoorway.Enabled = false;
      set_door_state(0, 0);
      cWhitfield.SayQueued("You may have noticed there's a customer back here.");
      cWhitfield.SayQueued("Don't you think it's a tad rude not checking up on him?!");
      tutorialState = 4;
      SetTimer(1, 400);
    }
    //USE INV
    else if(UsedAction(eGA_UseInv)) {
      Unhandled();
    }
    // don't forget this
    else Unhandled();
  }


Bandersnatch

This is the dialogue and scripting after which I'd like the tutorialState to become "5", in which there are no timers or pieces of dialogue. I have no idea how to activate a tutorial state after dialogue.

Code: ags

@5
cEleanor: That's not what I--
cMancomb: I AM DESCENDED FROM A CARIBBEAN GOVERNOR, YOU KNOW!
cMancomb: GET OUT OF MY SIGHT!
  cEleanor.FaceDirection(eDir_Down);
cEleanor: *sigh*
  Wait(40);
cEleanor: What a butt.
  Wait(40);
cWhitfield: Well? How's he doing?
  cEleanor.Walk(287,95,eBlock,eWalkableAreas);
  cEleanor.FaceDirection(eDir_Right);
cEleanor: He's far from satisfied.
  Wait(40);
cWhitfield: That'll be your fault then.
  Wait(40);
cWhitfield: You're fired.
  gAction.Visible = true;
  gMaingui.Visible = true;
stop

Khris

-tutorialState is a room variable. If you want to change it within a dialog, you have to make it global. Use the Global variables pane to create it, and remove the line from the room script (line 10 in the code you posted). Once you did this, just add " tutorialState = 5;" at any point in the dialog script.

-In line 3, instead of "function", it's supposed to be "int". Technically, the two are equivalent, but leaving it like that looks wrong and is highly confusing.

-When you use "if (condition)" and want to execute multiple commands depending on whether the condition is true, you have to group them together using { and }.
Consider this:
Code: ags
  if (a)
  player.Say("a is true");
  player.Say("I will always say this.");

The if only affects line 2; line 3 is always called.
Here's the correct way:
Code: ags
  if (a) {
    player.Say("a is true");
    player.Say("I will only say this if a evaluates to true.");
  }

Bandersnatch

Thanks! So let me get this straight - if I set "tutorialState" as a global variable, I can still use it in the room script but it'll be possible to use it in dialogues too? Excellent. I'll look into it and get back to you, most likely with more rookie questions.

Bandersnatch

So I got to work on doing all that stuff and it works perfectly. Thank you! Now to get my head down and finish this demo ting...

Bandersnatch

Sorry to bump this after months and months but I'm struggling to change the timers. Obviously Timer(1) is set to repeatedly execute but that's only for when tutorial.State = 1. Once it reaches tutorial.State 2 I want Timer(2) to start and repeatedly execute and so on with each tutorial.State. I'm just not sure where to add the changes in timer.

Khris

You can directly use the variable as parameter:
Code: ags
  SetTimer(tutorialState, 400); // ten seconds

// in rep_exe
  if (IsTimerExpired(tutorialState)) ...


The question is whether that's actually useful, since at least in the second case you'll probably want to do different things depending on the value of tutorialState, right?
Which means you can use timer #1 for each state no problem:
Code: ags
  if (IsTimerExpired(1)) {
    if (tutorialState == 1) {
      ...
    }
    if (tutorialState == 2) {
      ...
    }
    ...
  }

Bandersnatch

Thanks - I think you're right about using Timer #1 for each state, and that's what I've been doing - the dialogue is changing accordingly but the only thing I can't work out is how to get the timer to reset each time the tutorial state changes. For example, I have the timer set at 400 (about 10 seconds?) but if the tutorial state changes 5 seconds into the countdown, then it's only 5 seconds until the next dialogue. If there's a way to stop/start it again at each state change that would be helpful...

Bandersnatch

I think I've cracked it. Before telling the timer to count down from 10 in each change of state, I used setTimer(1, 0), which seems to have reset it. Does that seem logical?

Khris

Yeah, you definitely need to reset the timer when you change tutorialState.
400 equals ten seconds if you kept the default GameSpeed of 40 frames per second. In case the player can change the speed of your game, you can use something like SetTimer(1, 10 * GetGameSpeed()); instead.

SMF spam blocked by CleanTalk