Menus cause a crash when you click a hyperlink

Hi guys! I’ve been using Hyperlink Interface by Leonardo Boselli for a while now, and it works great! But, if I click a link while in a conversation or menu I made with Shadow Wolf’s Activity Based Simple Chat, it crashes the game saying: “Fatal Error: Printing text to a window that is waiting for line or character input is not allowed.

Anyone know any way to fix this? I’ve already made so many work-arounds they are starting to slow the game down!

This might be helpful: https://intfiction.org/t/if-archive-hugo-downloads/59/1

The topic bg linked to is probably a bit obstruse (as it is more focused on audio) but it does have an incidence in it of the same problem.

In summary, Inform has an input loop which is most often waiting for the player to type a line of text and press RETURN (this is line input). Then it does all its processing and runs your code for a turn, and comes back to the loop again

There are other kinds of input (eg hyperlink clicks) which can be checked for at the same time as the main loop. But since acting on these can’t be allowed to interfere with the collection of line input (eg - if player clicks a hyperlink after typing half a sentence, the half a sentence still needs to be there - Inform doesn’t lop it off and move on) the game can’t go printing to the window that’s waiting for line input until the line input is resolved. This is the problem you’ve encountered.

So it seems that the Shadow Wolf extension, at least when combined with what else you’ve got going, is trying to print stuff in response to actions while the game is still waiting for unresolved line input. I assume the Shadow Wolf thing works if used on its own, so it’s most likely the combination of extensions and techniques they’re using. It may also depend on whether you’ve opened more than one window in your game or not, and where the game is printing, when.

This shouldn’t be super hard to fix; we just have to find the conflicting program paths that are causing it, but without seeing your code, I can probably just start by having a glance at the Shadow Wolf extension. I’ll try to get back to you if others don’t solve this faster. (Which they probably will…)

-Wade

Hi guys! The error does still happen when it’s just hyperlinks and Shadow’s chat system, so I’m pretty sure that is the conflict. Here’s the version of the chat mod I’m using in case you can’t find it:

[rant][code]Version 3/150212 of Activity-based Simple Chat by Shadow Wolf begins here.

Section - Chat Nodes and Activation

A chat node is a kind of thing. No-quip-chosen is a chat node.
Node-type is a kind of value. The node-types are activated, non-active, choose-once, and show-once.
A chat node has a node-type. The node-type of a chat node is usually activated.

A chat node has a text called quip. The quip of a chat node is usually “”.
A chat node has a text called prompt. The prompt of a chat node is usually ">> ".

To activate (chosen node - a chat node): now the chosen node is activated.
To deactivate (chosen node - a chat node): now the chosen node is non-active.

Section - Quittability

Chat quittability is a truth state that varies. Chat quittability is true.

To allow exiting on zero: now chat quittability is true.
To forbid exiting on zero: now chat quittability is false.

To decide whether exiting on zero is allowed: if chat quittability is true, decide yes; decide no.

Section - the Table of Current Choices

Table of Current Choices
result
a chat node
with 20 blank rows

The rowcount is a number which varies.

To link to (response - a chat node):
unless response is non-active or the number of blank rows in the Table of Current Choices is 0:
choose a blank row in the Table of Current Choices;
now the result entry is the response;

To reset the links:
blank out the whole of the Table of Current Choices.

Section - Finding Responses

Finding responses to something is an activity on chat nodes.
To find responses to (C - a chat node): carry out the finding responses to activity with C.

Section - Giving Text About

Giving text about something is an activity on chat nodes.
Rule for giving text about a chat node (called the current node):
if the initial appearance of the current node is not “”:
clear only the main screen;
say the initial appearance of the current node;
otherwise:
say “Error - no text for [the current node]”.

Before giving text about a choose-once chat node (called the current node):
now the current node is non-active.

To give text about (C - a chat node): carry out the giving text about activity with C.

Section - Showing Links to

Prior node is a chat node that varies.

Showing the link to something is an activity on chat nodes.
Rule for showing the link to a chat node (called the current node):
if the quip of the current node is not “”:
say the quip of the current node;
otherwise:
say “Error - no quip for [the current node]”.

Before showing the link to a show-once chat node (called the current node):
now the current node is non-active.

To show the link to (C - a chat node): carry out the showing the link to activity with C;

Section - Readchoice I6 routine

Chat prompt is text that varies. Chat prompt is ">> ";

Include (-
[ ReadChoice low high i;
for (::slight_smile: {
print (I7_string) (+ Chat prompt +);
KeyboardPrimitive (buffer, parse);
i = TryNumber (1);
if (i >= low && i <= high) return i;
else print "[Please answer by typing a number between ", low, " and ", high, “.]^”;
}
];
-).

To decide what number is the choice made from (low value - a number) to (high value - a number): (- ReadChoice ( {low value}, {high value} ) -).

Section - Starting a Conversation

To start a conversation with (current node - a chat node):
clear only the main screen;
say “[paragraph break]”;
let previous node be no-quip-chosen;
let next node be no-quip-chosen;
while current node is not no-quip-chosen:
give text about the current node;
say “[paragraph break]”;
reset the links;
find responses to the current node;
if the Table of Current Choices is empty:
now the current node is no-quip-chosen;
otherwise:
now the prior node is the current node;
sort the Table of Current Choices in result order; [shuffles all blank rows to the bottom]
let rowcount be the number of filled rows in the Table of Current Choices;
repeat with choice running from 1 to the rowcount:
say “[choice]) [run paragraph on]”;
choose row choice in the Table of Current Choices;
show the link to the result entry;
say “[line break]”;
let choice made be 0;
now chat prompt is the prompt of the current node;
if exiting on zero is allowed:
say “[italic type]([simple chat zero option])[roman type][line break]”;
now choice made is the choice made from 0 to rowcount;
otherwise:
now choice made is the choice made from 1 to rowcount;
if choice made is 0:
now next node is no-quip-chosen;
say “[line break][run paragraph on]”;
otherwise:
now next node is result in row choice made of the Table of Current Choices;
now previous node is current node;
now current node is next node.

zero-option-saying is an activity.
The last for zero-option-saying rule (this is the default zero option rule): say “or 0 to say nothing[run paragraph on]”.
To say simple chat zero option: carry out the zero-option-saying activity.

Section - German (for use with German by Team GerX)

This is the German zero option rule: say “oder 0 um nichts zu sagen[run paragraph on]”.
The German zero option rule is listed instead of the default zero option rule in the for zero-option-saying rulebook.

Section - French (for use with French by Eric Forgeot)

This is the French zero option rule: say “ou 0 pour ne rien dire[run paragraph on]”.
The French zero option rule is listed instead of the default zero option rule in the for zero-option-saying rulebook.

Activity-based Simple Chat ends here.

---- DOCUMENTATION ----

Section: Changes from Simple Chat

Activity-based Simple Chat is a rewrite of Mark Tilford’s Simple Chat extension. It uses activities where Simple Chat uses actions, in order to simplify the process of writing rules for chat nodes. Among other things, this means that the original player action (including noun, second noun, etc.) that initiates the conversation is always available rather than being overridden by nested actions.

It also turns chat nodes into things instead of values, allowing standard object properties to provide link names and text for chat nodes - so many chat nodes will require no additional rules except to build the link menu.

The text for the zero option is now also an activity (“zero-option-saying”). This allows you to override the text for specific kinds of nodes, etc., e.g.

Rule for zero-option-saying while the prior node is a help node: say "or 0 to quit[run paragraph on]"

I’ve also updated some of the table handling, to avoid maintaining a global row count and in order to simplify the syntax. Some other unnecessary globals have also been removed.

For questions, bug reports, etc, contact shadowolf3400@gmail.com

Section: Using Chat Nodes

A “chat node” is a conversational object, typically a quip spoken by the player, with a response from an NPC. By default, the “quip” property will be the player’s quip (as shown by the extension’s menus), while the “initial appearance” property is the response text. This makes defining a basic chat node fairly simple:

Node-harry-hello is a chat node with quip "'Hello, Harry.'". "Harry says, 'Hi, player! What's up?'".

(Note that with this syntax it is important to be sure there is a period between the quip and the initial appearance. In particular, if you have single quotes around the quip, you need to ensure that there is a period outside of the quotes, as above. Otherwise the compiler will not set the property correctly.

You can override the use of the quip property by providing a “Rule for showing the link to ___:” These rules can be qualified with the usual clauses. In particular, if you want to base the text on the chat node just displayed, you can test the “prior node” value:

Rule for showing the link to harry-good-bye when the prior node is harry-hows-tricks: say "'Well then, good-bye.'".

To override the use of initial appearance for the NPC response, create “Rule for giving text about ___:” Again, rules can be qualified with the usual clauses.

To build the menu of player choices, create a “Rule for finding responses to ___:” For each quip the player may pick, call the “link to ___” phrase for the appropriate node. Non-active nodes (see the chat node types below) will not be displayed. Additional conditional checks can be built into this rule as well. If you want to copy the responses of another node, you can call “Find responses to ___.” Be careful to avoid circular loops.

If there is no “rule for finding responses”, then the conversation will end. There can be at most twenty links displayed for a given node (should be plenty)! But this can be increased by extending the Table of Current Choices with additional blank rows.

Chat node types: There are four chat node states: activated, non-active, shown-once, and choose-once. Activated is the default with normal behavior. Non-active nodes will never be linked to until the state is explicitly changed (You can use the phrases “activate ___” or “deactivate ___”). A shown-once node will become non-active once the link has been displayed once - if the player doesn’t select it, they will never get the option again. A choose-once node will become non-active only once it has been picked by the player, after which it will not be displayed again.

To begin a conversation, simply use the phrase “Start a conversation with ___” (where the blank is the first node of the conversation). This can be used in the rule for a “Talk to…” action, for instance.

Section: Customizing the prompt

This is a pure enhancement over the original Simple Chat. Every node has a “prompt” property, which can be used to override the prompt for all nodes (“The prompt for a chat node is usually ___”) or on a node-by-node basis. (Or you could create different sub-kinds of nodes with special prompts.)

Section: Exiting a conversation

As with Simple Chat, the default is that the player can choose “0” to exit the menus and return to the normal prompt. The code can instead “Forbid exiting on zero” to turn this behavior off, or “Allow exiting on zero” to turn this behavior on again. I’ve included the German and French translations of the “simple chat zero option” text.

Example: *Simplest Chat - shows the basic functionality. This parallels the example in Mark Tilford’s version.

*: "Simplest Chat" by Shadow Wolf

Include Activity-based Simple Chat by Shadow Wolf.

Talking to is an action applying to one visible thing.

Understand "talk to [someone]" as talking to.
Report talking to: say "You have nothing to say.".

Living Room is a room. Larry is a man in Living Room.

chat-hello-larry is a chat node. "Larry looks up as you approach him."
Rule for finding responses to chat-hello-larry:
	link to chat-hows-tricks; link to chat-good-bye.

chat-hows-tricks is a chat node with quip "'How's tricks?' ". "'Just fine.'".
Rule for finding responses to chat-hows-tricks: link to chat-good-bye.
Rule for giving text about chat-hows-tricks: deactivate chat-hows-tricks; continue the activity.

chat-good-bye is a chat node with quip "'Good bye.' ". "'You too.'".
Rule for showing the link to chat-good-bye when the prior node is chat-hows-tricks:
	say "'Well then, good bye.' ".

Instead of talking to Larry: start a conversation with chat-hello-larry.

Test me with "talk to larry / 1 / 1 / talk to larry / 1 / talk to larry / 0".

Example: **Less Simple Chat - Shows some of the more advanced functionality. Functionally identical to the example in Tilford’s extension, although the order of menu options is likely different.

*: "Less Simple Chat" by Shadow Wolf

Include Activity-based Simple Chat by Shadow Wolf.

Talking to is an action applying to one visible thing.

Understand "talk to [someone]" as talking to.
Report talking to: say "You have nothing to say.".

When play begins:
	forbid exiting on zero.

Living Room is a room. Harry is a man in the Living Room. He carries Finnegans Wake.

Harry-chat-hello is a chat node. "Harry looks up as you approach him."
Rule for finding responses to Harry-chat-hello:
	link to Harry-chat-book; link to Harry-chat-fire; link to Harry-chat-again; link to Harry-chat-goodbye.

Harry-chat-book is a choose-once chat node with quip "What was that book you told me about?". "'It's by some guy called Finnegan Wake, and I think it's in Irish or something. Do you want it?'"
Rule for finding responses to Harry-chat-book:
	link to Harry-chat-want-it; link to Harry-chat-dont-want.

Harry-chat-want-it is a chat node with quip "'Sure.' ".
Rule for giving text about Harry-chat-want-it: 
	move Finnegans Wake to player;
	say "Harry hands the book to you. ".
Rule for finding responses to Harry-chat-want-it: Find responses to Harry-chat-hello.

Harry-chat-dont-want is a chat node with quip "'No, thanks.' ". "Harry sighs. 'I'm never going to get rid of it.'"
Rule for finding responses to Harry-chat-dont-want: Find responses to Harry-chat-hello.

Harry-chat-fire is a show-once chat node with quip "'Run! Fire!'". "'We are only pixels on a two-dimensional screen. There is nowhere to run to.' Harry's words shatter the fourth wall.".
Rule for finding responses to Harry-chat-fire: Find responses to Harry-chat-hello.

Harry-chat-again is a non-active chat node with quip "'Didn't we have this conversation before?'". "'The world is one big circle, and we are doomed to repeat ourselves.'"
Rule for finding responses to Harry-chat-again: Find responses to Harry-chat-hello.

Harry-chat-goodbye is a chat node with quip "'See you later, Harry.'". "'Later!'"
After giving text about harry-chat-goodbye: activate Harry-chat-again.

Instead of talking to Harry: start a conversation with Harry-chat-hello.

Test me with "talk to harry/2/2/talk to harry/2/1/1/2/i/talk to harry/2".

Activity-based Simple Chat ends here.
[/code][/rant]

Thanks a lot in advance for looking over it!

By the way, are you using Inform 6G60 or 6L38?

EDIT: Hm, this is harder than I thought to operate on in theory world. I really need a test case project.

Could you possibly make a simple case in the style of your game? IE One location using all these extensions, with some hyperlinkd objects, and some link to take us into one thing created with smart chat, and at least one item in there so that we can cause the crash? If you could share the code for the test case, then I think we’ll be able to hack our way to a solution.

-Wade

Oh, it’s the latest version of Inform, if that helps. To be honest, though, I think the best solution would be for me to just turn off Alice’s “Common Commands Sidebar extension” during conversations. It’ll be a pain to script but it shouldn’t be as hard as trying to jury-rig some kind of fix. If it doesn’t work I’ll sort you out a demo of the bug.

Thanks a lot for helping me anyway, I’m sorry I didn’t think of this earlier and save you some time.

Well, you never know how easy or hard a fix will be 'til you get close to it. See, it could be that you just change one mechanism in the chat extension and suddenly everything’s OK. But that hyperlink extension is doing some heavy-hitting stuff, and then you’re combining it with activities from the chat extension, and the latter presumably was made without hyperlinks on its mind. So yeah, the fix could just as easily be horrible.

If you’ve found an easy enough way around it, good!

-Wade

Yeah, it seems to work pretty well. I guess it would be nice to fix the problem itself, but I think that would need someone who knew that hyperlink extension pretty well and could code something into it to fix it. :confused: