I am trying to use widgets for changing game state and generating a status message. I want to embed these in links so they will only fire when the link is clicked.
When I put the following in a widget passage:
<<widget play-red>>
<<set $reds = $reds + 1>>
You play a red card.
<</widget>>
<<widget play-black>>
<<set $blacks = $blacks + 1>>
You play a black card.
<</widget>>
<<widget play>>
<<link _args[0]>>
<<set $atext = '<<play-'+_args[0]+'>>'>>
<<replace '#action'>>$atext<</replace>>
<<goto Room>>
<</link>>
<</widget>>
And using the following passage (named âRoomâ):
<span id="room">
Red: $reds.
Black: $blacks.
This is a test story for testing widgets and side effects.
Click the <<play red>> link to play a red card.
Click the <<play black>> link to play a black card.
</span>
<hr>
<span id="action">$atext</span>
Whenever I click a link, counters are updated twice instead of once. How can I use a widget within a link to update state and produce some output without side effects?
Itâs your use of <<set $atext = '<<play-'+_args[0]+'>>'>> that is causing the widget to be evaluated twice, once to turn it into a value inside <<set>> and again as get clicked.
There are plenty of ways around it, such as just having one widget to do both colours, with dynamic text, or bundling everything inside <<play>>.
However, the simplest way to stay close to what you have now is:
The example I gave above was a simplified example to isolate the problem. I have many references to these widgets. I guess I can write a script to go through all references to e.g. the play widget and construct a big switch statement out of the results but I was hoping for a simpler way.
I wanted to use widgets instead of passages to generate content since the Twine UI becomes a bit cumbersome when I have a large number of passages.
The example above does not set the $atext variable, so the goto statement will refresh the page and the results of the replace will be overwritten with whatever is in $atext. That is why I wanted to capture the output of the widget in $atext. If I cannot use a widget to update variables and generate some text output then I will look for other ways.
In general, if what you want is to capture the output of some piece of reusable code, you really want to be using a function, rather than a widget. Functions return values for you to reuse, widgets â in general â do not.
Another option would be to change the <<play>> widgets to set $atext
<<widget play-red>>
<<set $reds = $reds + 1>>
<<set $atext = "You play a red card.">>
<</widget>>
But going back to the original question, I realise that I donât actually know why you have the <<goto>> at all. The <<replace>> sets the contents of #action to the result of running your widget, but then you refresh the passage, throwing away the text in #action.
So it sounds like you donât actually want the <<goto>> at all
Long story short: This is my first attempt at creating a Twine game. It will basically be the Twine version of my parser game I submitted for IFComp last year.
I now have this working:
:: Room {"position":"300,100","size":"100,100"}
<span id="room">
Red: $reds.
Black: $blacks.
This is a test story for testing widgets and side effects.
Click the <<play red>> link to play a red card.
Click the <<play black>> link to play a black card.
</span>
<hr>
<span id="action">$atext</span>
:: StoryInit {"position":"100,100","size":"100,100"}
<<set $reds = 0>>
<<set $blacks = 0>>
<<set $atext = 'Here the action text will be shown.'>>
:: Widgets [widget] {"position":"500,100","size":"100,100"}
<<nobr>>
<<widget play-red>>
<<set $reds = $reds + 1>>
<<set $atext = "You play a red card.">>
<</widget>>
<<widget play-black>>
<<set $blacks = $blacks + 1>>
<<set $atext = "You play a black card.">>
<</widget>>
<<widget play>>
<<link _args[0]>>
<<if _args[0] == 'red'>>
<<play-red>>
<<else>>
<<play-black>>
<</if>>
<<goto Room>>
<</link>>
<</widget>>
<</nobr>>
I need that goto to ensure saves work for my game. As I understand it, a save only works for the state preserved at the last page transition. If I never change the page (and goto to itself also counts as a transition), then a save game would not work.
That is largely true, State is only saved as a moment in the history when a passage transition happens.
So, since you refreshing the passage, your original <<replace>> does nothing, and I see you have removed it now. Basically <<replace>> helps with dynamically updating the passage when something changes without a passage load. If you are navigating to new passages, or reloading the current one, you donât need it.
A different question, of course, is why only have one passage.
I wanted to offer a lightweight alternative (less clicking on links) to what the âdefaultâ appears to be: using a passage for each and every action.
And we are back were we started. Half the number of clicks needed (but we need more screen space, so potentially more scrolling if played on mobile devices with limited screen space.)
Technically the page mode is working as it should, but that is due to the fact the widget is always executed exactly once. I merely tried to get the same effect for the flow mode.
Agreed. Although it might be possible to find a way to get it working, I rather spend time on getting other things working, so I dropped the flow mode idea for now. I do like the widget mechanics, I consider them âlightweight passagesâ and they allow me to put related actions together in the same file.