Using shared functions for keeping GlobalScript clean

Started by js, Mon 05/09/2022 17:19:19

Previous topic - Next topic

js

Hello,

Not really a question, but a summary of an interesting discussion in Discord chan.
I’m just quoting what was said on discord-chan, with a bit of editing for readability (i’ve left curses and swears).

My question was:
« How to avoid multiples functions to be created in GlobalScript, cluttering it ? Especially for Characters signal handling ».

Laura Hunt had an excellent idea:

You could create a generic function cGenericCharacterInteract().
Then with a single switch, trigger the function corresponding to the character you just clicked on:

Code: ags

function cGenericCharacter_Interact()
{
   Character*char = Character.GetAtScreenXY(mouse.x, mouse.y);
   switch (char) {
     case cPeter: PeterTalk(); break;
     case cPaul: PaulTalk(); break;
     case cMary: MaryTalk(); break;
     // etc etc
   }
}


and of course, PeterTalk() , PaulTalk() , … would be placed in another castle script file.

That’s a great idea ! I adopted it immediately, but …

(play plot_twist.xm)

Enters crimson wizard:

The problem with the above approach is that theoretically this function may be called not when the character was clicked; or not when it is the one in front.
For example, there’s Character.RunInteraction() function. It will trigger this callback too, and it may be run regardless of the mouse cursor and clicks.

As a reminder,  Character.RunInteraction()  do that:
Fires the event script as if the player had clicked the mouse on the character in the specified cursor mode. This is one of the mouse cursor modes, as defined in your Cursors tab in the editor.

That means that your mouse cursor could be anywhere on the screen, and in this case, the code above (finding the character under the mouse cursor) won't work.

So the above method will break in such case.
It also won’t work in case of keyboard / gamepad controls.

Thinking more on this, in such case it may be worked around by saving the character you are interacting with in a global variable, whenever you call RunInteraction.

The ideal solution would be to have a Character pointer in the callbacks.
(like GUI OnClick callbacks, in which GUI pointer is already there).

A pointer would just tell which character is interacted with.

Then Crimson Wizard has opened a ticket for adding Character * passing to the callback.

https://github.com/adventuregamestudio/ags/issues/1765

(to be continued)

newwaveburritos

Oh, yeah, thanks for posting this because I was following the conversation with great interest and trying to think of a way to record it for later usage.  You've done it for me!  Thanks!!

Khris

Since this approach still requires pasting cGenericInteract into each character's event table, there's another approach that also solves the "which character?" issue, and the keyboard / gamepad issue: calling the function yourself in on_mouse_click (or some other handler). That way you can pass any additional parameters you want.

For basic cursor interactions you can use GetLocationType(), and by storing the mouse coordinates and using them for both that function and Character.GetAtScreenXY() it is all but ensured you'll get an actual character.

Keyboard or gamepad controls will already have picked the character in repeatedly execute when a button is pressed which means you can directly use the variable storing the currently highlighted character in your generic function.

SMF spam blocked by CleanTalk