Howdy, Stranger!

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

(SugarCube 2) Monitor a global variable and override content when it gets too high

I'm trying to implement a system where a particular negative variable is monitored during the player's playthrough and when it gets too high the player is taken out of whatever part of the game they're in and forcibly moved to a sequence giving them the opportunity to reduce it or lose. I'm not entirely sure the best way to put this into the game, and hopefully I'm making sense & explaining myself correctly, but any ideas?

Comments

  • edited February 14
    Posting from my phone at the moment (before 6AM my time, medical appointments all day), so a real reply will have to wait until later tonight or tomorrow.

    It is definitely possible, yes—though perhaps not as cleanly as I'd like.

    Question: When does this need to happen? Is on the transition to a new turn/moment sufficient or should this happen even in the middle of a turn. The former would really be better if that's acceptable.
  • Happening during the transition to another passage would actually be preferable (the latter strikes me as potentially too jarring and the player might miss what they've done to trigger the sequence shift if it happens right in the middle of a passage.)
  • edited February 15
    There are—or will be—three ways you could handle this.

    Method 1. Check the passage name in a prehistory/predisplay task or the PassageReady special passage and force navigation to another passage. (disrecommended)
    While I've seen people do this, I do not recommend this approach. It does not terminate the currently running navigation, so you're really just layering a new navigation on top. This can have consequences if the original navigation causes side-effects—e.g. variable modifications, etc. It also makes a hash of the history—which may or may not be an issue.

    Method 2. Choose the destination at the link site.
    Basically, you use a <<link>> to choose a destination, rather than having a hard coded one—it's also possible to do this with a wiki link if you use a function as a passthrough, but Twine 2's automatic passage creation ruins that method.

    For example:
    → Normally
    [[Go to Carol's house|Carol's House]]
    
    → With Variable Monitoring
    <<link "Go to Carol's house">>
    	<<if $darkPower gt 100>>
    		<<set _followup to "Carol's House">>
    		<<goto "Dark Power Overflow">>
    	<<else>>
    		<<goto "Carol's House">>
    	<</if>>
    <</link>>
    
    The downside to this is that if you need to do this everywhere, all of your links become complex.


    Method 3. Use the new Config.navigation.override callback (will be introduced in v2.13.0) to override the pending navigation destination.
    The callback takes one parameter, the original passage name. If its return value is falsy, the override is cancelled and navigation to the original destination continues unperturbed. If its return value is truthy, the override succeeds and that value is used as the new destination of the navigation.

    For example:
    Config.navigation.override = function (passageName) {
    	if (State.variables.darkPower > 100) {
    		State.temporary.followup = passageName;
    		return "Dark Power Overflow";
    	}
    };
    


    NOTE: The _followup temporary variable I used within the examples for methods 2 & 3 is there to allow you to forward the player to their original destination after the event if you need to.


    EDIT: BTW, SugarCube v2.13.0 should be released within a day or two as of the date and time of this post.
  • The third option sounds like it might be what I want, but unfortunately that really goes entirely over my head and I'm not remotely sure how I'd implement it. I suppose I'll wait until the new version is out to give it a try, however.
  • I didn't know I needed a navigation override until I see it (almost) released here. TME, why do you keep anticipating users needs like this? Can't thank you enough.
  • Okay, now that I can see the documentation for the new function, let me make sure I get this right:
    Config.navigation.override = function (passageName) {
    

    passageName here refers to the new passage I want the player to be taken to when the threshold is reached, yes?

    If so, I'm confused here:
    if (State.variables.darkPower > 100) {
    		State.temporary.followup = passageName;
    		return "Dark Power Overflow";
    	}
    

    Specifically, what is return "Dark Power Overflow"; intended to refer to? From my terrible javascript skills it reads to me that if darkPower is greater than 100 you're taken to a passage titled "Dark Power Overflow," but I'm not sure what the first passageName is supposed to be if that's the case.

    I'll likely ignore State.temporary.followup = passageName; as I don't think it would be easy to capture where the player is when they trigger the effect, and I'm going for an impact akin to something like your wounds getting too high that you collapse unconscious; I wouldn't want the player to necessarily be able to pick up wherever they were right away and plan on taking them to a sequence of the game where they have to reduce/improve the negative stat until they can go back to normal again.
  • edited February 16
    mixvio wrote: »
    Okay, now that I can see the documentation for the new function, let me make sure I get this right:
    Config.navigation.override = function (passageName) {
    
    passageName here refers to the new passage I want the player to be taken to when the threshold is reached, yes?
    No. From the docs:
    The callback is passed one parameter, the original destination passage title.
    For example, if the following link is activated:
    [[Go to Carol's house|Carol's House]]
    
    The passageName parameter will be "Carol's House" when the callback is invoked.

    mixvio wrote: »
    If so, I'm confused here:
    	if (State.variables.darkPower > 100) {
    		State.temporary.followup = passageName;
    		return "Dark Power Overflow";
    	}
    
    Specifically, what is return "Dark Power Overflow"; intended to refer to? From my terrible javascript skills it reads to me that if darkPower is greater than 100 you're taken to a passage titled "Dark Power Overflow," […]
    Correct. If the callback returns a truthy value, which "Dark Power Overflow" happens to be, that value is used as the new destination passage title.

    mixvio wrote: »
    I'll likely ignore State.temporary.followup = passageName; as I don't think it would be easy to capture where the player is when they trigger the effect, […]
    That's exactly what that does. Well, depending on what you mean.

    Specifically, it captures where the player is supposed to be going, because that's what passageName records.

    To capture where the player actually was at the time they activated the link, you'd want to record the value of State.passage—or passage(). That probably seems counterintuitive, however, the callback is invoked before a new moment is created for the history, so at that point the player is still technically exactly where they were at the time they activated the link.

    For example: (using Twee notation)
    :: Path
    /* Set $darkPower to some value >100, so that the callback's condition will be true. */
    <<set $darkPower to 101>>\
    [[Go to Carol's house|Carol's House]]
    
    
    :: Carol's House
    /* Player is supposed to be sent here. */
    
    
    :: Dark Power Overflow
    /* Player is actually sent here, since $darkPower > 100. */
    
    When the player clicks on the "Go to Carol's house" link in the "Path" passage and the callback is invoked the following will be true:
    passageName    →  "Carol's House"
    State.passage  →  "Path"
    


    mixvio wrote: »
    […] and I'm going for an impact akin to something like your wounds getting too high that you collapse unconscious; I wouldn't want the player to necessarily be able to pick up wherever they were right away and plan on taking them to a sequence of the game where they have to reduce/improve the negative stat until they can go back to normal again.
    You should, obviously, do whatever your plans dictate. I simply wanted the example to show that you could capture where the player was supposed to be headed, via the link they activated, so that if the override event allowed them to continue on afterward, you'd know where to send them.
  • Sorry, I'm not getting it. In your example:
    Config.navigation.override = function (passageName) {
    	if (State.variables.darkPower > 100) {
    		return "Dark Power Overflow";
    	}
    };
    

    is passageName something I have to replace myself? If so that's probably not going to do what I am after because the point of this is that it kicks in wherever the player is, whatever they're doing and overrides their progression. Not at hard-coded places. Unless I'm completely misunderstanding, which is also very likely!

    As is I put that code in and got an error of "Error [tw-user-script-0]: Cannot set property 'override' of undefined." so I'm assuming I'm doing something wrong.
  • edited February 16
    mixvio wrote: »
    As is I put that code in and got an error of "Error [tw-user-script-0]: Cannot set property 'override' of undefined." so I'm assuming I'm doing something wrong.
    That code will only work in the new v2.13.0 release of SugarCube 2, and that error message will occur for any previous version.

    If you need v2.13.0 you can download a copy from the SugarCube 2 website, the instructions on how to add it to your Twine 2 application can also be found there.
  • edited February 16
    I do have 2.13.0 installed and it's what is being used at least according to twine.

    ETA: Just deleted and redownloaded/reinstalled it so it's definitely being used as far as I can tell, still no dice.
  • Can you do the following check for me, use the Publish to File option to create a story HTML file and open that HTML file within a text editor. Near the top of the file should be some text that read something like the following:
    SugarCube (v2.x.y): A free (gratis and libre) story format, based on TiddlyWiki.
    ... where x and y are two numbers. Are those two numbers 13 and 0, or are they something else like 12 and 1.

  • edited February 16
    That's rather interesting, it says SugarCube (v2.12.1). I installed 2.12.2 when that came out a few weeks ago and now 2.13.0 today but it doesn't seem to be using it.

    ETA: I quit and relaunched Twine and it went from 2.13.0 being active to 2.12.1. Bug?
  • edited February 16
    mixvio wrote: »
    Sorry, I'm not getting it. In your example:
    Config.navigation.override = function (passageName) {
    	if (State.variables.darkPower > 100) {
    		return "Dark Power Overflow";
    	}
    };
    
    is passageName something I have to replace myself?
    No. When the callback you assign to Config.navigation.override is called by the navigation process, it passes the intended destination passage in via the passageName parameter, so that your callback may have that information available to it.

    mixvio wrote: »
    As is I put that code in and got an error of "Error [tw-user-script-0]: Cannot set property 'override' of undefined." so I'm assuming I'm doing something wrong.
    mixvio wrote: »
    That's rather interesting, it says SugarCube (v2.12.1). I installed 2.12.2 when that came out a few weeks ago and now 2.13.0 today but it doesn't seem to be using it.

    ETA: I quit and relaunched Twine and it went from 2.13.0 being active to 2.12.1. Bug?
    I think I know what's going on here. Let me send you a PM.

    I'll also open an issue on Twine 2's issue tracker.
  • I think I know what's going on here. Let me send you a PM.

    I'll also open an issue on Twine 2's issue tracker.

    Perfect, after following your workaround this works perfectly and looks like it's exactly what I am after. Thank you!
  • edited February 17
    Thanks a lot for that new feature. I have tested it to make the player win after picking all the treasures and it works perfectly. You offered a very nice and simple way to do that kind of things.
    /*! Passage Override en cas de victoire */
    Config.navigation.override = function (passageName) {
    	if (State.variables.animaux == State.variables.max_animaux) {
    	   return "victoire";
    	}
    };
    
  • mixvio wrote: »
    As is I put that code in and got an error of "Error [tw-user-script-0]: Cannot set property 'override' of undefined." so I'm assuming I'm doing something wrong.
    mixvio wrote: »
    That's rather interesting, it says SugarCube (v2.12.1). I installed 2.12.2 when that came out a few weeks ago and now 2.13.0 today but it doesn't seem to be using it.

    ETA: I quit and relaunched Twine and it went from 2.13.0 being active to 2.12.1. Bug?
    I think I know what's going on here. Let me send you a PM.

    I'll also open an issue on Twine 2's issue tracker.
    Just an update, this should be fixed in the next release of Twine 2.
Sign In or Register to comment.