How to make multiple links perform the same (complex) set of actions?

Twine Version: 2
Story Format: Harlowe

Hi! I think this is quite an advanced one. I’ve managed to create a set-up where every time the player clicks within a certain space, it adds to their score, updates the text on the page (once the score passes a certain threshold) and fills a little bar up. This all works nicely.

However, I now want to have the player click individual words, which then disappear. I’ve got two problems – I can’t seem to combine the normal ‘link’ or ‘link-reveal’ macro with the rest of my code. Either the words disappear, or the score updates, but not both at the same time.

The other problem is I don’t want to repeat my code for every single clickable link – there’s too much of it. It’d be better if I could have each link disappear and at the same time call in a passage that runs all the code and then vanishes itself. Something like that?

At the moment, this is the code:

[(display: "UpdateScore")]<scorelogic|\
\[]<reaction|
</div>

The ‘UpdateScore’ passage which is set to display is as follows:

{[<div style="position: absolute; top: 0; left: 0; width: 100vw; height: 100vh;"></div>]<link|(click: ?link)[

  (if: $score is 20)[(replace: ?reaction)[<div class="shake">(She raised a thuggish brow.)</div>]]
  (if: $score is 50)[(replace: ?reaction)[<div class="shake">(She pinched her cuffs till they were taut.)</div>]]
   (if: $score is 80)[(replace: ?reaction)[<div class="shake">(She smoothed her sails. She thumbed her ruff.)</div>]]

  (if: $score > 99)[(go-to: "I'd come forearmed")]

  (else:)[
	(set: $score to it + 10)
	(print: "<script>GE.updateScore(" + (text: $maxScore) + "," + (text: $score) + ");")
	(replace: ?scorelogic)[(display: "UpdateScore")]
]



]}

note: You didn’t supply an example of the JavaScript code used to define the GE.updateScore() function, so I used the following in my test project…

window.GE = {
  updateScore: function (maxScore, score) {
    console.log('max: ' + maxScore + '; score: ' + score);
  }
};

…which just outputs the values passed to the function.

The following are a couple of corrections I would make to your examples:

1: Recent version of Harlowe 3.x support variable substitution within the contents of a HTML <script> element. So the following line in your example…

(print: "<script>GE.updateScore(" + (text: $maxScore) + "," + (text: $score) + ");")

…can be replaced with just…

<script>GE.updateScore($maxScore, $score);</script>

2: Generally when you have a consecutive series of (if:) macros that have related (mutually exclusive) conditional expressions the 2nd and later (if:) macros would be replaced with (else-if:) macro calls.

(if: $score is 20)[...do something...]
(else-if: $score is 50)[...do something else...]
(else-if: $score is 80)[...do a third thing instead...]
(else-if: $score > 99)[...do a forth thing instead...]

And in situations where you want to do a “common” thing for all other related conditions then you would add an (else:) macro call at the end…

(if: $score is 20)[...do something...]
(else-if: $score is 50)[...do something else...]
(else-if: $score is 80)[...do a third thing instead...]
(else-if: $score > 99)[...do a forth thing instead...]
(else:)[ ...do the thing for when score is not 20 or 50 or 80 or greater-than 99...]

There are a number of methods you can use to reuse code, and you are already using one of them to access the content of the UpdateScore Passage

1: Place the “common” code within a “known” child Passage, and then use the (display:) macro as needed to execute that code.

eg. Create a Passage named something like Check Score and place the (if:) family of macro calls within it. You can then use a (display:) macro within the associated Hook of each link to execute that the (if:) family of macro calls.

The following TWEE Notation based example demonstrates doing such…

:: Lots of Links
(link-repeat: "Option 1")[
	(display: "Check Score")
]
(link-repeat: "Option 2")[
	(display: "Check Score")
]
(link-repeat: "Option 3")[
	(display: "Check Score")
]


:: Check Score
(if: $score is 20)[...do something...]
(else-if: $score is 50)[...do something else...]
(else-if: $score is 80)[...do a third thing instead...]
(else-if: $score > 99)[...do a forth thing instead...]
(else:)[ ...do the thing for when score is not 20 or 50 or 80 or greater-than 99...]

2: Place the “common” code within the body of a custom (macro:) definition.

Thanks very much, Grey Elf!