Get hotspot by reference?

Started by Nine Toes, Sat 24/05/2025 05:30:18

Previous topic - Next topic

Nine Toes

This didn't feel like a noobie question.

I'm scripting some simple interactions with hotspots in a room. I'm trying to figure out if there's a way I can dynamically grab some sort of reference to the hotspot in question.

I tried this...
Code: ags
function hHotspot3_Talk(Hotspot *theHotspot, CursorMode mode)
{
  Display("You can't talk to the %s", theHotspot.GetTextProperty("Description"));
}

And this...
Code: ags
function hHotspot3_Talk(Hotspot *theHotspot, CursorMode mode)
{
  Display("You can't talk to the %s", this.GetTextProperty("Description"));
}

Neither work.

And, even though this isn't what I was aiming for, I tried this...
Code: ags
function hHotspot3_Talk(Hotspot *theHotspot, CursorMode mode)
{
  Display("You can't talk to the %s", hHotspot3.GetTextProperty("Description"));
}

This sort of works, but I'm getting an error message that "Description" isn't a property of that hotspot?

I figured, instead of manually typing out in every "silly" interaction, "you can't look at/talk to/open/take the...", that I'd eliminate repeating code and make a couple global functions that I could plug the reference for the hotspot into, and it would deliver the message to the player. Like this:
Code: ags
function youCantTalkToThe(hotspotRef){
  Display("You can't talk to the %s", hotspotRef.GetTextProperty("Description"));
}

// In my room script
function hHotspot3_Talk(Hotspot *theHotspot, CursorMode mode)
{
  youCantTalkToThe(thisHotspotRef);
}

Which would output to the player:
QuoteYou can't talk to the porch.

So what am I doing wrong?
Watch, I just killed this topic...

Crimson Wizard

#1
GetProperty and GetTextProperty work only with the custom properties, not standard ones. For standard ones there are explicit properties declared as a part of Hotspot type.

The property which is called "Description" in the Editor is actually called Name in script:
https://adventuregamestudio.github.io/ags-manual/Hotspot.html#hotspotname

So the code will be:
Code: ags
Display("You can't talk to the %s", theHotspot.Name);

EDIT:
Other than that, this function declaration misses a argument type
Code: ags
function youCantTalkToThe(hotspotRef){

It should be:
Code: ags
function youCantTalkToThe(Hotspot* hotspotRef){

Nine Toes

#2
@Crimson Wizard: Excellent. It works. Thank you.

Code: ags
function youCantTalkToThe(Hotspot* hotSpotRef)
{
  Display("You can't talk to the %s", hotSpotRef.Name);
}

// room script
function hHotspot3_Talk(Hotspot *theHotspot, CursorMode mode)
{
  youCantTalkToThe(theHotspot);
}

I have minimal understanding of C++; my background is mostly web languages. But by placing the asterisk immediately after the data type, I'm essentially saying "get the passed hotspot from the above function"?
Watch, I just killed this topic...

Khris

#3
Hotspots are objects, not in the AGS sense but in terms of programming. References to them are stored in pointers, declaring those requires an asterisk.

Code: ags
int a; // primitive value, initially 0
Hotspot* h; // pointer, initially pointing to null

(JavaScript is weakly typed and therefore doesn't require asterisks, every variable can store all data types.)

Regarding the general feature you're implementing, AGS already has a built-in handler for unhandled events:
https://adventuregamestudio.github.io/ags-manual/Globalfunctions_Event.html#unhandled_event

Unfortunately, there's no way to get the actual hotspot inside this function. One way to fix this is to add some lines above and inside on_mouse_click:
Code: ags
// above
LocationType _lt;
Hotspot* _h;
Object* _o;
Character* _c;

    // inside on_mouse_click / eMouseLeft in a standard template
    int x = mouse.x, y = mouse.y;
    _lt = GetLocationType(x, y);
    if (_lt == eLocationHotspot) _h = Hotspot.GetAtScreenXY(x, y); else _h = null;
    if (_lt == eLocationObject) _o = Object.GetAtScreenXY(x, y); else _o = null;
    if (_lt == eLocationCharacter) _c = Character.GetAtScreenXY(x, y); else _c = null;
    Room.ProcessClick(x, y, mouse.Mode); // this is the existing line

Now put this somewhere below the on_mouse_click function:
Code: ags
function unhandled_event(int what, int type)
{
  if (what == 1) // hotspots
  {
    if (type == 4) // TalkTo was used
    {
      Display("You can't talk to the %s.", _h.Name); // should be save to assume _h isn't null
    }
  }
}


--

You can also skip the somewhat outdated built-in function like this:
Code: ags
function Unhandled_Hotspot(Hotspot* h, CursorMode mode) {
  if (mode == eModeTalkto) Display("You can't talk to the %s.", h.Name);
}

    // on_mouse_click / eMouseLeft
    int x = mouse.x, y = mouse.y;
    if (!IsInteractionAvailable(x, y, mouse.Mode)) {
      int lt = GetLocationType(x, y);
      if (lt == eLocationHotspot) Unhandled_Hotspot(Hotspot.GetAtScreenXY(x, y), mouse.Mode);
    }
    else Room.ProcessClick(x, y, mouse.Mode);

Crimson Wizard

Quote from: Nine Toes on Sat 24/05/2025 07:06:35I have minimal understanding of C++; my background is mostly web languages. But by placing the asterisk immediately after the data type, I'm essentially saying "get the passed hotspot from the above function"?

There's no difference whether asterisk is right after data type or with a space in-between, AGS script (and also C and C++) treat these as the same thing. Where to place it in your code is only a matter of the code style.
In the above example this declaration sais "pass the hotspot INTO the function". If you would like to get the hotspot FROM the function, then that should be a return value instead, like:

Code: ags
Hotspot* getSomeHotspot()

SMF spam blocked by CleanTalk