Howdy, Stranger!

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

Sugarcube - Sidebars and Save files

edited April 2015 in Help! with 2.0
Hi there! I'm pretty new to Twine and slowly figuring everything out, but I think it's coming along nicely. I do have two pretty big questions, though.

First:

Is there a way I can add (an) additional "side"bar(s) to Sugarcube and easily control what is in them on each page? For instance, to put dialogue options or action buttons at the bottom of the page in such a way that the passage text above them will scroll if too long but the bottom box is always visible? Or to have a right-aligned sidebar for enemy stats or the like while I have player stats in the default bar on the left? Could I, perhaps, even control whether or not these boxes appear on a given page?

Second:

How can I make the save game info display the Player's name in addition to the default information? And how do I change the gray (save slot empty) text? I've tried every combination of id and class elements that I can find associated with it but I'm sure I'm missing something. 8'|

-

Less a how-to and more a general curiosity question: if I have a save file and then add things to the StoryInit passage, will the new things load up on my old save, or does StoryInit activate at the beginning of the game only?

Comments

  • edited April 2015
    EDIT: Sorry for the random yellow highlighting and code messups. The forum is totally mangling the code and it refuses to display things in the sugarcube << >> format. But hopefully this gives you an indication of what you can do. Come back and check this passage after code markup gets fixed.

    StoryInit activates at start of the game. But you need to start the game to load the save in the first place, so you will be always activating StoryInit first.

    For a sidebar box, see the example code on the SugarCube website: http://www.motoslave.net/sugarcube/download.php/examples/example-rhs-box.zip

    There are several methods to display custom information in saves. If autosaves, the sugarcube website has a few examples. If you just want to specify your own custom text, one way is to put in your javascript config:
    config.altPassageDescription = true;
    
    This replaces the default save game titles with the passage title instead. So you then name the passage titles meaningfully.

    There is a way to customize save games based on player titles but it is rather involved and I don't have time to write it out and bug check it.

    However, it involves creating a separate Save Game passage that you link to based on if logic, then using the
    <<script>>UISystem.saves()<</script>>
    
    function to activate the save games dialog on that passage. E.g. If you wanted to link to a passage called John Save Game and put that code in the passage, the resulting save game would be called "John Save Game".

    However, you would also have to find a way to route around that passage so the player oesn't load into an infinite passage loop. The best way is to put your save game function in a separate options passage, and then use a popup to link to the save game passage. Popup code is something like:
    macros.add("popup", {
    	version: { major: 1, minor: 0, revision: 0 },
    	handler: function ()
    	{
    		if (this.args.length < 2)
    		{
    			var errors = [];
    			if (this.args.length < 1) { errors.push("link text"); }
    			if (this.args.length < 2) { errors.push("passage name"); }
    			return this.error("no " + errors.join(" or ") + " specified");
    		}
    
    		var el = document.createElement("a");
    		el.innerHTML = this.args[0];
    		el.className = "link-internal link-popup";
    		el.setAttribute("data-passage", this.args[1]);
    		UISystem.addClickHandler(el, null, function(evt) {
    			var dialog = document.getElementById("ui-body");
    			$(dialog)
    				.empty()
    				.addClass("dialog popup");
    			new Wikifier(dialog, tale.get(evt.target.getAttribute("data-passage")).processText().trim());
    			return true;
    		});
    		this.output.appendChild(el);
    	}
    });
    
    
    #ui-body.popup
    {
    	padding: 40px; 
    	color: #000;
    	max-width: 600px; 
     } 
    
    /* Links in the main passage */
    .link-popup
    {
    	color: #red; 
    }
    
    and the code to access it in passages is
    <popup "link name" "passage name">>
    

    So e.g. you might write
    <<popup "Save Game" "Save Game">>
    

    When the user clicks that link, they immediately open the save game dialog if the script is in Save Game. If the main passage which linked to the passage is John Save Game, that will be where the save is routed to, as SugarCube will not save games into popups (which is a good thing).

    There may be an easier solution, but this one works well for me. It also has the benefit of strictly controlling where the player is able to save. If you don't want them to save at a certain point, just redirect the link in the StoryCaption passage.

    You might e.g. write a link to your save game passages in StoryCaption, and then use
    #menu-saves, #menu-restart {
    	display: none;
    }
    
    To turn the default save game and restart options off.
  • edited April 2015

    @EssGee said:

    And how do I change the gray (save slot empty) text? I've tried every combination of id and class elements that I can find associated with it but I'm sure I'm missing something. 8'|

    The easiest way is after your story is published, open it in a html editor, search that text, and change it.

    Remember everything which gets displayed must be written down somewhere in the html file, so you can change anything in notepad, even passage content.

  • edited April 2015
    ✪▽✪ This is a fantastic macro in general and will help make several other things that were functional but a little awkward MUCH more fluid. Thank you so much!

    Passage titles would be difficult, unless there's a way to have buttons link to passage titles with spaces. Even then the person I'm working with and I both find it easier for organization to have less.. aesthetic titles, heh.

    What about the function variation of config.altPassageDescription though? Could I call variables defined within the game there, and if so could I get an example of the format? Like say I just wanted it to say "Name: " with the $name variable. How do I tell it to use that, or would I need to name it something more unique like "playername" rather than just "name", or?

    Alternatively, where/how could I use the SaveSystem.save() property?

    --

    And... sorry I'm so new to this but.. What would be the best way to view that .tws file? I looked at it in notepad and textpad but it... This is a small excerpt:
    sg15
    (lp101
    I10
    aI290
    asg17
    (itiddlywiki
    Tiddler
    p102
    (dp103
    g21
    VWait. Did the box just update?
    \u000a
    p104
    sg23
    VNext

    It's not... /supposed/ to look like that, right? So I figured rather than downloading a lot of other programs to test I'd just... ask what's the most recommended, heh.
  • edited April 2015
    You need to download Twine 1.4 and install the 1.4 SugarCube format to view that file.

    To use the SaveSystem(saves) function, you would put it in a script comment like:

    <<script>>SaveSystem.save(1, Hello)<</script>> and whenever the person lands on the passage with that script comment, it executes the script automatically and would save their position in slot 1 with save name "Hello".

    You could do something like have a popup containing <<script>>SaveSystem.save(1, Hello)<</script>> that the person can click and under that write "Your game is now saved!"

    Popups can link to popups and simply replace each other on screen so if you wanted you could even replicate the save game menu like that by having one popup with links to other popups containing that script for each slot.

    So eg:

    <<popup "Save Game" "Save List">>

    and in save list:

    <<popup "Save Game Slot 1" "Slot 1">>
    <<popup "Save Game Slot 2" "Slot 2">>
    <<popup "Save Game Slot 3" "Slot 3">>
    <<popup "Save Game Slot 4" "Slot 4">>


    And in the passage Slot 1 have:

    <<script>>SaveSystem.save(1, Hello)<</script>> Your game is now saved in slot 1!

    In passage Slot 2 write:

    <<script>>SaveSystem.save(2, Hello)<</script>> Your game is now saved in slot 2!

    And so on. You can do the same for load games using the SaveSystem.load(slot) function, but it's probably best to just use the normal saves menu you link to with to allow the player to view the save game names.

    E.g. write:

    <<popup "Load Game" "Load Games">>

    And in Load Games you'd have:

    <<script>>UISystem.saves()<</script>>

    And also do something like:

    display: none;

    in a css selector tag you apply for that popup passage so that the game does not display any popup but simply executes the script without bringing anything up on screen.

    E.g.
    .nodisplay
    {
    	display: none;
     } 
    

    And tag popup passages you want to be invisible to simply execute script functions with the nodisplay tag.
  • edited April 2015
    With my above popup code, it seems the forum's code formatting introduced a whole bunch of "\" into it which breaks it. This is the correct macro:

    macros.add("popup", {
    version: { major: 1, minor: 0, revision: 0 },
    handler: function ()
    {
    if (this.args.length < 2)
    {
    var errors = [];
    if (this.args.length < 1) { errors.push("link text"); }
    if (this.args.length < 2) { errors.push("passage name"); }
    return this.error("no " + errors.join(" or ") + " specified");
    }

    var el = document.createElement("a");
    el.innerHTML = this.args[0];
    el.className = "link-internal link-popup";
    el.setAttribute("data-passage", this.args[1]);
    UISystem.addClickHandler(el, null, function(evt) {
    var dialog = document.getElementById("ui-body");
    $(dialog)
    .empty()
    .addClass("dialog popup");
    new Wikifier(dialog, tale.get(evt.target.getAttribute("data-passage")).processText().trim());
    return true;
    });
    this.output.appendChild(el);
    }
    });
  • ^-^ No problem, I'd taken out all the slashes myself, but thank you for covering bases!

    That save UI thing sounds super great, and I do like the idea of separate load and save screens to reduce the risk of accidents (even if the default system seems really good for that factor too).

    How, though, can I make that display the save game data? Looking over the API it sounds like it would be the .get(slot) one but doing just script tags around that doesn't seem to display anything. Is that not the right thing or what would I need to do to make it work? Also, would that include the time and date like the default or how could I add that?


    Also, trying to use a variable as given in the example SaveSystem.save(5, "Midgar", $party)-- or in my case SaveSystem.save(0, "Name:", $name)-- is telling me that $name isn't defined. Why is that?
  • If you're worried about choosing slots, judging from the the API, you could use <<script>>if (SaveSystem.has(1)) {SaveSystem.save(1, Hello)}<</script>> to only save the game in slot one if the slot 1 is free.

    The $party in the example refers to metadata, but I am not sure what that is.
  • To access a variable in TwineScript you use the $variablename format, to access the same variable inside javascript you use state.active.variables.variablename when using the SugarCube story format as shown in the history API documentation.

    So SaveSystem.save(0, "Name:", $name) should be:
    SaveSystem.save(0, "Name:", state.active.variables.name)
    
  • greyelf wrote: »
    So SaveSystem.save(0, "Name:", $name) should be:
    SaveSystem.save(0, "Name:", state.active.variables.name)
    

    EEEK!! Thanks so much! :D And a string seems to work fine for the "title" part without getting into whatever metadata is.

    Claretta wrote: »
    If you're worried about choosing slots, judging from the the API, you could use <<script>>if (SaveSystem.has(1)) {SaveSystem.save(1, Hello)}<</script>> to only save the game in slot one if the slot 1 is free.

    No, I actually like the idea of being able to save over a file without having to manually delete it first, because while it presents a slight risk of accidents it also makes it much more convenient to save constantly in the same slot or two, so that part's fine.

    What I'm looking for now is how to get my custom Saves UI to display the information it saved-- that "Name: Blah, Level: 7" etc info-- next to the save buttons so that players can immediately see which slot they're saving to/over. Like if they've got a playthrough for Bob and a playthrough for Belzenaf, they can be sure they're saving Bob to the Bob slot and Belzenaf to the Belzenaf slot.

    How do I display that data?

    ---

    Also I finally got around to downloading 1.4 and that sidebar code is working beautifully for two bars! ^▽^
  • edited April 2015
    Well you can still use my original suggestion for that.

    You said it wasn't an option due to the existing passage naming scheme, but because in that suggestion you're saving only on specific passages, you can name those passages with the required page data without any other impact on your story passage naming scheme.

    E.g. If Bob is level 7, when you asked to save you would redirect the player to an options menu named "Bob, Level 7". That's what I do in my game. I have multiple versions of the same options menu passage that I use to name the save file depending on what point the player is at.

    If you had 3 characters and 20 levels for each you'd end up with 60 options passages, but that's no big deal. I have 30 different options menu passages in my game.
  • EssGee wrote: »
    Could I, perhaps, even control whether or not these boxes appear on a given

    To respond to this, yes just use the <<addclass>> macro in the Box content passage to add a css class containing display: none; if certain conditions are triggered.
  • edited April 2015
    Claretta wrote: »
    Well you can still use my original suggestion for that.

    You said it wasn't an option due to the existing passage naming scheme, but because in that suggestion you're saving only on specific passages, you can name those passages with the required page data without any other impact on your story passage naming scheme.

    E.g. If Bob is level 7, when you asked to save you would redirect the player to an options menu named "Bob, Level 7". That's what I do in my game. I have multiple versions of the same options menu passage that I use to name the save file depending on what point the player is at.

    If you had 3 characters and 20 levels for each you'd end up with 60 options passages, but that's no big deal. I have 30 different options menu passages in my game.

    I would need to be able to put player-defined variables into passage names for that. I mean, I could achieve that effect by having unique passages with the info displayed at the top of it, like a confirmation of what you're saving, and just using the default passage excerpt method with that.

    Which wouldn't be too bad, except it doesn't seem to work for pop-ups. When the save menu is in a pop-up and the passage info is used, it uses the active passage, not the pop-up passage. (Unless a tweak to the pop-up code or something could change that?)

    If it's not possible to display the saved data then I suppose that's not too bad an option, but all the other menus are such pretty pop-ups now. :(

    And I mean... there's an option to customize that info, so it feels like there has to either be a way to achieve the customization easier or to display the customized info.

    I keep looking over this thread, too, trying to figure out what variable to call or how to call it but I'm stumped. ;-; Perhaps you-- or someone else more experienced than I-- could parse it out of that?
  • Claretta wrote:
    The $party in the example refers to metadata, but I am not sure what that is.
    EssGee wrote:
    And a string seems to work fine for the "title" part without getting into whatever metadata is.
    Metadata is data about data (see: Wikipedia: metadata). In this case, it's referring to user-defined descriptive metadata for the save (i.e. data about the save).

    Say, for example, your project allowed several party members and you wanted your custom save/load screens to show the party makeup for each save (beyond simply stuffing that info in the title I mean; e.g. showing character portraits or something to that effect). You could store an array or object (or whatever) in the user metadata for the save which details that information (meaning you wouldn't have to try to sift through the save data itself, which you really don't want to do).


    EssGee wrote:
    What I'm looking for now is how to get my custom Saves UI to display the information it saved-- that "Name: Blah, Level: 7" etc info-- next to the save buttons so that players can immediately see which slot they're saving to/over. Like if they've got a playthrough for Bob and a playthrough for Belzenaf, they can be sure they're saving Bob to the Bob slot and Belzenaf to the Belzenaf slot.
    For simple things, like name/level, you could simply store them in the save's title. For example:
    <<click "Save #1">><<script>>
    var	sav   = state.active.variables,
    	title = "Name: " + sav.name + ", Level: " + sav.level;
    SaveSystem.save(0, title);
    <<script>><</click>>
    
    I'd probably wrap that up in a widget macro or a <<for>> loop, so you wouldn't have to repeat it for each slot.

    To display it as part of a custom load screen, you could do something like the following:
    <<if SaveSystem.has(0)>>\
    <<button "Load">><<script>>SaveSystem.load(0)<</script>><</button>> \
    Save #1 — <<print SaveSystem.get(0).title>>\
    <<else>>(empty)<</if>>
    
  • edited April 2015
    EssGee wrote: »
    Which wouldn't be too bad, except it doesn't seem to work for pop-ups. When the save menu is in a pop-up and the passage info is used, it uses the active passage, not the pop-up passage. (Unless a tweak to the pop-up code or something could change that?)

    That's the whole point. :P

    You put the save title in the active passage, and not the pop up. The options menu containing links to save, load, restart etc in this example is a normal passage with a <<return>> link to get back out of it and go back to the main game.

    E.g. on my story I have a timer that is $day1, $day2, $day3 etc. Depending on what the timer variable is, my options link links to different passages called Day 1, Day 2, Day 3 etc, with functionally identical content except the underlying passage name. In each of these passages they have the same links to save, load, restart, turn off music etc.

    Then when someone saves the game via popup on that page, it gets saved as Day 1, Day 2, Day 3 etc.

    I realise that for what you want specifically, it'd be a bit more complex than what I want (which is to simply display the day in the save game file), but it works quite well in my game, so put the option out there.

    The difference that seems to be coming between us here is that I keep my options menu in a normal passage with a <<return>> link to go back to the previous passage, and you want to put the entire thing in a popup, options links and all.
  • edited May 2015
    Claretta - Yeah. I definitely do appreciate the effort! It just wasn't what I was looking for in this case was all. ^.^ I'm still going to be using several pages out of your book, too, just framed a bit differently. (And again, thanks so much for the popup macro! :D)

    TheMadExile - That works beautifully, thank you! (Also I'm glad I was at least sort of on the right track, even if I couldn't figure out the right syntax for it, heh. x3)

    :V I'm sure I'll be back for other things but I think that about wraps up this thread~

    Edit: I lied. Claretta, is there any way I could make that popup macro function like buttons? Like I currently have them displaying as buttons anyway, but I mean in the way that you can put multiple <<set>> macros inside a button. owo
  • edited May 2015
    I'm not entirely sure how to do that, but you can just put the <<set>> macro in the popup passage and it'd have the same effect.

    Why do you need it in the actual link?
  • Just to cut down on the number of passages I have to make for simple things, really. Everything I'm thinking of can be done without them but it would be a lot tidier if I could set stuff in the buttons. Definitely not a big deal but it would be nice. :3
  • edited May 2015
    Edit: nvm. Got a few things mistaken.
  • edited May 2015
    If you want to set variables on clicking a popup you can do it with an autopopup macro.

    In your story javascript, write this:
    /* Usage: <<autopopup "Some Passage">> */
    macros.add("autopopup", {
    	version : { major : 1, minor : 0, revision : 0 },
    	handler : function () {
    		if (this.args.length === 0) {
    			return this.error("no passage name specified");
    		}
    
    		var dialog = UISystem.setup("popup2");
    		new Wikifier(dialog, tale.get(this.args[0]).processText().trim());
    		UISystem.open();
    	}
    });
    

    Where in css you define it under:
    #ui-body.popup2
    {
    CSS formatting goes here
    }
    

    You can change the name "popup2" in the javascript if you want. Just needs to match the css. If you need more formatting variants you can simply replicate the code several times and call the macro different names in the first line and reference different css.

    The autopopup macro will be called immediately when it is triggered, so if you put it into an open passage, a user will get an autopopup in their face. To put it in a link you need to go:
    <<click "link text to display">><<set $variable to 1>><<autopopup "Passage Name">><</click>>
    

    Or as a button:
    <<button "button text to display">><<set $variable to 1>><<autopopup "Passage Name">><</button>>
    

    And voila. You now have popups that can set variables on click. Make sure you set all variables before the popup in the click macro because otherwise the popup will trigger before they get set.

    To streamline, you could probably replace all your popup javascript with autopopups, as long as you remember to always put them inside a click or button macro to prevent premature popups.

  • That works great! Thank you! :D
Sign In or Register to comment.