Howdy, Stranger!

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

[Sugarcube 2.13.0] Passing arguments and widgets calling widgets

edited February 2017 in Help! with 2.0
Hey there,

I come to you with another problem that I ran into.
I'm running SugarCube 2.13.0 and Twine 2.1.0

The issue is the following, I'm trying to implement a way in which the player can interact with the inventory of other objects in the game, by placing and taking items from their containers. I'm basically listing the items inside the player's and the inspected container's contents (items) and then offer actions that can take place on the given object. Such as moving items back and forth, inspecting item properties, etc.

I'm trying to do this using a <<widget>> which calls another <<widget>>. I've tested and been using recursive <<widget>> which had no problems whatsoever (probably because of the same arguments that get passed to them).
In my case I fail to pass the _item object to <<putItemInContainer>>. Since the latter throws an error that .hasOwnProperty of an undefined variable made the whole thing crash and burn. This is very interesting to me since, the other widgets have never been complaining. I imagine the for loop and the temporary _i (iterator value) adds a complication. I'm trying to remedy this by setting up a temporary variable: _item and reference the indexed item ($player.inventory[_i]). This also doesn't seem to help in this case.

I tried to substitute the <<putItemIntoContainer>> widget by taking out the part that was important to me with the hasOwnProperty check and then the calling of other widgets such as unequip and JS function call to transfer the item into the new container. Now, this substitution kinda fails too since I only get the last item that is then put into the container after the second try, which I can't take out, since the wrong item gets put into the container.

There must be a way to call transfertItem() using the correct arguents (_item) I just have no idea how.

Can anyone explain to me what is going on here?
Am I missing something when passing arguments to another widget?
@
		  <</if>>
	<</linkreplace>>
<</nobr>><</widget>>
@color:red;[Error]putItemIntoContainer arg[0] or item is undefined@@
		<</if>>
	<</if>>
<</nobr>><</widget>>

Comments

  • All of your current problems seem to stem from an incorrect understanding of how temporary variables work. With the sole exceptions of having a lifetime of one turn/moment and not becoming part of the story history, temporary variables have exactly the same semantics as story variables. Meaning, you cannot assign a new value to a variable, temporary or story, and expect it to be able to yield its original value. That's exactly what you're attempting to do here with predicable, and unfortunate, results.


    You're reassigning _item every loop iteration, which wouldn't be an issue under normal circumstances. The <<putItemIntoContainer>> call, however, happens asynchronously—being inside a <<linkreplace>>. Thus, by the time the player activates any of the generated <<linkreplace>> links, the _item temporary variable is at the last value it was assigned within the loop—unless something else has reassigned it since.

    Speaking of something else trampling _item's value, you also reassign it within <<putItemIntoContainer>>.

    You may have a similar problem with _container if you ever make multiple calls to <<openContainer>> within the same passage. The final call will be the one to define the value assigned to _container. If you only make one call or make the calls asynchronously, then you should be okay, elsewise….


    The easy fix for <<putItemIntoContainer>> is to make its item variable unique—e.g. _piic_item or something like that.

    As for <<openContainer>>. If you were passing in primitive types, then you could use the Stupid Print Trick™ to address the <<linkreplace>> issue by causing the value to be resolved early, however, you're passing objects, so that's out. There is, unfortunately, no convenient solution at present—at least off the top of my head. Solving this will likely require me to implement some kind of capture mechanism.
  • I see. At least I know what is really the problem with temporary variables. I never really understood how they affect my code, but now it starts to become clear.

    Thank you for your valuable input, I always appreciate them!
  • FYI. I've implemented the necessary plumbing and a new macro to allow capturing the values of story and temporary variables into, essentially, a local scope. It should be in the next release.

    For example, the following should work as you'd expect:
    <<for _i = 0; _i < $player.inventory.length; _i++>>
    	<<set _item to $player.inventory[_i]>>
    	_item.name &times; _item.count
    	<<showItem _item>>
    	<<inspectItem _item>>
    	<<debugItem _item>>
    	<<capture _item>>
    		\<<linkreplace "Put _item.name in here">>
    			\<<putItemIntoContainer $player.inventory _container _item>>
    		\<</linkreplace>>
    	\<</capture>>
    <</for>>
    
    NOTE: Macro name not finalized.
  • Thanks man! I'll make sure to try this out once SugarCube gets updated!

    I assume calling a JS function inside the same widget (openContainer) which (JS function) has _item declared inside but used for other purposes would also be affected. Is this correct or am I overthinking it?
  • WILL YOU Document this new macro?
  • Disane wrote: »
    I assume calling a JS function inside the same widget (openContainer) which (JS function) has _item declared inside but used for other purposes would also be affected. Is this correct or am I overthinking it?
    There really aren't sufficient details there for me to say.

    WILL YOU Document this new macro?
    I document all of SugarCube's macros. I'm honestly surprised there was even a question.
  • edited February 2017
    Actually, don't get too excited yet. :(

    My initial implementation was a bit too simple and it remains to be seen if I'll be able to make this work. The core systems really aren't designed to support something like this, so I'm waging an uphill battle.
  • Okay. Situation resolved I believe, so back on track for the next release.
  • I'm having trouble upgrading to SC2.14 from SC2.13, see my question about it. Twine 2.1 would not let me add SC2.14 as a new story format, since SC2.12 is already installed in Twine 2.1 by default.
  • Disane wrote: »
    ...see my question about it.
    I posted a comment about this problem in the other thread.
  • @TheMadExile : hey, I tried SugarCube 2.14's <<capture>> but I still only get the last item listed for taking:
    @
    		<</if>>
    	<</linkreplace>>\
    <</widget>>\
    

    I tried to capture _i and even tried _item (using <<set>>)
  • I tested the version of SugarCube v2.14.0 that comes with Twine 2 v2.1.1—to ensure that I hadn't buggered the release up somehow—and all of the shadowing/<<capture>> tests passed. Assuming that's the version you're using, it should be working as intended.

    As far as your example code goes. Nothing immediately jumps out as incorrect with how you're attempting to use <<capture>> within that one widget, however, I cannot say that you're not modifying the value of _item within the <<transferItem>> widget as you didn't provide an example of its code—I bring that up, because you were trampling its value in earlier examples.

    Beyond that, the second use of <<capture>>, where you localize _i, could be problematic if <<transferItem>> alters the source/destination arrays themselves—if you alter the arrays, you will likely invalidate the captured indices at some point. You should probably be capturing the array member there, rather than its index, as you do with the first use of <<capture>>.
  • edited March 2017
    Hey @TheMadExile

    About the the code you requested: I would like to add, that I don't really want to reveal more source code now or in the future. The reason for that is source code tracking, that I really want to avoid when it comes to my Twine projects.

    From what I've understood, you are saying that I should look for clues inside my
    <<transferItem $source_container $destination_container $item>>
    
    JS code whether the passed temporary variables: _item or _i are being changed there. As soon as I have access to my computer, I'll let you know, if I've found any traces of this.
  • Disane wrote: »
    ... I don't really want to reveal more source code now or in the future. The reason for that is source code tracking...
    I am assuming that you're aware that anyone that plays your released game in a web-browser has complete access to the game's source code, that it is a trivial process to convert your Story HTML file back into a Story Project, and that it is not unusable for interesting code/techniques from one game to eventually appear in another.
  • edited March 2017
    Yes, I understand that @greyelf. I've been researching methods to obfuscate and/or encrypt the code and unpack it at run-time to avoid this. My concern is privacy related and has nothing to do with fear of other people reverse engineering and re-using my code.

    As soon as I can get back to my comp. I'll post some code. Don't get me wrong, I'm not trying to hide my "crappy" code from anyone, I just don't want people to connect it to me in any way.
  • Hey I did not forget about what I promised:
    By looking at my code, I could not find any problems. I even tried your suggestion of using the "Stupid Speed Trick" tm you suggested, which worked nicely after your help, that is :D

    I'll try and break down the problem into a much simpler one like I did with the jquery.append() jquery.wiki() trouble that I had. I'll come back to you with the results soon.

    Also I think @TheMadExile deserves a reward from me :)
  • Stupid Print Trick™ *** worked. Now, onto testing capture in SC 2.15
Sign In or Register to comment.