Development Diaries

Smedis2's picture

The Game Which We Need Forget

howtoindie.PNG

Uploaded this for Snapman.

Taken down from the games section because I didn't want to get anyone mad.

Bitches don't know bout my vorticons

bitches_dont_know_bout_my_vorticons.jpg

So i couldn't think up a game for this one
Kind of like a "where are they now"
And it was kind of obvious to me that if Keen has a yorp
then McMire should own a garg but then i felt maybe
he should own a shockshund as it's more doglike
so he owns both because whatever

Twine: apply CSS to individual characters

Update: The Javascript on this page is now built into Twine 1.4! It is no longer necessary to install it.

This script causes every single character in passages to be wrapped in a <span class="char"> element. This enables a number of mildly interesting CSS effects.

Obsolete script removed: use Twine 1.4

These characters have the class of "char", and also a class equal to themselves ("a" for the letter "a", "2" for "2", etc.) It's recommended that you use the :nth-child pseudo-class to select them. Some potential CSS effects that can be performed include the following (examples only):

Horizontally spin characters on mouseover:
(works best with large text)

.char:not(.space):hover {
  transform: rotateY(1440deg);
  -webkit-transform: rotateY(1440deg);
}
.char:not(.space) {
  display: inline-block;
  transition: transform 2s ease-out;
  -webkit-transition: -webkit-transform 2s ease-out;
}

Wavy text:

 .char{ position:relative; }
.char:nth-child(8n) { top:0px; }
.char:nth-child(8n+1) { top:-1px; }
.char:nth-child(8n+2) { top:-1.5px; }
.char:nth-child(8n+3) { top:-1px; }
.char:nth-child(8n+4) { top:-0px; }
.char:nth-child(8n+5) { top: 1px; }
.char:nth-child(8n+6) { top: 1.5px; }
.char:nth-child(8n+7) { top: 1px; }

Animated wavy text:

.passage {
  font-size: 3em;
}
.char { 
  position:relative;
}
.char:nth-child(8n) { 
  animation: wavetext 4s 0s infinite;
  -webkit-animation: wavetext 4s 0s infinite;
}
.char:nth-child(8n+1) { 
  animation: wavetext 4s -0.5s infinite;
  -webkit-animation: wavetext 4s -0.5s infinite;
}
.char:nth-child(8n+2) { 
  animation: wavetext 4s -1s infinite;
  -webkit-animation: wavetext 4s -1s infinite;
}
.char:nth-child(8n+3) { 
  animation: wavetext 4s -1.5s infinite;
  -webkit-animation: wavetext 4s -1.5s infinite;
}
.char:nth-child(8n+4) { 
  animation: wavetext 4s -2s infinite;
  -webkit-animation: wavetext 4s -2s infinite;
}
.char:nth-child(8n+5) { 
  animation: wavetext 4s -2.5s infinite;
  -webkit-animation: wavetext 4s -2.5s infinite;
}
.char:nth-child(8n+6) { 
  animation: wavetext 4s -3s infinite;
  -webkit-animation: wavetext 4s -3s infinite;
}
.char:nth-child(8n+7) { 
  animation: wavetext 4s -3.5s infinite;
  -webkit-animation: wavetext 4s -3.5s infinite;
}
@keyframes wavetext {
  0%, 100% { top: 0em; } 50% { top: 0.5em; }
}
@-webkit-keyframes wavetext {
  0%, 100% { top: 0em; } 50% { top: 0.5em; }
}

Rapid rainbow text:

.char:nth-child(8n) { color:hsl(45,100%,75%); }
.char:nth-child(8n+1) {color:hsl(90,100%,75%); }
.char:nth-child(8n+2) {color:hsl(135,100%,75%); }
.char:nth-child(8n+3) {color:hsl(180,100%,75%); }
.char:nth-child(8n+4) {color:hsl(225,100%,75%); }
.char:nth-child(8n+5) {color:hsl(270,100%,75%); }
.char:nth-child(8n+6) {color:hsl(315,100%,75%); }
.char:nth-child(8n+7) {color:hsl(0,100%,75%); }

Illuminate letters on mouseover

.char { 
  transition: all 5s; -webkit-transition: all 5s;
  opacity: 0.4;
}
.char:hover {
  transition: all 0.1s; -webkit-transition: all 0.1s;
  opacity:1;
  text-shadow: 0 0 1em white;
}

Erase text on mouseover

.char { 
  transition: opacity 999s step-end; -webkit-transition: opacity 999s step-end;
}
.char:hover {
  opacity:0;
  transition: opacity 1ms; -webkit-transition: opacity 1ms;
}

Remove all the T's in the passage text:
.char.t {
  display:none;
}

Change "u" to "U":

.char.u {
  visibility:hidden;
}
.char.u::before {
  content: "U";
  position:absolute;
  visibility:visible;
}

These are to be considered basic examples - prompts for more practical uses.

This code also enables some particularly interesting Javascript visual effects to be performed, which I shall explore in a future blog post.

Feel free to report any bugs to @webbedspace.

Twine: Improved back and forward buttons in Sugarcane

Update: this feature is now built into Twine 1.4! This behaviour is now the default and this page is no longer necessary.

This script allows Sugarcane to use HTML5 history management instead of URL hash strings to alter the browser history. This means that various non-deterministic game state changes (random numbers, player data input, state changes inside <<replace>> macros, etc.) will be properly remembered when you use the browser's Back button. This code also updates <<back>> and <<return>> and the Rewind menu.

Obsolete script removed: use Twine 1.4

Feel free to report any bugs to @webbedspace.

Twine macro: <<once>>

This little macro shows a span of text only the first time you encounter it - for all subsequent times you visit a passage containing it, it will be absent. This can be done with variables, but this form lets you use a single pair of macro tags. This can be good for, let's say, IF-style verbose opening descriptions of scenes or rooms.

Install my <<Replace>> Macro Set to use this macro.

You can use <<becomes>> or <<gains>> to specify text that should appear only on the second visit, or the third, and so forth.

Usage examples:
* <<once>>I'm going now. Goodbye.<<endonce>>
* <<once>>You arrive at the bathhouse.<<becomes>>You return to the bathhouse a second time.<<endonce>>
* <<once>>You arrive at the garage.<<becomes>>Back at the garage.<<becomes>>Third visit to the garage.<<endonce>>

Notes:
* If many <<once>> macros containing exactly identical text are used in different passages, seeing one of them will hide the others.

Version history

  1. 16-6-13 - Updated regarding Combined Replace Macro Set.
  2. 12-5-13 - Initial.

Feel free to report any bugs to @webbedspace.

Twine macro: <<hoverreplace>> and <<mousereplace>>

This set of macros is a mouse-driven counterpart to <<replace>> and are essentially a simpler form of <<hoverrevise>>. They cause a span of passage text to change into a different span when the mouse moves over it. It comes in two main varieties: <<mousereplace>> replaces the span outright when the mouse touches it, whereas <<hoverreplace>> simply displays the alternative span while the mouse is hovering over it, and will change back when it leaves.

For convenience, there are also the following variations:

  1. <<mousecontinue>> functions like the <<continue>> macro, causing a single enclosing span to disappear when the mouse touches it, and revealing all subsequent passage text.
  2. <<mouseremove>> creates text that simply disappears when the mouse touches it.

Install my <<Replace>> Macro Set to use this macro.

Usage examples:
Separate both versions of the span using <<becomes>>.

  1. <<hoverreplace>>You see here a clock.<<becomes>>It's 8:09PM.<<endhoverreplace>> causes the text "You see here a clock" to become "It's 8:09PM." when the mouse hovers over it, and go back when the mouse leaves.
  2. <<mousereplace>>A [[bird]]!<<becomes>>It flew away.<<endmousereplace>> causes the text to become "It flew away." when the mouse touches it.

The <<mousecontinue>> and <<mouseremove>> variations don't use <<becomes>>:
  1. <<mousecontinue>>Move here to begin.<<endmousecontinue>> hides all further passage text until the mouse touches "Move here to begin.", whereupon those words vanish and the text is revealed.
  2. <<mouseremove>>Don't touch me!<<endmouseremove>> causes "Don't touch me!" to vanish when the mouse touches it.

<<becomes>> vs. <<gains>>
If you use <<gains>> instead, then the second version is appended to the first version.
  1. <<hoverreplace>>[[End game|Quit]]<<gains>> Are you sure??<<endhoverreplace>> adds the words "Are you sure??" after the link while you hover over it.
  2. <<mousereplace>>You see a barrel. <<gains>>It is empty.<<endmousereplace>> adds the words "It is empty." when your mouse touches the words.

Version history:
  1. 16-6-2013: Updated regarding Combined Replace Macro Set.
  2. 12-5-13 - Initial.

Feel free to report any bugs to @webbedspace.

Twine: Jonah: Disable all links after leaving a passage

Update: The Javascript on this page is now built into Twine 1.4! It is no longer necessary to install it. You can enable this in Twine 1.4 by setting "Undo: off" in the StorySettings passage.

If you're using Jonah, and you're not using single-passage, then you may find this useful. It causes all internal links to behave like the <<choice>> macro.

Obsolete script removed: use Twine 1.4

This is designed to also work with approximately all of my link macros (<<cyclinglink>>, <<revise>>, <<replace>> etc.)

Version history:

  1. 9-5-13: Initial.

Feel free to report any bugs to @webbedspace.

Twine macro: <<else if>>, an improvement to <<if>>

Update: This macro is now built into Twine 1.4! It is no longer necessary to install it.

This is not strictly a new macro, but a replacement version of the <<if>> macro. You might have noticed that nesting the <<if>> macro can get a bit messy:

<<if $fire eq "warm">>
The fire isn't hot yet.
<<else>>
<<if $medal eq "water">>
You medal protects you.
<<else>>
<<if $dead gt 0>>
Not again!
<<else>>
You died!
<<endif>>
<<endif>>
<<endif>>

The <<else if>> macro allows you to essentially have multiple <<if>> macros chained together, without needing to nest each of them within the <<else>> / <<endif>> tag pair of the other:

<<if $fire eq "warm">>
The fire isn't hot yet.
<<else if $medal eq "water">>
You medal protects you.
<<else if $dead gt 0>>
Not again!
<<else>>
You died!
<<endif>>

The macro code is here:
Obsolete script removed: use Twine 1.4

You might wonder why I chose "else if" instead of "elseif"... I guess my mind flipped a coin and the 'natural language' side shone upward.

If someone else has already developed a similar macro, as I suspect they might, then do tell.

Feel free to report any bugs to @webbedspace.

Twine: Further remarks about <<cyclinglink>> and game choices

I've recently played the game Breakfast on a Wagon With Your Partner, which uses the <<cyclinglink>> macro, and it's inspired a few brief thoughts about the user interface of text choices.

Generally, the interface used for choice, especially dialogue trees, in videogames and Twine games, resembles the following:

Fig. 1: A doctored page from "Breakfast on a Wagon With Your Partner"
A list, usually exhaustive, of the possible choices one could make, usually in an egalitarian fashion. Its exact shape is highly variable, but the important aspect is that every choice is simultaneously visible.

However, the introduction of my <<cyclinglink>> macro has unwittingly introduced an alternative arrangement:

Fig. 2: An actual page from "Breakfast on a Wagon With Your Partner"
A single hyperlink that cycles between choices when clicked, displaying only the current choice. The choice is confirmed by clicking a proper link below.

This differs from the former in a number of interesting ways. Firstly, when you initially approach the page, all of the other options are concealed. Only by clicking the link successively does each option become briefly visible - the choices are presented in a temporal sequence, rather than a spatial sequence. And, not only are the choices themselves hidden, but their quantity as well - a list of 20 choices takes up the same screen space as a list of two.

I feel as if these differences slightly more closely resemble the actual human process of making a decision. Seldom do we, in our minds, see two drastically opposing options appear side-by-side, when confronted with a tough decision. Rather, our minds actively scour themselves for choices, possibilities - the few that appeal to our intuitions rise immediately, and others must be forced up to our conscious realisation, whereupon we focus intently on it. Neither of these link presentations can be said to truly capture this marvelous process, but I like to think that the cyclinglink presentation has more superficial similarities.

One other difference I feel is worth examining is the way in which cyclinglink, in this particular usage, reverses the usual meaning of clicking a hyperlink. Consider the text "I'm not opposed to settling down" in both illustrations. In the first one, the act of clicking it means to commit to the decision - to perform these words. But in the second, the act of clicking it is the act of revising the decision, replacing it with a different possibility. This strikes a somewhat discordant note within me.

Of course, usually a Twine hyperlink doesn't translate to the player verb "act according to these words" - most often it simply means "provoke the computer to delve further into this subject" or "continue a line of thought paused at this point", any of which could somehow revoke or reverse the link text's meaning, relevance or significance. Porpentine has previously called the hyperlink an "omniverb", commenting that its meanings within a game are as varied as the words you could put inside it, and the text that results when you click it. And, indeed, my original impetus for creating this macro was to extend the mechanical potential of links in a playful fashion - links that change unexpectedly when clicked, like a puzzle switch, or a toy, or an animate object in Windosill. Links that are multifaceted, multifarious, capricious. And, indeed, many uses of cyclinglink that I've seen thus far have used it for playful or cute subject matter, where rubbing and touching the story text, and seeing unexpected changes appear, is in keeping with the tone of the story.

I only came to think of cyclinglink as a genuine replacement for the 'choice list', and began considering the implications thereof, when I encountered the above choice in "Breakfast on a Wagon With Your Partner". This story, to its credit, does a very good job of establishing a "hyperlink vocabulary" - a link at the bottom of each page, reading "(o)", serves as the 'confirm choice' button, and is the only one that is used to advance to a subsequent passage. Nevertheless, the cyclinglink still runs contrary to the grain of the traditional hyperlink's meaning - its underline suggests a button waiting to be pushed, rather than a dial waiting to be turned. I hesitated conspicuously when I got to that page, for I had become quite invested in the path of the story, and of my performance as the player-character.

What shall we conclude from this? I believe that the cyclinglink is entirely in keeping with the standard interface of Twine games, and of the versatility that the hyperlink is afforded within a Twine game. I believe further that the use of a cyclinglink for choices, particularly especially mental choices, lends the selection some superficial resemblance to the human act of reaching and developing decisions. However, it is also important that they are sufficiently differentiable from normal links, in situations where it's important the player has full confidence in the presented hyperlinks. This could be through establishing a firm in-game vocabulary, or, more directly, it could be through CSS. (I do not include CSS within the cyclinglink script that forces them to appear differently to normal links, but I do provide CSS hooks that enable them to be styled differently from normal links.)

For a time after adding the variable-alteration functionality to cyclinglink, I wondered if I had perhaps erred by making it produce a Javascript-augmented link - perhaps a more familiar interface element, like a dropdown menu, would be more appropriate for the use cases of this macro. But, I committed to the justification that the hyperlink is the player interface element in Twine games, far more so than even familiar website navigation elements. They are, after all, not web sites, but videogames. So, let the hyperlink's scope be extended so.

Twine: visited(), a function to find how often a passage was visited

Update: The Javascript on this page is now built into Twine 1.4! It is no longer necessary to install it.

I've noticed that a good deal of variable usage in Twine is simply employed to track whether or not you've visited a certain passage previously, or done so a number of times. This script code provides you with a function that can give this value straight, without needing to use the <<set>> macro.

Obsolete script removed: use Twine 1.4

To use it, use "visited("Passage")" as a value in a <<set>>, <<if>> or <<print>> macro. It will equal the number of times you've visited the passage whose name is between the quotes and parentheses. For instance:

  1. <<if visited("Store")>>You've been to the store.<<endif>>
  2. <<if not visited("Firepit") and not visited("Maggotpit")>>You've not yet been to the fire pit or maggot pit.<<endif>>
  3. <<if visited("Trap Floor") gt 2>>Your repeated stomping is making the floor weaken.<<endif>>
  4. You've visited the chasm <<print visited("Dark Chasm")>> times.<<endif>>
  5. <<set $count = visited("Jewelers")>>You've visited the Jeweler's <<print $count>> times.<<endif>>

Also, instead of a passage name, you can put a variable.
  1. <<if visited($bossPassage)>>If only you'd had this when you'd fought the boss!<<endif>>
  2. <<set $beenToMyHome = visited($myHome)>>

New: If you just put visited(), then it will count visits to the current passage, without you needing to include the passage's name.
<<set $beenHereBefore = visited()>>

In addition, here is a function called "visitedbefore" which can be used to tell you if a passage has ever, in the course of the game, been visited before another passage.

window.visitedbefore = function(e,f) {
	var h,c,ret;
  	for(ret=c=0; c<state.history.length; c++) {
		h = state.history[c].passage;
		if(h && h.title == e) {
			return true;
		} else if (h && h.title == f) {
			return false;
		}
	}
	return false;
}

This only returns true or false. Use it like so:
  1. <<if visitedbefore("Firepit", "Maggotpit")>>First the fire pit, then the maggot pit, now this?!<<endif>>
  2. <<if visited("Armory") and visitedbefore("Firepit", "Maggotpit")>>First the fire pit, then the maggot pit, now this?!<<endif>>

Again, variables can be substituted for passage name strings:
  1. <<if visitedbefore("Dragon Hoard", $myHome)>>You must've left it at home after meeting the dragon.<<endif>>

The two passage names must be separated by a comma.

Some notes:

  1. This doesn't count use of the <<display>> macro as a visit.
  2. If neither passage has been visited, visitedbefore() will return false.

Feel free to report any bugs to @webbedspace.

Syndicate content
pensive-mosquitoes