Choicescript-Like Stats Screen And Opposed Pair Stats In Twine

Adapting some of my old Choicescript projects to Twine. How would I go about setting opposed pair stats like in Choicescript, or a functional equivalent? As an example, one of my stat pairs is Limelight/Shadows, and I want to be able to have it measured and displayed as a percentage where one end falls when the other rises. Also, how would I set up a permanent sidebar link to a menu where stats are displayed?

You may want to consider using SugarCube for your new project, as it comes with both an extendable menu area (the StoryMenu special passage) in its sidebar, as well as a extendable Dialog system you could use to display the stats without causing the end-user to navigate away from the ‘current’ Passage.

SugarCube is also (in some ways) easier to extend. But you can do it in Harlowe, it’s just a little more clunky.

Story Stylesheet
.statBar {
  width: 20em;  /* Overall stat-bar width (in 'm' characters) */
  background: #fb5;  /* Right-side background color */
  color: #111;  /* Text color */
  font-weight: bold;
  margin: 0.5ex auto;
  position: relative;
}

.statBar div {
  position: relative;
  z-index: 1;
}

.statBar .statLeftBg {
  position: absolute;
  top: 0px;
  left: 0px;
  background: #1a5;  /* Left-side background color */
  z-index: 0;
}
Opposed Stat passage (displays the stat bar)
{
(set: _bar to '<div class="statBar">')
(set: _bar to it + '<div style="float:right">&nbsp;$right ' + (text: 100-$percent) + '%&nbsp;</div>')
(set: _bar to it + '<div class="statLeftBg" style="width:'+(text: $percent)+'%">&nbsp;</div>')
(set: _bar to it + '<div>&nbsp;$left $percent%</div>')
(set: _bar to it + '</div>')
_bar
}
%+ passage
{
	(set: _end to 50 + 50*(sign: $change))
	(set: $percent to it + (abs: $change)/100 * (_end - $percent))
}
%- passage (optional: unlike ChoiceScript, my %+ is ok with negative changes)
(set: $percent to -it)(display: "%+")
Using the above code
{
	<!-- Initialize a stat. -->
	(set: $Limelight to 50)

	<!-- Change a stat (note that it's ok to use negative values with %+) -->
	(set: $percent to $Limelight)(set: $change to -30)
	(display: "%+")
	(set: $Limelight to $percent)

	<!-- Display a stat bar -->
	(set: $left to "Limelight")(set: $right to "Shadows")(set: $percent to $Limelight)
	(display: "Opposed Stat")
}
1 Like

I wrote a Twine game in 2016 called “Stuff and Nonsense” which had a basic stat screen (more inventory than stats) which displays on the side (and players could also click on a link to get more info on what the stats meant). There was a huge amount of code making that work, and I reckon I’ll stick to ChoiceScript for that from now on—ChoiceScript is a little harder to learn but has lots of really excellent functionality, especially with stats, especially opposed stats.

May I ask why you want it in Twine?

I can send you the chunks of code from “Stuff and Nonsense” if that’s helpful for you.

https://philome.la/FBanksBooks/stuff-and-nonsense/play/index.html

2 Likes

The Twine Cookbook also includes two Harlowe based recipes for showing dynamic content within the left margin of the story area, the same area of the page that Harlowe’s own <tw-sidebar> (header) element is re-positioned to. note: both recipes support the 3.x series of Harlowe.
“Left Sidebar”: Harlowe (both v1.x and v2.x series)
“Left Sidebar”: Harlowe (only v2.1.0 or later)

note: My early post was not mean to imply that such functionality could not be achieve in Harlowe, just that it may not be the best story format to use to do such. Especially if you also plan to use Array or Data-Map for storage of information, because Harlowe implements its own variations of those objects and those implementations are quite inefficient when it comes to things like looping / contents manipulation / element accessing / etc…

Yeah, if you’re not already too attached to Harlowe…here’s the same code for SugarCube:

Story Stylesheet (same as Harlowe)
.statBar {
  width: 20em;  /* Overall stat-bar width (in 'm' characters) */
  background: #fb5;  /* Right-side background color */
  color: #111;  /* Text color */
  font-weight: bold;
  margin: 0.5ex auto;
  position: relative;
}

.statBar div {
  position: relative;
  z-index: 1;
}

.statBar .statLeftBg {
  position: absolute;
  top: 0px;
  left: 0px;
  background: #1a5;  /* Left-side background color */
  z-index: 0;
}
Story JavaScript (defines <<fair_plus>>)
// <<fair_plus "$stat" _change>>
Macro.add('fair_plus', {
	handler: function() {
		var percent = State.getVar(this.args[0]), change = this.args[1]
		var end = 50 + 50 * Math.sign(change)
		percent += Math.abs(change)/100 * (end - percent)
		State.setVar(this.args[0], percent)
	}
})
passage with widget tag (defines <<opposed_stat>>, <<fair_minus>>)
<<widget "fair_minus">><<fair_plus $args[0] -$args[1]>><</widget>>

<<widget "opposed_stat">><<nobr>>
<div class="statBar">
	<div style="float:right">&nbsp;$args[1] <<= 100-$args[2]>>%&nbsp;</div>
	<<= '<div class="statLeftBg" style="width:'+$args[2]+'%">&nbsp;</div>'>>
	<div>&nbsp;$args[0] $args[2]%</div>
</div>
<</nobr>><</widget>>
<!-- Initialize a stat. -->
<<set $Limelight to 50>>
​
<!-- Change a stat (note that negative values are ok) -->
<<fair_plus "$Limelight" -30>>
​
<!-- Display a stat bar -->
<<opposed_stat "Limelight" "Shadows" $Limelight>>