Howdy, Stranger!

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

If variable is not equal...

Hello. I'm having problems with showing hook if variable is NOT equal to something. The code I'm using is
(if: $a is not "")[ Variable `$a` is not empty, instead it's $a!
[[Hooray!]] ]
Of course it was anonymized. Instead of "is not" I've tried "not is" "not =" "= not" - nothing works. Any help?

Comments

  • (if: $var != 100)[Variable is not 100.]
  • Thanks.

    //edit: Doesn't work. Either some bug or doesn't work for string variables.
  • Scratch that, I think my variable is not updating altogether.

    I've put at very end of passage $a for debug purposes and it doesn't update. I'm changing the variable using (click:) hooks, e.g (click ?paragraph)[(set: $a to "asdf")] and it doesn't update it.
  • When your supply code as an example you should mark it using the "Insert Code" feature on the tool bar, the button has a # on it.

    1. You should assign a value to your variables before you compare their value using the (if:) macros

    2. The (click:) macro in your second example is missing the colon after the word 'click', it should be as follows:

    (click: ?paragraph)[(set: $a to "asdf")]
    3. The (click:) macro is meant to be used with a "Named hook". I'm not sure if you are doing that but your 2nd example did not include one, but it would look something like the following:

    [This hook is named 'paragraph']<paragraph|
    (click: ?paragraph)[(set: $a to "asdf")]
    4. Variables set within (click:) macros only change value after the related hook is clicked on, as demostrated in the following:

    (set: $var to "A")
    [`$var` equals $var, click on this hook to change its value]<changevar|

    (click: ?changevar)[
    (set: $var to "B")
    (replace: ?changevar)[`$var` new value is $var]
    ]
  • greyelf wrote:

    When your supply code as an example you should mark it using the "Insert Code" feature on the tool bar, the button has a # on it.

    1. You should assign a value to your variables before you compare their value using the (if:) macros

    2. The (click:) macro in your second example is missing the colon after the word 'click', it should be as follows:

    (click: ?paragraph)[(set: $a to "asdf")]
    3. The (click:) macro is meant to be used with a "Named hook". I'm not sure if you are doing that but your 2nd example did not include one, but it would look something like the following:

    [This hook is named 'paragraph']<paragraph|
    (click: ?paragraph)[(set: $a to "asdf")]
    4. Variables set within (click:) macros only change value after the related hook is clicked on, as demostrated in the following:

    (set: $var to "A")
    [`$var` equals $var, click on this hook to change its value]<changevar|

    (click: ?changevar)[
    (set: $var to "B")
    (replace: ?changevar)[`$var` new value is $var]
    ]


    Well, code was anonymized as I don't want to spoil my story. There are, of course, named hooks there. But the issue is that when I update variable within the click macro, all instances of $a in story should change and ifs should be recalculated. Example:
    Jack like apples. How many apples do you want to give to Jack?
    * |one>[One apple]
    * |two>[Two apples]
    * |three>[Three apples]

    Jack has $jackapples now.

    (click: ?one)[(set: $jackapples to $jackapples + 1)]
    (click: ?two)[(set: $jackapples to $jackapples + 2)]
    (click: ?three)[(set: $jackapples to $jackapples + 3)]

    (if: $jackapples = 6)[And now you have no apples left `:(`]
  • When you write something like "Jack has $jackapples now." the variable's value is determine just before the passage is displayed and that value is what is inserted into the generated output the user sees, this is why the (set:) macros within the (click:) macros are not changing the "Jack has x now" text.

    If you want the text to change try the following:

    Jack like apples. How many apples do you want to give to Jack?
    * |one>[One apple]
    * |two>[Two apples]
    * |three>[Three apples]

    [Jack has $jackapples now.]<msg|

    (click: ?one)[(set: $jackapples to $jackapples + 1)(replace: ?msg)[Jack has $jackapples now.]]
    (click: ?two)[(set: $jackapples to $jackapples + 2)(replace: ?msg)[Jack has $jackapples now.]]
    (click: ?three)[(set: $jackapples to $jackapples + 3)(replace: ?msg)[Jack has $jackapples now.]]
    A similar thing happens with (if:) macros, the expression is evaluated as the output is being generated. It is not re-evaluated each time the variable changes, and this is the same way Twine 1 story formats work.
  • On the original topic, in Harlowe I've had best luck using "unless" and "is." == and != don't always work as I intend (or didn't at one point), but
    (unless: $weapon is "")[I am wielding my trusty $weapon!]
    tends to work pretty reliably.

    Note that uninitialized Twine variables evaluate to 0, not "", so if you haven't ever set $weapon, you'll get "I am wielding my trusty 0!"

    If you want to check whether a variable has been initialized, you can use something like:
    (if: $weapon)[Good thing I have a weapon.]
    or:
    (unless: $weapon is 0)[Good thing I have a weapon.]
    (I don't know which one would be considered "conventional" in Twine, but the difference is stylistic, not functional.)

    Regarding the question of updating ?msg, I've been wondering if there's some way of redisplaying a hook without changing its text. I think right now the best way to deal with this is re-set the text each time the user clicks something, but I'm not sure what the most readable/efficient way of doing this is (there are several ways that work, I'm just not sure which one is 'best').
  • It is a general programming principle and a good idea to initialize all your variables to their default values at the start of your story/game instead of relying on the story format to assign a value for you.

    The current version of Harlowe defaults all unassigned variables the value of zero, who's to say this won't be changed for some technical reason in the future.
  • Agreed on the best practice being to initialize everything before using it. But I don't like to initialize at story start due to it prevents debugging from a specific passage. Instead, I prefer an initialization script that can be run at top of any page, which relies on a bunch of this sort of thing:

    (unless $var:)[(set: $var to "$var's initial value")]

    Obviously, that's relying on Harlowe's defaulting unassigned variables to something that evaluates to false. Unfortunately, any alternative (e.g. using an equivalent of a #ifndef preprocessor directive) also relies on that property.

    I don't know what an alternate best practice would be that allows random access debugging (it strikes me as a bad idea to leave out the (unless) because that's just asking to forget to remove the initialization script from the place you're debugging). I was pondering this earlier today, but I didn't come up with anything.
  • This is why the Twine 1 story formats had the StoryInit special passage that always got called when your story started even when you asked it to display a particular passage at start-up.

    Using a variation of your idea you can do something similar with a bit of work using Harlow.

    1. Create a StoryInit passage and use it to setup the default values of your story's variables. Add to the end of this passage a variable named $initialized and give it the value of true. The passage would something like the following:
    (note: using open and close curly braces to suppress displaying of blank lines.)

    {
    (set: $item to "")
    (set: $weapon to "stick")

    (set: $initialized to true)
    }
    2. Add the following line of code to the top of any passage (including your main passage)) you want to debug.

    {(unless: $initialized)[(display: "StoryInit")]}
  • Yeah, that's about what I'm thinking. The one issue is that will fail in exactly the same circumstances as
    (unless: $weapon)
    because it still relies on uninitialized variables evaluating to false.

    I'm leaning toward testing (unless: $initialized) in the StoryInit passage, because that is a centralized location to change if for some reason that is no longer the case (there would have to be some other way to make sure the code only got run once).

    Sorry for the thread hijack Darkhog :)
  • Confession: I actually forgot to mention on the Twine 2 page that the equivalent of the "neq" operator in Twine 2 is "is not". You should, er, use that instead of !== etc.
Sign In or Register to comment.