Howdy, Stranger!

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

Mimicking Recipes

So, I'm writing a game where you are making dinner. You have 9 ingredients, and may choose two. There are then many branching paths (though obviously not a full 81 or whatever) from there. I'm having trouble figuring out an elegant way to do the very beginning - coding that initial set of choices. I know if worst comes to worst, I could brute force it and make like 81passages (First choice meat, and then first choice meat, second choice lettuce, first choice meat, second choice bread, etc), but I know there must be a more elegant and simpler way to do this. I've read about variables and expressions, and I have some very basic experience in coding with BASIC and the long-dead Adobe Director program (anyone else remember that?), but I can't seem to figure out exactly what to do. My first thought is to use checkboxes, but I'd have to find a way to limit the choice. And then, I haven't been able to find a more comprehensive guide for writing that kind of code to go with it. I've read the wiki, but I haven't been able to find exactly what I'm looking for.

Specifically, can I write something so after the two checkboxes are checked, then Meal=M,O if Meat and Oil are chosen for example, and then the game code goes "If Meal=MO or OM, goto Steak, if Meal=MP or PM then goto Spaghetti", that kind of thing? And if limiting checkboxes aren't an option, what recourses do I have? Would having two pages with radio buttons work better/easier? Any help is much appreciated.

Wait, like, could I have one page for the first ingredient, then the next page is missing/hiding that ingredient, and then the next page adds the two choices together to goto the appropriate passage? Thanks!

Comments

  • edited June 2015
    I'd group the ingredients together by type, so meats go in their own passage, and vegetables in another etc.

    With each ingredient when you add it set a variable that gets checked later on.

    Using "if" statements you can do everything you want to do.
  • The following is a very basic example of one way you could do what you want.

    It consists of four passages: "Select From Ingredients", "Show Possible Ingredient Choices", "Made Choice", and "Make Meal" as well as some Javascript that you will need to add to your Story Javascript area.

    1. The Javascript: this potentially adds two methods to the standard array object to make it easier to find and delete an element from an array.
    The first method allows us to find an element within an array, some older web-browser may not have this method built-in.
    The second method allows us to delete an element from an array and uses the first method to find it.
    /* MDN Polyfill */
    if (!Array.prototype.indexOf) {
    	Array.prototype.indexOf = function(searchElement, fromIndex) {
    		var k;
    
    		if (this == null) {
    			throw new TypeError('"this" is null or not defined');
    		}
    
    		var O = Object(this);
    
    		var len = O.length >>> 0;
    
    		if (len === 0) {
    			return -1;
    		}
    
    		var n = +fromIndex || 0;
    
    		if (Math.abs(n) === Infinity) {
    			n = 0;
    		}
    
    		if (n >= len) {
    			return -1;
    		}
    
    		k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
    
    		while (k < len) {
    			if (k in O && O[k] === searchElement) {
    				return k;
    			}
    			k++;
    		}
    		return -1;
    	};
    }
    
    if (!Array.prototype.removeElement) {
    	Array.prototype.removeElement = function(element) {
    		if (this == null) {
    			throw new TypeError('"this" is null or not defined');
    		}
    
    		var i = this.indexOf(element)
    		if (i != -1) {
    			this.splice(i,1);
    		}
    		return this;
    	};
    }
    

    2. The four passages:
    note: "Select From Ingredients" is the first passage in my story.

    a. Select From Ingredients
    {
    <!-- Setup the list of possible ingredients: -->
    (set: $ingredients to (array: "ingredient1", "ingredient2", "ingredient3", "ingredient4", "ingredient5", "ingredient6", "ingredient7", "ingredient8", "ingredient9"))
    
    <!-- Setup the list of selected ingredients: -->
    (set: $selected to (array:))
    }
    
    |options>[(display: "Show Possible Ingredient Choices")]
    

    b. Show Possible Ingredient Choices
    This passage displays each of the possible Ingredient that the reader can choose from, it will only show a link for items that can still be selected.
    Choose some ingredients:
    (set: $choice to "")
    (if: $ingredients contains "ingredient1")[(link: "ingredient1")[(set: $choice to "ingredient1")(display: "Made Choice")]]
    (if: $ingredients contains "ingredient2")[(link: "ingredient2")[(set: $choice to "ingredient2")(display: "Made Choice")]]
    (if: $ingredients contains "ingredient3")[(link: "ingredient3")[(set: $choice to "ingredient3")(display: "Made Choice")]]
    (if: $ingredients contains "ingredient4")[(link: "ingredient4")[(set: $choice to "ingredient4")(display: "Made Choice")]]
    (if: $ingredients contains "ingredient5")[(link: "ingredient5")[(set: $choice to "ingredient5")(display: "Made Choice")]]
    (if: $ingredients contains "ingredient6")[(link: "ingredient6")[(set: $choice to "ingredient6")(display: "Made Choice")]]
    (if: $ingredients contains "ingredient7")[(link: "ingredient7")[(set: $choice to "ingredient7")(display: "Made Choice")]]
    (if: $ingredients contains "ingredient8")[(link: "ingredient8")[(set: $choice to "ingredient8")(display: "Made Choice")]]
    (if: $ingredients contains "ingredient9")[(link: "ingredient9")[(set: $choice to "ingredient9")(display: "Made Choice")]]
    
    Currently selected ingredients:
    $selected
    

    c. Made Choice
    This passage first removes the selected ingredient from the array of possibles, then adds the selected ingredient to the array of selected. It also checks to see if enough ingredients have been selected (2), if they haven't then the reader gets to choose another ingredient otherwise they are moved to the next passage.
    {
    (set: $dummy to $ingredients.removeElement($choice))
    (set: $dummy to $selected.push($choice))
    (set: $choice to "")
    
    <!-- Has the reader selected enough items? -->
    (if: $selected's length is 2)[(goto: "Make Meal")]
    (else:)[(replace: ?options)[(display: "Show Possible Ingredient Choices")]]
    }
    

    d. Make Meal
    This passage is where you check which ingredients the reader has selected and show which meal they made.
    One of the issues you had in your example "If Meal=MO or OM" was because you don't know which order the reader will choose the two ingredients you had to check for two values ("ingredient1ingredient2" or "ingredient2ingredient1"), you can get around this by sorting the selected items before joining the two together to form your "value".
    {
    <!-- sort the selected items and then join them to make a string. -->
    (set: $have to $selected.sort().join(""))
    debug: you have $have
    }
    
    You can make:
    (if: $have is "ingredient2ingredient7")[Meal 1]
    (elseif: $have is "ingredient4ingredient5")[Meal 2]
    (else:)[A mess!]
    

    I hope all the above makes some sense.
  • edited June 2015
    Define a cookbook in StoryInit:
    <<set $cookbook to { 
           Meat_Oil: { name: "Steak", goto: "P5" },
           Meat_Pasta: { name: "Spagetti", goto: "P7" },
           Seafood_Oil: { name: "Fish", goto: "P9" },
           Seafood_Rice: { name: "Paealla", goto: "P12" },
    }>>
    

    Probably also an idea to set up a nice naming index for the ingredients:
    <<set $stock to [ "Meat", "Oil", "Seafood", "Pasta", "Rice" ]>>
    

    Then some variables to track your ingredients:
    <<set $choice_count to 0>>
    <<set $choice to [-1, -1]>>
    

    Then in the page where they pick their ingredients:
    <<nobr>>
    <<if choice_count lt 2>><br>Pick you ingredients:
    <<if $choice[0] neq -1>><br><<print $stock[choice[0]] + " and:">><<endif>>
    <<if $choice[0] neq 0>><br>[[<<$stock[0]>>|passage()][$choice[choice_count] to 0;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 1>><br>[[<<$stock[1]>>|passage()][$choice[choice_count] to 1;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 2>><br>[[<<$stock[2]>>|passage()][$choice[choice_count] to 2;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 3>><br>[<<$stock[3]>>|passage()][$choice[choice_count] to 3;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 4>><br>[[<<$stock[4]>>|passage()][$choice[choice_count] to 4;$choice_count += 1]]<<endif>>
    <<else>>
    <<if choice[1] gt choice[2]>><<set $temp to $choice[0];$choice[0] to $choice[1];$choice[1] to $temp>><<endif>>
    <br>You chose <<$stock[choice[0]]>> and <<$stock[choice[1]]>>.
    <<set $key to stock[choice[0]] + "_" + $stock[choice[1]]>>
    <<set $meal to $cookbook[$key]>>
    <<if $meal eq null>><<set $meal to { name: "something disgusting", goto: "P15" }>><<endif>>
    <<print "<br><br>[[You make " + $meal.name + "|" + $meal.goto + "]]">>
    <<endif>>
    <<endnobr>>
    

    Only thing to watch is that you have to define the ingredients in the index for the cookbook with the lowest choice value item first. If you want Oil_Meat to be different from Meat_Oil you'd need to take out the line that swaps the choice values if your second choice is lower than your first one and ensure you had all combinations defined. As it is, you need only define the combination where the lowest value item is picked first.

    And you broken the JSON variables in Harlowe why?
  • edited June 2015
    @mykael: did you actually test your suggestion or was there a problem with cut-n-paste/posting?

    I ask because a number of your variables are missing dollar signs:
    <<nobr>>
    <<if $choice_count lt 2>><br>Pick you ingredients:
    <<if $choice[0] neq -1>><br><<print $stock[$choice[0]] + " and:">><<endif>>
    <<if $choice[0] neq 0>><br>[[<<$stock[0]>>|passage()][$choice[$choice_count] to 0;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 1>><br>[[<<$stock[1]>>|passage()][$choice[$choice_count] to 1;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 2>><br>[[<<$stock[2]>>|passage()][$choice[$choice_count] to 2;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 3>><br>[[<<$stock[3]>>|passage()][$choice[$choice_count] to 3;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 4>><br>[[<<$stock[4]>>|passage()][$choice[$choice_count] to 4;$choice_count += 1]]<<endif>>
    <<else>>
    <<if $choice[1] gt $choice[2]>><<set $temp to $choice[0];$choice[0] to $choice[1];$choice[1] to $temp>><<endif>>
    <br>You chose <<$stock[$choice[0]]>> and <<$stock[$choice[1]]>>.
    <<set $key to $stock[$choice[0]] + "_" + $stock[$choice[1]]>>
    <<set $meal to $cookbook[$key]>>
    <<if $meal eq null>><<set $meal to { name: "something disgusting", goto: "P15" }>><<endif>>
    <<print "<br><br>[[You make " + $meal.name + "|" + $meal.goto + "]]">>
    <<endif>>
    <<endnobr>>
    

    Once I added the missing dollar signs the list appears like:
    Pick you ingredients:
    <<$stock[0]>>
    <<$stock[1]>>
    <<$stock[2]>>
    <<$stock[3]>>
    <<$stock[4]>>

    And if I select a second item I get the following error, though that could be due to my adding missing dollad signs to your variables:
    Error: macro <<$stock[$choice[0]]>> does not exist

    Does your suggestion handle the situation of a Reader using the web-browser's Back button?
  • edited June 2015
    Typed straight into the forum ;-(

    The back button should work - it's just reversing a passage transition.
  • Since, AFAIK, we're talking about Twine 2 here (the thread is in the 2.0 category), then the angle-bracket markup could only be used with SugarCube. And SugarCube doesn't support what you're trying to do here.

    Wiki links like this are the problem:
    [[<<$stock[0]>>|passage()][$choice[$choice_count] to 0;$choice_count += 1]]
    

    If you were trying to use the horrible shorthand syntax for the <<print>> macro (e.g <<$foo>>), then it is not and will never be supported by SugarCube. You don't need it there anyway, because SugarCube's handling of the optional text portion of the wiki link markup () is different from the Twine 1 vanilla story formats. So, instead, it should be something like the following:
    [[$stock[0]|passage()][$choice[$choice_count] to 0;$choice_count += 1]]
    

    Otherwise, if you were trying to print literal double angle-brackets (<<, >>), then you'd do so like you would inside a call to <<print>>. For example, it should be something like the following:
    [["<<" + $stock[0] + ">>"|passage()][$choice[$choice_count] to 0;$choice_count += 1]]
    

    Basically, the Twine 1 vanilla story formats treat the link and optional text portions differently (the former as either plain-text or TwineScript code, and the latter as wiki-text). SugarCube (in Twine 1 or 2), on the other hand, treats both the same, as either plain-text or TwineScript code.
  • edited June 2015
    Well, I normally code for Twine 1.4.2 sugercane - guess it might be time to look at Twine 2 with Sugarcube.

    Just needed a few $ and a fix to the not found in cookbook check to get it working:
    <<nobr>>
    <<if $choice_count lt 2>><br>Pick you ingredients:
    <<if $choice[0] neq -1>><br><<print $stock[$choice[0]] + " and:">><<endif>>
    <<if $choice[0] neq 0>><br>[[<<print $stock[0]>>|passage()][$choice[$choice_count] to 0;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 1>><br>[[<<print $stock[1]>>|passage()][$choice[$choice_count] to 1;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 2>><br>[[<<print $stock[2]>>|passage()][$choice[$choice_count] to 2;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 3>><br>[[<<print $stock[3]>>|passage()][$choice[$choice_count] to 3;$choice_count += 1]]<<endif>>
    <<if $choice[0] neq 4>><br>[[<<print $stock[4]>>|passage()][$choice[$choice_count] to 4;$choice_count += 1]]<<endif>>
    <<else>>
    <<if $choice[1] gt $choice[2]>><<set $temp to $choice[0];$choice[0] to $choice[1];$choice[1] to $temp>><<endif>>
    <br>You chose <<$stock[$choice[0]]>> and <<$stock[$choice[1]]>>.
    <<set $key to $stock[$choice[0]] + "_" + $stock[$choice[1]]>>
    <<set $meal to $cookbook[$key]>>
    <<if $meal eq 0>><<set $meal to { name: "something disgusting", goto: "P15" }>><<endif>>
    <<print "<br><br>[[You make " + $meal.name + "|" + $meal.goto + "]]">>
    <<endif>>
    <<endnobr>>
    

    See here for a live version.

Sign In or Register to comment.