Calling Room function via Global Script.

Started by Silent Bob, Wed 30/07/2014 19:19:50

Previous topic - Next topic

Silent Bob

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.
If you wanna do something - you seek for solution, if you don't want to - you seek for a reason.

Cassiebsg

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.
There are those who believe that life here began out there...

Crimson Wizard

#2
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

// 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

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

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

Khris

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.

Silent Bob

Thank You all guys :)

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

Cheers!
If you wanna do something - you seek for solution, if you don't want to - you seek for a reason.

Mehow

#5
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'.

:(
If you wanna do something - you seek for solution, if you don't want to - you seek for a reason.

Mehow

If you wanna do something - you seek for solution, if you don't want to - you seek for a reason.

Crimson Wizard

#7
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

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.

Mehow

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);
}
If you wanna do something - you seek for solution, if you don't want to - you seek for a reason.

Crimson Wizard

#9
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

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).

Mehow

#10
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.
If you wanna do something - you seek for solution, if you don't want to - you seek for a reason.

Crimson Wizard

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?

Khris

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.

SMF spam blocked by CleanTalk