+1 vote
by (1.7k points)

(not sure if this should be here or the subreddit; feel free to let me know to move it.)

This is a bit hard to explain, so bear with me. The game Emily is Away has a mechanic in which the player chooses a dialogue option ("Hello how are you"), then types gibberish into their keyboard ("diogjfd dsf d"), and the random key presses trigger the selected dialogue to be typed out on screen, as if the player had typed it themselves. I tried searching to see if anyone had replicated this outside the game, but I'm not sure what to call it exactly, and the searches are mostly cluttered up with auto-typing animations.

Any thoughts on how this could be built and applied in Twine? I feel like it's a great mechanic for interactive fiction that a lot of people could use in their games to augment the ~~interactive~~ atmosphere. Tracking key presses from the user isn't hard, but I have no idea how to translate random key presses into displaying a pre-selected message.... Anyway, I know it's a lot to ask, but I thought I'd float the question in case anyone with more js skill was also intrigued by the mechanic and wanted to give it a go.

(I don't think format matters too much here, but for reference, I use mostly Sugarcube 2 in Twine 1.)

1 Answer

+2 votes
by (63.1k points)
selected by
 
Best answer

(not sure if this should be here or the subreddit; feel free to let me know to move it.)

I'd like an answer to this, too.  I'm not sure if asking for something like this (a feature or functionality rather than a straight-up answerable question) is in line with the rules of this forum.

You'll need some CSS to make it look pretty, but here's a start:

Macro.add('typeme', {
	   tags : null,
	handler : function () {
		
		var $text    = $(document.createElement('textarea'));
		var $wrapper = $(document.createElement('div'));
		
		// simple error checking
		if (this.args.length !== 1) {
			return this.error('incorrect number of arguments');
		} if (typeof this.args[0] != 'string') {
			return this.error('argument should be a string');
		}
		
		// get message parameters
		var message = this.args[0],
			shown   = '', 
			length  = message.length,
			i       = 0,
			id      = 'typeme-output-' + message.replace(/[^A-Za-z0-9]/g, ''),
			cls     = 'macro-' + this.name,
			content = this.payload[0].contents;
			
		$text
			.wiki(shown)
			.attr({
				id       : id,
				readonly : true
				})
			.addClass(cls)
			.appendTo(this.output);
		
		// listener
		$(document).on('keydown', '#' + id, function (e) {
			
			if (i < length) {
				shown = shown + message.charAt(i);
				$('#' + id).empty().wiki(shown);
			}
			
			if (i === length) {
				$wrapper
					.wiki(content)
					.addClass(cls)
					.insertAfter('#' + id);
			}
			
			i++;
		});
		
	}
});

Syntax:

<<typeme 'message to type out'>>
    STUFF TO SHOW/CODE TO RUN ONCE MESSAGE IS COMPLETED (e.g. a [[Continue]] link)
<</typeme>>

Things to note:

  • The text area generated by the macro must have focus for the typing to work.
  • You can have multiples in the same passage; i.e. they shouldn't interfere with each other unless they both have the exact same message, which might cause problems.
  • You can pass variables as the string argument (e.g. <<typeme $message>><</typeme>>).
  • The content that is generated on completion is evaluated only on completion (so if it contains code, that code won't fire until the message is completed), and is appended beneath the text area as a div, so you may need to be careful with your white space.  I made it a div because that seemed easier at the time.
by (1.7k points)
Brilliant as always!! You are an absolute treasure. I already have an idea of where to use this, and I hope others find it equally valuable. Thank you!
...