Howdy, Stranger!

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

Inventory in Sugarcube 2

I'm using Twine 2, Sugarcube 2.18.0 and with my very basic understanding, I can't get an inventory to work.
I copied the code from the twine wiki from the following link:
https://twinery.org/wiki/twine2:add_an_inventory_system
In the Javascipt section, made passage named "StoryMenu" and put Inventory in it.
Made an Inventory passage and put
<<if $inventory.length == 0>>You do not have any belongings.<<else>>You are carrying:
<<invWithLinks>> <<endif>>
<<back>>
in it.
At my game start I put
<<initInv>>
<<if $inventory.indexOf("An Unsigned Note") == -1>>There is a note here. [[Pick up the note.]]<<endif>>
and made a passage called "Pick up the note." with
<<addToInv "An Unsigned Note">>\
You picked up the note.
<<back>>
in it.

Most of it seems to work, except that it does not add anything to the inventory, which in turn does not let me test if the "There is a note here. Pick up the note." disappears if you have "An Unsigned Note" in your inventory. Over the last 3 days I tried to find an answer on my own, even contemplated to only use variables and if statements to make it work but I just don't like the "dirty" way of doing it. I want it "future proof" if ever want to make another game that requires an inventory. I really spent enough time on it, for a feature that was not really needed or planed for my game and I would really appreciate if someone could point out what I am doing wrong.

Also, since don't know anything about java: Is it possible that you can make the first letter after a dash (-) uppercase? So it will not correct "Mary-Ann" to "Mary-ann"? With the current code it always auto corrects to lowercase:
<<set name to $name.trim()>>\
<<set $name to $name.toLowerCase()>>\
<<set $n to $name.charAt(0).toUpperCase()>>\
<<set $name to $name.slice(1)>>\
<<set $name to $n + $name>>\

Comments

  • I don't know how or why or where you're using that second chunk of code, so I can't really speak to that. For your original question, try changing <<back>> to <<return>>. The <<back>> macro walks the whole State back one step, which is likely undoing your variable changes.
  • Deviate wrote: »
    ....since don't know anything about java:
    The programming language you are using is Javascript not Java, they are two totally unrelated languages with unfortunately similar names.

    Deviate wrote: »
    Is it possible that you can make the first letter after a dash (-) uppercase? So it will not correct "Mary-Ann" to "Mary-ann"?
    You can use a Regular Expression to obtain each Word in your Sting value combined with the Javascript String.replace function to do what you want.

    Using the replace function directly on a String value would look something like the following:
    <<print "string value".replace(/\b\w+/g,function(s){return s.charAt(0).toUpperCase()+s.substr(1).toLowerCase();})>>
    
    ... but doing it that way is messy and could easily lead to errors.


    Instead you should create a custom function (eg. toProperCase()) to contain the complex part and then use that instead in your TwineScript code. There are two main places you can create that function depending on if you like extending Javascript's built-in objects or not.

    1. Extending SugarCube's setup object.

    Use code like the following to add a custom toProperCase() function to the setup object, this code is placed within the story's Story Javascript area.
    /*
    	Returns a string the first letter of each word converted to uppercase and the other letters in each word converted to lower case.
    */
    if (! setup.toProperCase) {
    	setup.toProperCase = function(value) {
    		if (value == null) {
    			throw new TypeError('setup.toProperCase called with a null or undefined value');
    		}
    		
    		return value.replace(/\b\w+/g,
    				function(s){
    					return s.charAt(0).toUpperCase() +
    						s.substr(1).toLowerCase();
    				});
    	};
    }
    
    ... and you use the setup.toProperCase() function in your passage like so:
    <<set $name to "mary-ann was here">>
    before: $name
    
    <<set $name to setup.toProperCase($name)>>
    extending setup: $name
    


    2. Extending Javascript's String prototype.

    Use code like the following to add a custom toProperCase() function to the Javascript String prototype, this code is placed within the story's Story Javascript area.
    /*
    	Returns a string the first letter of each word converted to uppercase and the other letters in each word converted to lower case.
    */
    if (!String.prototype.toProperCase) {
    	Object.defineProperty(String.prototype, 'toProperCase', {
    		configurable : true,
    		writable     : true,
    
    		value() {
    			if (this == null) {
    				throw new TypeError('String.prototype.toProperCase called on null or undefined');
    			}
    
    			return this.replace(/\b\w+/g,
    					function(s){
    						return s.charAt(0).toUpperCase() +
    							s.substr(1).toLowerCase();
    					});
    		}
    	});
    }
    
    ... and you use the <String>.toProperCase() function in your passage like so:
    <<set $name to "mary-ann was here">>
    before: $name
    
    <<set $name to $name.toProperCase()>>
    extending String: $name
    


    notes:
    a. The original Regular Expression example was obtain from this stackoverflow article.

    b. The structure of the String prototype extension example is heavily based on SugarCube's own extension of the same prototype.
  • Chapel wrote: »
    I don't know how or why or where you're using that second chunk of code, so I can't really speak to that. For your original question, try changing <<back>> to <<return>>. The <<back>> macro walks the whole State back one step, which is likely undoing your variable changes.
    Well, it says in the link I posted: "Starts your inventory. You need to call this once at the start of your game in order to make the inventory work." And I assume the second line lets the text and link disappear if "An Unsigned Note" is in your inventory.
    Sadly, <<return>> brings the same result as <<back>>.
  • edited June 2017
    Deviate wrote: »
    Also, since don't know anything about java: Is it possible that you can make the first letter after a dash (-) uppercase? So it will not correct "Mary-Ann" to "Mary-ann"?

    Is there a reason, why text-transform: capitalize won't work for you?

    Put into your stylesheet:
    p.capitalize {
        text-transform: capitalize;
    }
    

    And then you can just say:
    <p class="capitalize">marie-ann</p>
    

    and you will get Marie-Ann.

  • edited June 2017
    Deviate wrote: »
    Well, it says in the link I posted: "Starts your inventory. You need to call this once at the start of your game in order to make the inventory work." And I assume the second line lets the text and link disappear if "An Unsigned Note" is in your inventory.
    Sadly, <<return>> brings the same result as <<back>>.

    I meant the part at the bottom when I said 'second chunk,' but I honestly don't know what that does either.

    If that starts the inventory, then it probably resets it, right? Isn't that probably clearing your inventory every time you go to that passage? Put that in your StoryInit special passage.

    EDIT: You need to fix both these problems. I whipped up a test based on the code you provided, and the <<initInv>> macro empties the inventory array, so that's problem 1. Problem 2, the <<back>> macro undoes your <<addToInv>> macro, but <<return>> does not. If you fix both these things, it works fine.
  • idling wrote: »
    Deviate wrote: »
    Also, since don't know anything about java: Is it possible that you can make the first letter after a dash (-) uppercase? So it will not correct "Mary-Ann" to "Mary-ann"?

    Is there a reason, why text-transform: capitalize won't work for you?

    Put into your stylesheet:
    p.capitalize {
        text-transform: capitalize;
    }
    

    And then you can just say:
    <p class="capitalize">marie-ann</p>
    

    and you will get Marie-Ann.

    Note that this is great for output but it won't work for comparison of strings, so it depends on what you're doing with it.
  • edited June 2017
    Chapel wrote: »
    EDIT: You need to fix both these problems. I whipped up a test based on the code you provided, and the <<initInv>> macro empties the inventory array, so that's problem 1. Problem 2, the <<back>> macro undoes your <<addToInv>> macro, but <<return>> does not. If you fix both these things, it works fine.

    Yeah, that seems to have been the problem. It works now. Thanks.
    idling wrote: »
    Is there a reason, why text-transform: capitalize won't work for you?

    Well, it will show "jim" as "Jim" but checking if the character is called "Jim" will result in a "false". Because I need to check if the character has a certain name, that will not work for me.

  • edited June 2017
    Deviate wrote: »
    idling wrote: »
    Is there a reason, why text-transform: capitalize won't work for you?

    Well, it will show "jim" as "Jim" but checking if the character is called "Jim" will result in a "false". Because I need to check if the character has a certain name, that will not work for me.

    Fair enough. How about:
    <<widget "capitalize">><<nobr>>
    <<set $letters to []>>
    <<set $word to "">>
    <<for _i to 0; _i lt $args[0].length; _i++>>
    	<<set $letters.push($args[0][_i])>>
    	<<if _i === 0 or $letters[_i - 1] === "-" or $letters[_i - 1] === " " or $letters[_i - 1] === "_">>
    	<<set $letters[_i] to $letters[_i].toUpperCase()>>
    	<<else>>
    	<<set $letters[_i] to $letters[_i].toLowerCase()>>
    	<</if>>
    	<<set $word += $letters[_i]>>
    <</for>>
    <<print '<<set ' + $args[1] + ' to $word>>'>>
    <</nobr>><</widget>>
    

    And then:
    <<set $name to "marie-ann">>
    <<capitalize $name "$name">>
    
Sign In or Register to comment.