Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Event trigger after a set amount of time? (SugerCube)

Heya, so I'm trying to create an event that appears after a certain amount of time in-game has been reached (using the Javascript shown here).

For example: I would like that after 1 week in-game has happened, it will take the reader to a certain passage/event automatically. But... I'm not entirely sure how I can do that.

I've been looking through the forum and miscellaneous sites for some help but I can't really find anything that works so far.

Does anybody have any tips on how I can do this? Thank you !

Comments

  • edited March 2017
    You should always state the story format you're using and its version, because advice will tend to vary based on that information.

    For example: I would like that after 1 week in-game has happened, it will take the reader to a certain passage/event automatically. But... I'm not entirely sure how I can do that.
    Take the player when? The next time the player attempts to navigate passages, immediately, on some other criteria? For now, I'm going to assume that on the next navigation is okay.

    If you're using SugarCube ≥v2.13.0, then you may use the Config.navigation.override callback to override the player's navigation.

    For example, the following setup.eventOnDate() static method accepts the event passage and date as parameters and sets up a navigation override callback which compares the current game date to the event date and, if necessary, overrides the player's navigation—it also records the original destination passage in the _followup temporary variable, which you may use to send the player on after the event if you want: (Twine 2: goes in Story JavaScript; Twine 1: goes in script-tagged passage)
    if (!setup.eventOnDate) {
    	setup.eventOnDate = function(eventPassage, eventDate) {
    		Config.navigation.override = function (destinationPassage) {
    			// Override, if the game date is greater-than-or-equal to the event date.
    			if (State.variables.now.getTime() >= eventDate.getTime()) {
    				// Make this a single-use override.
    				Config.navigation.override = null;
    
    				// Record the original destination passage within a temporary variable.
    				State.temporary.followup = destinationPassage;
    
    				// Return the name of the event passage.
    				return eventPassage;
    			}
    		};
    	};
    }
    
    NOTE: The above only allows one event at a time and assumes that you're using $now as the current game date variable.

    Usage:
    <<run setup.eventOnDate(
    	'THE NAME OF THE EVENT PASSAGE',
    	setup.changeDate($now, 'weeks', 1)
    )>>
    
  • Whoops, sorry! I'm using SugarCube 2.12.1 and Twine 2.

    And yeah, the next navigation was what I was had in mind. Again, sorry for not being more clear about that.

    So, I placed the setup in the Story JavaScript and attempted to activate the usage in the appropriate passage (with the correct name of the passage I wanted it to be TAKEN to and in the Usage code and all) aaand I got an error.

    ' Error: <<run>>: bad evaluation: Cannot set property 'override' of undefined '

    I didn't really change anything (except for 'THE NAME OF THE EVENT PASSAGE' to the actual name of the passage with the event but I'm guessing that's probably not the problem here), so I'm not entirely sure what went wrong.

    My apologies if the answer is super obvious or something, I'm pretty new to Twine and everything so if I'm being a dummins, I'm sorry!
  • Whoops, sorry! I'm using SugarCube 2.12.1 and Twine 2.

    ...

    ' Error: <<run>>: bad evaluation: Cannot set property 'override' of undefined '

    ...
    As mentioned by TME, this code relies on the Config.navigation.override callback, which is only in v2.13 and later.

    Probably the simplest solution would be to update your SugarCube install, if possible.

  • As I noted in my previous post, you need SugarCube ≥v2.13.0 for that to work.
    If you're using SugarCube ≥v2.13.0, then you may use the Config.navigation.override callback to override the player's navigation.
  • Yeah sorry, I read that wrong. Whoops.

    It works fabulously, thanks you guys soooo much! You really are a lifesizer, thank you!

    On a side note, I don't know if I should ask this in a separate discussion or not, but since it's kind of close to the original question I'll just ask it here:

    Is there any way to use the Javascript's time as an expression in an If macro?

    So if I wanted to, say, have an If macro activate but only at a certain time and in a certain location (so basically overriding them, but only if they go to a specific passage, not just one that activates regardless of where they're at like the code you guys helped me with), is there any way to do that?

    Just in case I'm not making that much sense, what I'm asking to do would be like " <<if currenttime is so-and-so>> Text <<endif>> ". That expression wouldn't work obviously, but I wanted to visualize what I'm asking just in case.

    Sorry if this is basic babby stuff I should probably know by now. It might've been a month since I've asked a question but I'm still not nearly as good at Twine as I wished I could be! :blush:
  • You could do something like the following to check the current game date against a specific game date:
    <<set _date to new Date(…)>>\
    <<if $now.getTime() gte _date>>…<</if>>
    
  • You could do something like the following to check the current game date against a specific game date:
    <<set _date to new Date(…)>>\
    <<if $now.getTime() gte _date>>…<</if>>
    

    Do you put the time you want the If macro to activate in the (...) parenthesis on the first line (so like <<set _date to new Date($now, 'minutes', 15) or does something else belong there?

    And should I just leave the () in the second line empty? Or does it need the same value as the parenthesis above too?

  • In the opening post you stated that you were using the JavaScript from the How to make a time system? thread. The periods of ellipsis should be replaced by the very same kind of parameters you, apparently, used to initialize your game clock, as shown in that thread.

    For example:
    <<set _date to new Date(2000, 0, 1, 0, 0, 0)>>\
    <<if $now.getTime() gte _date>>…<</if>>
    
    That is likely not the date you'll wish to use.
  • edited April 2017
    It works!! Thank you so much!

    It wasn't initially doing anything, regardless of how much tinkering I did/making sure all the numbers were right. But somehow changing the underscore in "_date" to a dollar sign ended up working for me. Huh, weird!

    Still, I'm super happy I was able to get all of this to work (even though now I have a problem where I want the if macro to only activate once but meh)

    Thank you so very much for your help, Exile! :smiley:
  • I have a real quick (hopefully) final question: if I wanted the If macro to only show up at the specific time and nothing else, what should I do? Because while the current one works really well for the most part, it seems that once it activates the text doesn't go away after the time changes. It just kinda... stays there, forever. Even using a second macro after the first's time (which also work, by the way!) still displays the first's text, along with the second's, even though the time isn't the same anymore. Is this fixable?
  • It wasn't initially doing anything, regardless of how much tinkering I did/making sure all the numbers were right. But somehow changing the underscore in "_date" to a dollar sign ended up working for me. Huh, weird!
    Then you are using SugarCube v1, instead of v2. My condolences.


    I have a real quick (hopefully) final question: if I wanted the If macro to only show up at the specific time and nothing else, what should I do? […]
    If the time will match exactly, then you could change out the greater-than-or-equal (gte) operator for the equality operator (is). I would think that's unlikely to happen, however, so you'll probably have to use a sentinel variable to keep it from showing up again. For example:
    <<if not $eventName and $now.getTime() gte new Date(2000, 0, 1, 0, 0, 0)>>\
    <<set $eventName to true>>\
    …stuff…\
    <</if>>
    
  • It worked really great!

    Thanks again for all your help, Exile!
  • Hey, so, it's me again.

    Sorry for constantly bringing this discussion up but I've got a new problem and I'm having some trouble trying to fix it.

    So I figured out that if I wanted to, say, have any afternoon-focused If statements I could use something like <<if setup.changeDate ($now, 'hours', 12)>> <<set $afternoon to true>> <<endif>>, so that way I don't have to make like dozens of different dates for every afternoon in game.

    It worked for the most part but now I'm in a bit of a snag.

    I'm trying to make it so that if the player is in a specific room while $afternoon is true, they are taken to a different passage automatically (using goto "Passagename").

    But, whenever they enter the passage that's SUPPOSED to take them to the afternoon event ONLY when $afternoon is true, but the goto activates at ANY time, even if it's no where near 12 hours. I've tried to fidget and fix this but it doesn't seem like anything I'm trying is working. Either it still takes the player to the passage AUTOMATICALLY, even if it's the right time or not, or nothing happens. It's pretty frustrating.

    Does anyone have any ideas of how to do this WITHOUT making like tons of different new Dates for every day or without it activating the passage even though it's nowhere near the time it's supposed to trigger at?

    Thank you!
  • edited May 2017
    Please use the code tag—it's C on the editor bar—when posting code or markup.

    So I figured out that if I wanted to, say, have any afternoon-focused If statements I could use something like <<if setup.changeDate ($now, 'hours', 12)>> <<set $afternoon to true>> <<endif>>, so that way I don't have to make like dozens of different dates for every afternoon in game.
    Your example doesn't do what you think it does. The setup.changeDate() returns a new Date object. By using it as the sole part of the <<if>> macro's conditional expression, you're simply causing it to be coerced into a boolean. Objects are always truthy—i.e. when coerced to boolean, they always coerce to true. Thus your <<if>> will always be true and execute it contents.

    You probably wanted to compare the new Date to some approximation of an "afternoon" range—e.g. 12:01–17:59.


    SugarCube v1 example
    Since v1 does not have temporary variables, the example uses story variables and unsets them at the end.
    <<set
    	$_plus12 to setup.changeDate($now, 'hours', 12),
    	$_hh to $_plus12.getHours(),
    	$_mm to $_plus12.getMinutes()
    >>\
    <<if
    	($_hh gt 12 or ($_hh eq 12 and $_mm gte 1)) and
    	$_hh lt 18
    >>\
    <<set $afternoon to true>>\
    <</if>>\
    <<unset $_plus12, $_hh, $_mm>>
    


    SugarCube v2 example
    <<set
    	_plus12 to setup.changeDate($now, 'hours', 12),
    	_hh to _plus12.getHours(),
    	_mm to _plus12.getMinutes()
    >>\
    <<if
    	(_hh gt 12 or (_hh eq 12 and _mm gte 1)) and
    	_hh lt 18
    >>\
    <<set $afternoon to true>>\
    <</if>>
    
  • Please use the code tag—it's C on the editor bar—when posting code or markup.

    I'll start doing that from now on, thanks for the heads-up!

    So, I used the example you gave and it works... kinda. The If statement DOES only trigger at the specific times like it's supposed to (thank you very much for helping me out there!) but when it does it's at midnight, or hour 0, not 12. I tried and fidget with the numbers a bit to try and get results but after swapping out the '12' for any other number the entire code just stops working.

    Could it be that I'm setting/advancing the date wrong? I posted the two codes I'm using below:
    Setting date: <<set $now to new Date(1, 0, 0, 6, 35, 0)>>
    
    Advancing time: <<set $now to setup.changeDate($now, 'hours', 1)>>
    

    (thanks for telling me how to put the code in the box thingy, it looks so much better and easier than just plopping it with the rest of the comment!)
  • edited May 2017
    I cannot say with certainty what's wrong at the moment.

    First. Where are you running this code? In the PassageReady special passage?

    Anyway. You were a bit scant on details, so I made the assumption that the new Date you were attempting to generate—i.e. current game time plus 12 hours—was when the event was to take place, so you could see if that time was in the afternoon block. If that assumption was incorrect, then yes, it probably isn't doing what you want.


    If you simply want to know if the current game time is within the afternoon block, then there's no need to create a new Date. You will, likely, want to run the code automatically every turn, probably in PassageReady, and have it set $afternoon appropriately for either condition.

    Here is a PassageReady-based code example—for SugarCube v1 and v2—and usage examples for the version of $afternoon set by the code example.

    Also. The code examples—both the previous set and the following ones—define afternoon as: 12:01 ↔ 17:59 (24 hr) or 12:01 PM ↔ 5:59 PM (12 hr). Anything else is considered to be not afternoon.


    SugarCube v1 example (goes in the PassageReady special passage)
    Since v1 does not have temporary variables, the example uses story variables and unsets them at the end.
    /*
    	Set $afternoon appropriately each turn, based on the current game time ($now).
    */
    <<set
    	$_hh to $now.getHours(),
    	$_mm to $now.getMinutes()
    >>
    <<if
    	($_hh gt 12 or ($_hh eq 12 and $_mm gte 1)) and
    	$_hh lt 18
    >>
    	<<set $afternoon to true>>
    <<else>>
    	<<set $afternoon to false>>
    <</if>>
    <<unset $_hh, $_mm>>
    


    SugarCube v2 example (goes in the PassageReady special passage)
    /*
    	Set $afternoon appropriately each turn, based on the current game time ($now).
    
    	NOTE: I've left $afternoon as a story variable to maintain parity with the v1
    	example, however, in v2 it probably makes more sense to use a temporary variable
    	for it instead—i.e. _afternoon—since this code sets it at the top of each turn.
    */
    <<set
    	_hh to $now.getHours(),
    	_mm to $now.getMinutes()
    >>
    <<if
    	(_hh gt 12 or (_hh eq 12 and _mm gte 1)) and
    	_hh lt 18
    >>
    	<<set $afternoon to true>>
    <<else>>
    	<<set $afternoon to false>>
    <</if>>
    


    Usage of $afternoon (as set by the preceding code examples)
    Checking for both afternoon and not afternoon.
    <<if $afternoon>>
    	/* Current game time is afternoon. */
    <<else>>
    	/* Current game time is not afternoon. */
    <</if>>
    
    Checking only for afternoon.
    <<if $afternoon>>
    	/* Current game time is afternoon. */
    <</if>>
    
    Checking only for not afternoon.
    <<if not $afternoon>>
    	/* Current game time is not afternoon. */
    <</if>>
    
Sign In or Register to comment.