Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: Silent Bob on Wed 30/07/2014 19:19:50

Title: Calling Room function via Global Script.
Post by: Silent Bob on Wed 30/07/2014 19:19:50
Hey there,

I have defined couple of hotspots in a given room. When the mouse is over a hotspot, the cursor changes into a specifed graphic-mode, which is a prompt that a given 'thing' is clickable. When i click on a given hotspot (let's say for example I click on Trash-Bin) it releases custom GUI with two buttons 'talk to' and 'interact'. Each button's script is in GlobalScript by default, so my question is - how can I release a function defined in ROOM (like look_at trash bin) script, by clicking a button which has its code defined in GlobalScript? The mentioned GUI will be common for all hotspots, and I have an idea how to 'tell' the program which hotspot was clicked, but i can't figure out how to call a ROOM function from global script :embarrassed:

Thanks.
Title: Re: Calling Room function via Global Script.
Post by: Cassiebsg on Wed 30/07/2014 19:28:23
Try looking at Import and Export commands. :) And remember that in Global Script you need to refer to hotspots by their ID, not their name.

Hope it helps.
Title: Re: Calling Room function via Global Script.
Post by: Crimson Wizard on Wed 30/07/2014 19:38:33
Quote from: Cassiebsg on Wed 30/07/2014 19:28:23
Try looking at Import and Export commands. :) And remember that in Global Script you need to refer to hotspots by their ID, not their name.
This won't work in this case, because functions are in room script, not global, nor custom modules.

The solution could be to remember the clicked Hotspot by pointer, then call "RunInteraction" function.

Following is a simple example:
1. When you process click upon hotspot, store current hotspot in a global variable:
Code (ags) Select

// in GlobalScript.ash
import Hotspot *InteractedHotspot;

// in GlobalScript.asc
Hotspot *InteractedHotspot;
export InteractedHotspot;

// in whatever script function you are calling your GUI:
....
InteractedHotspot = Hotspot.GetAtScreenXY(mouse.x, mouse.y);
....


2. When the user clicks button, use the remembered hotspot to call for particular interaction type:
Code (ags) Select

InteractedHotspot.RunInteraction(eModeLookat);


//---------------------------------------------
You may also simplify your life by writing a function which both stores object and shows GUI. This way you will be able to add Room Objects and Characters for your interaction system:
Code (ags) Select

function ShowInteractionGUI()
{
    InteractedHotspot = Hotspot.GetAtScreenXY(mouse.x, mouse.y);
    InteractedObject = Object.GetAtScreenXY(mouse.x, mouse.y);
    InteractedCharacter = Character.GetAtScreenXY(mouse.x, mouse.y);

    MyGUI.Visible = true;
}

function DoPlayerInteraction(CursorMode mode)
{
    if (InteractedHotspot != null)
        InteractedHotspot.RunInteraction(mode);
    else if (InteractedObject != null)
        InteractedObject.RunInteraction(mode);
    else if (InteractedCharacter != null)
        InteractedCharacter.RunInteraction(mode);
}

function ClickedOnLookatButton()
{
    DoPlayerInteraction(eModeLookat);
}

function ClickedOnTalkToButton()
{
    DoPlayerInteraction(eModeTalk);
}

/// etc
Title: Re: Calling Room function via Global Script.
Post by: Khris on Wed 30/07/2014 23:01:35
There's also the ProcessClick() function, this is what the default game uses in on_mouse_click().
You'd store the screen coordinates of the first click, then call ProcessClick() on them from your button's OnClick.
Title: Re: Calling Room function via Global Script.
Post by: Silent Bob on Wed 30/07/2014 23:59:01
Thank You all guys :)

In the end I used Wizard's solution - works like charm! :)

Cheers!
Title: Re: Calling Room function via Global Script.
Post by: Mehow on Thu 31/07/2014 08:45:35
Crimson,

I have implemented your solution (step 1, 2), and it works just fine, but I've got problem with your second solution - somehow it does not work. I'm getting a message 'Cannot convert object to hotspot'.

:(
Title: Re: Calling Room function via Global Script.
Post by: Mehow on Thu 31/07/2014 08:52:47
Never mind. I figured out. Thanks :)
Title: Re: Calling Room function via Global Script.
Post by: Crimson Wizard on Thu 31/07/2014 11:12:07
Quote from: Khris on Wed 30/07/2014 23:01:35
There's also the ProcessClick() function, this is what the default game uses in on_mouse_click().
You'd store the screen coordinates of the first click, then call ProcessClick() on them from your button's OnClick.
Right, I forgot you can pass cursor mode to the ProcessClick as well.
If you don't need to know anything about selected object, that would be simplier way.
OTOH, if you want to use some hotspot/object etc properties in your GUI processing, or before calling actual interaction, then you'll need to store the object pointer.

Example variant with ProcessClick:
Code (ags) Select

function ShowInteractionGUI()
{
    InteractionX = mouse.X;
    InteractionY = mouse.Y;
    MyGUI.Visible = true;
}

function DoPlayerInteraction(CursorMode mode)
{
    ProcessClick(InteractionX, InteractionY, mode);
}


Or, you may combine both, and keep object pointer and mouse coords... depends on what are you trying to do.
Title: Re: Calling Room function via Global Script.
Post by: Mehow on Fri 01/08/2014 00:24:04
Hey Wizard,

For some strange reason this part of script doesn't work or I'm doing something wrong ??? (there's a situation, where particular functions work on Hotspot click for example, but don't work on Characters clicking - they don't even start).

function DoPlayerInteraction(CursorMode mode)
{
    if (InteractedHotspot != null)
        InteractedHotspot.RunInteraction(mode);
    else if (InteractedObject != null)
        InteractedObject.RunInteraction(mode);
    else if (InteractedCharacter != null)
        InteractedCharacter.RunInteraction(mode);
}


...but, everything works just fine when each condition is autonomous :):

function DoPlayerInteraction(CursorMode mode)
{
    if (InteractedHotspot != null)
        InteractedHotspot.RunInteraction(mode);
    if (InteractedObject != null)
        InteractedObject.RunInteraction(mode);
    if (InteractedCharacter != null)
        InteractedCharacter.RunInteraction(mode);
}
Title: Re: Calling Room function via Global Script.
Post by: Crimson Wizard on Fri 01/08/2014 00:43:02
Duh! My mistake.

In AGS the hotspots are everywhere, when there's none, it is Hotspot0 (same with Regions, and other "areas").
So...
Code (ags) Select

if (InteractedHotspot != hotspot[0])


On other hand, you may want to interact with Hotspot0 as well. The solution could be to change the order of conditions, making Hotspots go last.
Using a sequence of "if" blocks, as you did, will trigger everything found beyond mouse (I think it may trigger both Character and Hotspot, for example).
Title: Re: Calling Room function via Global Script.
Post by: Mehow on Fri 01/08/2014 01:18:17
Yes, You're right - if there will be a situation that a given character stands over the hotspot, and a mouse is over a character (so is over a hotspot too) then it will trigger both conditions probably ;/. I returned to the first shape of Your script and did as You suggest and move the condition line with hotspot to the end, and it seems to work. I wonder why does it make a difference? - You know... when the hotpost line is the first line, then - the character condition doesn't work, but when it's the last line, both conditions work fine.
Title: Re: Calling Room function via Global Script.
Post by: Crimson Wizard on Fri 01/08/2014 09:34:57
Quote from: Mehow on Fri 01/08/2014 01:18:17I wonder why does it make a difference? - You know... when the hotpost line is the first line, then - the character condition doesn't work, but when it's the last line, both conditions work fine.
Hmm, can you post the code that has this behavior?
Title: Re: Calling Room function via Global Script.
Post by: Khris on Fri 01/08/2014 16:20:38
AFAIK the GetAtScreenXY functions will return active elements regardless of others covering them, so you can get multiple "hits".
A simple solution is to use GetLocationType to figure out the topmost active element at the given coordinates first.

Or, you know, just use ProcessClick(). Like CW said, unless you need to read properties or deal with special situations, ProcessClick() takes the entire work off your hands.