Howdy, Stranger!

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

Footers and Health Bars

Hi folks,

I am really new to Twine and coding. Everything I know I have learned through google and reading through this forum. I am currently stuck with a few different issues, and I was hoping someone may be able to point me in the right direction.

I am currently working in Sugarcube and have a code for an inventory/codex system. In this code, each inventory/codex item as a separate passage that describes or gives further information for that item/person/etc. I was wondering if there is away to put the "Codex entry added" part of this code at the bottom of the passage? I was thinking that may be something that happens in the footer, but I haven't entirely figured that out yet.

<<linkappend "Wolves">><<addToCodex "Wolves">> Codex entry added. <</linkappend>>

I was having a really hard time figuring out the best way to operate my Codex/Inventory codes. If you have any advice, I would love it.

Next question:
I am trying to build a combat system in Sugarcube. I haven't been able to figure out how to create variables to deduct and add health. The code I have right now is:

<progress id="health" max=100></progress>
<div id="val"></div>

<script>
while (true){
document.getElementById("health").setAttribute("value", $health);
}
</script>

I have this code in the StoryCaption passage because I wanted it to appear in the sidebar for consistency. I haven't been able to figure out what I'm doing wrong.

I'm sorry these are kind of silly questions. I appreciate any help.

Comments

  • With regard to the first part, it is possible to set up new "sidebars", although that setup can be tricky, and I just mostly followed instructions to get it working.
    Another method might be to create a <span> area that gets added to the page via the <<link>>.
    There might be a way to assign something to a footer section, but I'm not a very good coder either (Greyelf, Madexile, and Chapel will a have much better idea of how to go about things).

    A span is a designated area. You can give it a class that will work with any defined class you put into the CSS section. It can also have an ID that gets referenced if you want a piece of code to <<replace>> its contents with something else.
    <span id="blah" class="horrificcolor">text goes here</span>
    <<link "Continue">>\
        <<replace "#blah">>\
            Told you the text was here!
        <</replace>>\
    <</link>>\
    
    The backslashes stop it from printing out a new linebreak. I don't know if that will help much, but it could be one way to update and add text to the end of the page on doing something.

    Also, I think anybody familiar will be able to tell from your code that you're using one of the 2.versions of sugarcube, but it's usually best to be specific around here about which versions of everything you have. It can make quite a big difference sometimes. =^^=
  • You should always state the story format you're using and its full version, because advice will tend to vary based on that information. I'll assume you're using SugarCube v2, as you should be at this point.

    Also. Please use the code tag—it's C on the editor bar—when posting code or markup.

    Minowen wrote: »
    […] I was wondering if there is away to put the "Codex entry added" part of this code at the bottom of the passage? […]
    You could do something like the following. In your PassageFooter special passage:
    <span id="notifications"></span>
    
    Then whenever you want to add something to that notification area:
    <<link "Wolves">>
    	<<addToCodex "Wolves">>
    	<<append "#notifications">><br>"Wolves" codex entry added.<</append>>
    <</link>>
    
    The line break (<br>) within the <<append>> is there simply so that if multiple notifications happen during the same passage, they'll appear on separate lines. If that will never happen or you'd prefer them to appear on the same line, simply remove it.

    Minowen wrote: »
    […] I haven't been able to figure out how to create variables to deduct and add health. The code I have right now is:

    <progress id="health" max=100></progress>
    <div id="val"></div>

    <script>
    while (true){
    document.getElementById("health").setAttribute("value", $health);
    }
    </script>

    I have this code in the StoryCaption passage because I wanted it to appear in the sidebar for consistency. I haven't been able to figure out what I'm doing wrong.
    You have several problems here.
    1. As with most of the special passages which are rendered into the UI bar, the StoryCaption special passage is, by default, rendered at the beginning of every turn—i.e. every time the player navigates to another passage. You have two problems because of that:
      1. You're attempting to run an umpteen number of loops via the <script> instance, which is bad.
      2. Your meters will be recreated every turn, thus resetting their values. I'd recommend creating a new element within the UI bar to hold the meters.
    2. You're using the <script> element instead of the <<run>> and/or <<script>> macros, which you almost never want to do—for various reasons. Additionally, you're attempting to access a story variable within that <script> element via the syntax which only works in markup.
    3. You're using an infinite loop which never breaks. That means you're never returning control back to the browser, which will probably cause the current tab to hang—or crash. That's the most serious issue here.
    4. The <progress> element is really not the correct thing to be using here. It's not a generic meter element—that would be <meter>—and it has styling issues that you'll have to fight on just about every browser, which is not a good position to be in. Technically, you should be using <meter>, however, IE and older versions of the iOS browser core don't support it, so that's a wash. It's fairly easy to create a faux-meter using <div> elements, which is what I'd recommend.

    The following, which comes in three parts (markup, styles, and code), is what I'd suggest.

    Meter markup: (goes wherever; though I suggest a passage named StoryMeters, see the code section below for additional details)
    <div id="health" class="meter-gauge" data-label="Health" data-max="150" data-value="150"><div></div></div>
    
    To be used with the code below, the ID must match the name of the associated story variable. I hope the other attributes are self-explanatory—if not, ask away.

    Meter styles: (Twine 2: goes in Story Stylesheet; Twine 1: goes in stylesheet-tagged passage)
    #story-meters {
    	line-height: 1;
    }
    .meter-gauge {
    	background-color: #222;
    	border: 1px solid #444;
    	box-shadow: 0 5px 5px -5px #333 inset;
    	height: 1em;
    	margin-top: 1.2em;
    	position: relative;
    	width: 100%;
    }
    .meter-gauge::before {
    	content: attr(data-label);
    	font-weight: bold;
    	left: 0;
    	position: absolute;
    	top: -1.2em;
    }
    .meter-gauge::after {
    	content: attr(data-value) " / " attr(data-max);
    	font-weight: bold;
    	position: absolute;
    	right: 0;
    	top: -1.2em;
    }
    .meter-gauge > div {
    	background-color: green;
    	box-shadow: 0 5px 5px -5px #999 inset;
    	height: inherit;  
    }
    

    Meter code: The following code creates a new UI bar element, populates it with the contents of the custom StoryMeters special passage, and sets up a recurring timer to update all of the meters: (Twine 2: goes in Story JavaScript; Twine 1: goes in script-tagged passage)
    /*
    	Create an element for the StoryMeters special passage
    	and render the passage into it.
    */
    $('<div id="story-meters"></div>')
    	.insertBefore('#story-caption')
    	.wiki(Story.get('StoryMeters').processText());
    
    /*
    	Create a recurring timer to update all meters.
    
    	NOTE: The meters' IDs must match their associated
    	story variable names.
    */
    setInterval(function () {
    	$('.meter-gauge').each(function () {
    		var $meter     = $(this);
    		var meterMax   = Number($meter.attr('data-max'));
    		var meterValue = Number($meter.attr('data-value'));
    		var storyValue = State.variables[$meter.attr('id')];
    
    		if (meterValue !== storyValue) {
    			var fillPercent = Math.min(storyValue * 100 / meterMax, 100) + '%';
    			$meter
    				.attr('data-value', storyValue)
    				.children('div')
    					.animate({ width : fillPercent });
    		}
    	});
    }, 100);
    
  • Sorry to barge in, but I found this really useful. If I wanted to use multiple bars, though, how would I give them different colors in CSS? And would that require changing any of the code used in the passage? thanks :)
  • For the markup. You must give each a unique ID and should give them unique labels. You should also give them appropriate max and initial values. That should be it, really. For example, health and mana meters:
    <div id="health" class="meter-gauge" data-label="Health" data-max="200" data-value="200"><div></div></div>
    <div id="mana" class="meter-gauge" data-label="Mana" data-max="200" data-value="200"><div></div></div>
    

    For the styles. Simply add new rules, after the set given in my last post, prefixed by the ID selector of the meter for which you want to provide an override. For example, here's how you'd change the health and mana meters' colors to red and blue:
    #health.meter-gauge > div {
    	background-color: red;
    }
    #mana.meter-gauge > div {
    	background-color: blue;
    }
    

    For the code. Nothing needs to change. Just remember that the ID of the meter must match the story variable name—i.e. if the ID is health the story variable must be $health, ID mana ⇒ story variable $mana, etc.
  • Oh, that's exactly what I needed. And it's simpler than I thought, thank you so much! :smiley:
Sign In or Register to comment.