Howdy, Stranger!

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

[SugarCube 2.14 Twine 2.1] Creating a game log that shows up in every passage

edited March 2017 in Help! with 2.0
Hi there,

I decided that I want to include a game log in the bottom of all of my passages.
So, if something happens to the character's stats, equipment, inventory or a quest is started or finished, the log in the bottom of the passage would show that.

The description of the area and the options the player's character has. These would be printed to that specific passage he or she is visiting currently and the game log below that would help me show text that is triggered if a status changes. I sometimes would like to display a passage in this log, which would send the player to a new passage to inform him/her of something and then using <<back>> the player could go back to the game.

Now, my problem is the length of the log. I don't want this to be too long. Maybe 8-10 lines. Before the text that was on the top would start to dissapear as new logging entries are being added by the game in the bottom of the log.

I already have a stowable right side and left side (default) UI and I would like to have this log to be stowable as well and slide into the bottom, when not needed.

My question is, how do I count the row of text that needs to be displayed and how do I present this logging screen in the bottom of my passages?

Thank you for your answers in advance!

Comments

  • Disane wrote: »
    My question is, how do I count the row of text that needs to be displayed and how do I present this logging screen in the bottom of my passages?
    There are several ways this could be done and it really depends on how you want the log to function.

    The easiest thing to do would be to rebuild the log's contents every time it changes from a list. For example:
    :: StoryInit
    <<set $log to []>>
    
    
    :: Widgets [widget]
    <<widget "log">><<silently>>
    
    /* Add new entry to the end. */
    <<set $log.push($args[0])>>
    
    /* Remove an old entry from the front if the log is too long. */
    <<if $log.length gt 10>>
    	<<set $log.shift()>>
    <</if>>
    
    /* Update the log. */
    <<updatelog>>
    
    <</silently>><</widget>>
    
    <<widget "updatelog">><<script>>
    var logMarkup = State.variables.log
    	.map(function (entry) {
    		return '*' + entry;
    	})
    	.join('\n');
    
    if (Engine.state === 'rendering') {
    	postdisplay['update-log'] = function (taskName) {
    		postdisplay [taskName];
    		$('#log').empty().wiki(logMarkup);
    	};
    }
    else {
    	$('#log').empty().wiki(logMarkup);
    }
    <</script>><</widget>>
    
    
    :: Log
    <div id="log"><<updatelog>></div>
    
    You'd display/include the Log passage someplace. Probably similar to how you're doing the stowable right side bar.

    To add a new entry:
    <<log "You found $$100 on the ground.  Lucky!">>
    
  • edited March 2017
    oh, an array. Of course. Hmm.. shift() interesting and I was trying to create a circular buffer of my own with a delete and a create function.
    It would've been an overkill.

    So, basically each time a new log entry is added or gets removed, it should refresh, regardless if the player is entering or leaving a passage.
    Since I'll be using a couple of <<link>> and <<linkreplace>> to trigger some of the log entries.

    Again @TheMadExile I cannot express how thankful I am for the help. You are always on point and help a lot!
    #game-log
    {
    	font-size: 1.2em;
    	text-align: left;
    	background-color: #eee;
    	width: 640px;
        height: 520px;
    	border: 1px dotted black;
    	overflow: scroll;
    	postion: absolute;
    	bottom: 0;
    }
    

    I wonder if I need something like #game-log-contents or something, to be honest I'm clueless how to glue this thing to the bottom of my window and make it respond to the window size if the player decides to resize his or her window.

    ps. I really suck at CSS, but I'll try my best to figure this one out...
    Now that I think about it a simple border with a show/hide button would be enough ...
  • The <<updatelog>> widget managed to get mutilated a bit in my original post. Here's the corrected version:
    <<widget "updatelog">><<script>>
    var logMarkup = State.variables.log
    	.map(function (entry) {
    		return '*' + entry;
    	})
    	.join('\n');
    
    if (Engine.state === 'rendering') {
    	postdisplay['update-log'] = function (taskName) {
    		delete postdisplay[taskName];
    		$('#log').empty().wiki(logMarkup);
    	};
    }
    else {
    	$('#log').empty().wiki(logMarkup);
    }
    <</script>><</widget>>
    
  • edited March 2017
    hmmm... man, this is though. So, I need to call postrender() again in the JS section. That
    updatelog
    
    widget is a confusing one, since it already sets up a task in
    postdisplay
    
    .
    var $gameLog = $('<div id="game-log"></div>').insertAfter("#right-ui-bar");
    
    postrender["Display Game Log Contents"] = function (content, taskName) {
    	setPageElement('game-log', 'StoryGameLog');
    };
    

    well, lol, it shows an ugly window with a white background and some scrollbars around it and saying this:
    Error: macro <<updatelog>> does not exist
    

    I need to say that I moved the contents of :: Log into a passage named StoryGameLog. Maybe this has something to do with the problem...

    Passage:
    Widget
    (has "widget" tag added)
    <<widget "log">><<silently>>
      <<set $log.push($args[0])>>
      <<if $log.length gt 10>>
    	  <<set $log.shift()>>
      <</if>>
      <<updatelog>>
    <</silently>><</widget>>
    
    <<widget "updatelog">><<script>>
    var logMarkup = State.variables.log
    	.map(function (entry) {
    		return '*' + entry;
    	})
    	.join('\n');
    
    if (Engine.state === 'rendering') {
    	postdisplay['update-log'] = function (taskName) {
    		delete postdisplay[taskName];
    		$('#game-log').empty().wiki(logMarkup);
    	};
    }
    else {
    	$('#game-log').empty().wiki(logMarkup);
    }
    <</script>><</widget>>
    
    Error: <<;updatelog>>;: error within widget contents (Error: &lt;&lt;script&gt;&gt;: bad evaluation: Cannot read property 'map' of undefined)
    

    Update: Solved!
    Had to initialize $log right at the first window (start passage).
    <<set $log to []>>
    

    Now I need to do something about the ugly window with the white background and white fonts that it displays. My non-existant CSS's skills are totally useless...

    http://imgur.com/a/815xb
  • edited March 2017
    Disane wrote: »
    Update: Solved!
    Had to initialize $log right at the first window (start passage).
    Why not initialize it in the StoryInit special passage? I mean, the initialization of variables and whatnot at startup is the whole reason it exists.
  • Why not initialize it in the StoryInit special passage? I mean, the initialization of variables and whatnot at startup is the whole reason it exists.

    You are right, I moved it there. I'm still having trouble with CSS though.
    Look at me failing:

    http://imgur.com/a/815xb

    This is hard to figure out, because the stowable right and left side UI will overlap the log screen and I can't seem to make it stick to the bottom area, where I want it to, right between the left and right opened stowable UI bars.
  • If you want to move the window to the bottom, get rid of
    right: 0;
    

    And try adding something like:
    bottom: 0;
    width: 60%;
    
  • edited March 2017
    @chapel, I need an offset value where the left or right UI bar ends and use this offset as the starting position for the #game-log. I got no clue how to accomplish this.

    Adding
    bottom: 0;
    width: 60%;
    
    did not solve the issue.

    I added
    modified width and height to 100% and 30% respectivly and closed both UI's on the left and right side, now I can at least see the text, lol
    Still, doesn't look good.
  • How or where are you adding the html element? If it's a child of #passages, by being placed in a passage, like a header or footer, it shouldnt interfere with the ui bar at all.
  • edited March 2017
    Well, I added the structure after #story.
    var $gameLog = $('<div id="game-log"></div>').insertAfter("#story");
    

    Modified it to
    var $gameLog = $('<div id="game-log"></div>').insertAfter("#passages");
    

    Now, it looks better, it is now stuck to the left UI bar and when that gets stowed it slides to the left. I wonder if there is a way to glue it to the bottom of the window and make it's left position independed from the right or left UI bars.

    Time to figure out how to make it collapse and reappear when the button is pressed again ...
  • Ah okay. I'm not super confident with my jQuery, but if you make it a child of #story or #passages, or similar, it should move with the ui bar. I don't know why you're using jQuery instead of a header or something, can't tell if it's necessary, but if it is, it should still be possible.
  • edited March 2017
    omg, transition to passages by clicking on the log works too:
    <<link "Cast healing spell">>
    	<<if $mana gte 75>>
    		<<set $mana -= 75>>
    		<<if $health lt 1000>>
    			<<set $logmessage to $health+100>>
    			<<log $logmessage>>
    			<<if $health+100 gt $totalHealth>> 
    				<<set $health to $totalHealth>>
    				<<log "You are fully healed!">>
    			<<else>>
    				<<set $health to $health+100>>
    				<<log "You healed your self by 100 and lost 75 mana!">>
    			<</if>>
    		<<else>>
    			<<log "You are wasting your mana! You are already healed! Go here instead: [[ChangeVarRoom]]">>
    		<</if>>
    	<</if>>
    	<<goto [[OtherRoom2]]>>
    <</link>>
    
    You found $100 on the ground. Lucky!
    the player has moved to OtherRoom1
    the player has moved to OtherRoom1
    1000
    You healed your self by 100 and lost 75 mana!
    You are wasting your mana! You are already healed! Go here instead: ChangeVarRoom
    

    Amazing! Thank you @TheMadExile !

    Now, I really need to figure out the rest of the CSS.
    Two things are left to do:
    - Glueing the game-log to the bottom of the window and between the two UI bars.
    - Adding a close/open log button.

    I haven't got the faintest clue how to do these...
  • edited March 2017
    There's likely plenty of tweaking you'll need to do, but try something like the following.

    Story JavaScript:
    var $gameLog = $(document.createElement('div'))
    	.attr({ id : 'game-log' })
    	.addClass('stowed')
    	.appendTo(document.body);
    
    $(document.createElement('button'))
    	.attr({ id : 'game-log-toggle' })
    	.ariaClick({ label : 'Toggle the log' }, function () {
    		$gameLog.toggleClass('stowed');
    	})
    	.text('Log')
    	.appendTo(document.body);
    
    Story Stylesheet:
    #game-log {
    	position: fixed;
    	width: 640px;
    	height: 520px;
    	bottom: 2.5em;
    	left: 19em;
    	transition: bottom 300ms ease-in;
    }
    #game-log.stowed {
    	bottom: -999px;
    }
    #game-log-toggle {
    	position: fixed;
    	bottom: 0;
    	left: 19em;
    }
    
  • It works pretty well. More stylish than what I wanted, but that's definitely not a bad thing! Thank you very much for the help!
  • I adjusted the pop-up log a little bit and now, I'm looking for a way to autoscroll to the latest entry. Is there a known way of achieving something like this?
Sign In or Register to comment.