Skipping <<type>> macro when it is within <<linkreplace>>

Hello!
I have a piece of code that looks like this:

<<linkreplace "The war took everything.">>\
<<type 30ms none>>\
<<linkreplace "From me, from everybody.">>\
<<type 30ms none>>\
[[Those of us left are only shells of our former selves; of what humanity once was.->War2]]
<</type>>\
<</linkreplace>>\
<</type>>\
<</linkreplace>>\

I want to make it so the player can click once for the typewriter effect to skip ahead. A potential problem with this is that if the text is clicked, even while the typewriter is executing, the text will be replaced by the following <<linkreplace>> (also at a delay, since it waits for the previous text to finish typing, even though it is no longer visible.)
My idea is that there needs to be some kind of check to make sure all text is displayed before it becomes a link. I played around with the t8n-typewriter module which skips the text once the space bar is pressed, however I understand that players may not want to go back and forth between the mouse and keyboard.
Alternatively, instead of having <<linkreplace>> at all, an arrow could appear at the bottom right of the content box once the text has finished typing/once the player has skipped the text, and instead act as the link to the next text and/or passage. This would allow the player to click anywhere in the content box to skip the text, then click the arrow once they are ready, which would replace the text with the next line or passage.
Unfortunately, I am not super sure how to execute either of these ideas. Perhaps they are wildly inefficient ways of going about this. If anyone has any solutions or advice, I would appreciate it a lot!

Placing the following into your project’s Story JavaScript will cause clicks upon typing sections to finish, just the same as hitting the skip key would.

(function () {
	var skipKeyEv = jQuery.Event('keydown', {
		key : Config.macros.typeSkipKey
	});

	jQuery(document).on(':typingstart', function (ev) {
		jQuery(ev.target).one('mousedown', function (ev) {
			ev.stopImmediatePropagation();
			ev.preventDefault();
			jQuery(document.body).trigger(skipKeyEv);
		});
	});
})();
1 Like

Awesome, thank you so much!! This is almost perfect, but I am wondering if it would be possible to click anywhere in the content box instead of just where the text will follow. Here is what my box looks like:
content box
The text will only skip if I click somewhere the text will end up after typing. Some of my links are short sentences, so this may be frustrating for the player who is just clicking blindly hoping for the text to skip.
Thank you again! Apologies for any unclear language, I struggle explaining things succinctly.

Sorry to topple onto this, but I am having another related issue. I would like the link to only work if the text has finished typing, in order to avoid the player clicking unfinished typed text and accidentally skipping to the next section. As it is now, if I click on an area that has not finished typing but my click falls on the visible typed area, it skips to the next <<linkreplace>> or passage entirely. Sorry if this does not make sense–I can provide a visual or sample of code if needed.

Before going farther with this. Is this something you’re going to use sparingly or are you attempting to have a VN-style interface for most, or all, of your text?

If it’s the latter, then you’d probably be much better served by using the third-party Click To Proceed (CTP) macro set as VN-style interfaces are what it’s designed to do.

CTP-based Example

Here’s what your current example could look like using CTP—and an optional helper widget that isn’t necessary but simplifies things.

Example CTP usage (w/ helper widget):

<<ctp "vn-text" clear>>\
<<vntype>>\
The war took everything.
<</vntype>>

<<ctpNext>>\
<<vntype>>\
From me, from everybody.
<</vntype>>

<<ctpNext>>\
<<vntype "War2">>\
Those of us left are only shells of our former selves; of what humanity once was.
<</vntype>>
<</ctp>>

Example <<vntype>><</vntype>> helper widget code:

/*
	<<vntype [passageName]>> … <</vntype>>
		- passageName: (optional) Name of the passage to send the player to

	Examples:
		<<vntype>>Text to type.<</vntype>>
		<<vntype "Next passage">>Text to type.<</vntype>>
*/
<<widget "vntype" container>>
\<<type 30ms none>>
	\<<= _contents.trim()>>

	\<span class="vn-link"><<link "Continue">>
		<<if _args[0]>>
			<<goto _args[0]>>
		<<else>>
			<<ctpAdvance "vn-text">>
		<</if>>
	<</link>></span>
\<</type>>
\<</widget>>

Example <<vntype>><</vntype>> continue link style:

.vn-link a::after {
	content: "▶︎";
	margin-left: 0.35em;
}
2 Likes

The latter is true, yes, though there will be instances within the game where the player must choose from a set of options rather than clicking a ‘next’ button, which shouldn’t be a problem to reformat for.

This macro set is actually beyond perfect–I cannot thank you enough for showing it to me and also writing the example code!!

Unfortunately, its been some time since I’ve touched coding, and I am especially dense with JavaScript, so I am having some difficulty implementing the helper widget. Specifically this part:

\<<= _contents.trim()>>

	\<span class="vn-link"><<link "Continue">>
		<<if _args[0]>>
			<<goto _args[0]>>

I read this and understand what it is meant to do (that is, I believe it is trying to check if the last section of ‘vn-text’ is being shown, and if so, go to the next passage when clicked) however I am unsure of what to plug in as the arguments to execute this. I also cannot figure out what <<_contents.trim()>> is used for, despite looking through the docs and other JS resources. Again, sorry if this is just super obvious, I hate to be the “code for me/teach me everything!” guy.

I also understand that the helper widget is optional, so I tried to find a workaround using just the macro set itself, however I ran into essentially the same problem: I cannot figure out how to make the last section of ‘vn-text’/the CTP container link to the next passage entirely using the :arrow_forward:︎ continue link. I feel like the solution is so simple but I can’t grasp it.

Thank you again for any further help, this is already way further than I would have gotten on my own!

It’s already implemented, so all you need to do is place it within a new passage that is tagged widget. Unless you meant modifying it?

 

That’s not quite correct. It checks to see if a passage name was passed to the widget—e.g., <<vntype "War2">>….

If no passage name was given, the link it creates calls <<ctpAdvance "vn-text">> to advance to the next CTP case. If a passage name was given, the link it creates calls <<goto>> to send the player to that passage.

You can see this in my previous example where all of the <<vntype>> calls do not include a passage name except for the last one <<vntype "War2">>. You’ll generally only want your final case to include a passage name argument.

 

You have a typo there, it’s <<= _contents.trim()>>.

In order:

  1. The <<=>> macro is a shorthand alias for the <<print>> macro.
  2. As noted in the <<widget>> macro docs, the special temporary variable _contents holds the contents of container widgets—i.e., what’s between the opening and closing tags.
  3. The <String>.trim() method removes leading and trailing whitespace from a string.
1 Like

Yep, sorry, I misread a critical piece of info on the docs and started overthinking stuff. All good here.

Thank you for your excellent explanation! That now makes perfect sense and I see what I was misunderstanding.

Thank you so much for breaking down that line of code, I definitely understand it a lot better now. Unfortunately I am getting this error regarding it:

Error: <<=>>: bad evaluation: State.temporary.contents is undefined

I tried messing around with it using what I found on the docs and older forum posts but it only leads to other stuff breaking. I understand a variable cannot be called upon before it is defined, but I thought that the contents of the passage were what it would refer to…but I guess since the widget passage is loaded first, it doesn’t even get there. I’m probably overthinking or missing something huge again, sorry.

The special _contents temporary variable is only defined for container widgets—i.e., those created with the container keyword. The <<vntype>> widget definition does have the keyword, so _contents should be defined within it.

What version of SugarCube are you using? The version required for container widgets is ≥v2.36.0 and the current release is v2.36.1, which has been out for about two years.

 
EDIT: Forgot to reply to this:

The special _contents temporary variable contains the contents of the container widget’s body—i.e., what it wraps. For example, in the following <<vntype>> call:

<<vntype>>\
The war took everything.
<</vntype>>

The _contents variable within the widget will hold The war took everything..

1 Like

This is what I assumed too, but I was unaware that the container widget is supposed to define _contents. That area in the docs now makes a lot more sense, and it explains why everything I tried to do to fix it was just making it worse.
I thought it could have been another stray piece of code somewhere interfering, but creating a new story and testing it isolated yields the same results.

I should be using 2.36.1, as it is says in my story format page.

Ooh! I could see what it was doing, but not the steps in which it was taking to get to that point. That process makes sense now, thank you!