scripting unhandled_event

Started by HandsFree, Mon 26/09/2011 18:05:23

Previous topic - Next topic

HandsFree

In unhandled_event I have:

else if (mouse.Mode == eModeUseinv){
      if (GetLocationType(mouse.x, mouse.y) == eLocationNothing) return; // do nothing
      if (player.ActiveInventory == iMoney){
        player.Say("That's not for sale");}

This ensures that you only get the response if you click the money on a hotspot or object.
But... if there is a scripted response for another inventory item on that hotspot, nothing happens.
I understand that that is how this code works. But is there a way to script it so you also get the response "That's not for sale" if there's existing code for another inventory item?

thanks

Khris

Import the function in the global header:

Code: ags
import function unhandled_event (int what, int type);


Now you can call it yourself:

Code: ags
// object_UseInv()

  if (player.ActiveInventory == iUsefulItem) {
    ...
    ...
  }
  else unhandled_event(2, 3);


Since the numbering of the parameters is really weird and doesn't correspond to the location types or cursor modes (at least not always), it's probably best to write your own unhandled function which uses mouse.Mode and GetLocationType() and have unhandled_event call that, otherwise you're stuck with supplying two useless parameters every time.

Btw, if the player interacted with nothing, the WHAT parameter equals 4, so you can use that at the start of unhandled_event:
Code: ags
  // ignore clicks on nothing
  if (what == 4) return;

monkey0506

#2
You really shouldn't be using mouse.Mode and GetLocationType inside of unhandled_event. That's what the what and type parameters are for. They're kind of a mess to work with to be perfectly honest, but why go and force the engine to look up information you already know? Besides, it might lead to inconsistency if the mouse mode has changed after the unhandled_event function is queued but before it's called.

If I understand your question correctly what you're saying is that there is a scripted event for hHotspotX_UseInv, but you want unhandled_event to be fired if the individual item itself isn't handled within that function, right?

AGS currently doesn't automatically handle that very well, but it's simple enough to get around it with a bit of scripting. What I'd actually recommend doing is to create a custom wrapper function to encapsulate the built-in unhandled_event, such as:

Code: ags
// GlobalScript.ash

import void UnhandledEvent(LocationType, CursorMode, InventoryItem*=0);

// GlobalScript.asc

void UnhandledEvent(LocationType type, CursorMode mode, InventoryItem *clickedItem)
{
  // put your code here
  // type will be what the user clicked on: eLocationCharacter, eLocationHotspot, eLocationObject, or eLocationNothing (this includes inventory of course)
  // mode is the cursor mode at the time the user clicked on the item
  // clickedItem is only used if type is eLocationNothing and the user clicked on an inventory item, and stores the item that they clicked on
  // you'll still want to use player.ActiveInventory here as appropriate
}

void unhandled_event(int what, int type)
{
  // this is of course the built-in function, but we'll use it just to automatically call your custom function
  // first, define our variables
  LocationType locType = eLocationNothing;
  CursorMode mode = 0;
  InventoryItem *clickedItem = null;
  // now give them their appropriate values
  if (what == 1) locType = eLocationHotspot;
  else if (what == 2) locType = eLocationObject;
  else if (what == 3) locType = eLocationCharacter;
  // if what is 4, then it's nothing, no need to set it again
  else if (what == 5) clickedItem = inventory[game.inv_activated]; // inventory is also treated as nothing, but store the item
  if ((what == 2) || (what == 3) || (what == 5))
  {
    // objects, characters, and inventory share similar type values
    if (type == 0) mode = eModeLookat;
    else if (type == 1) mode = eModeInteract;
    else if (type == 2) mode = eModeTalkto;
    else if (type == 3) mode = eModeUseinv;
    else if (type == 4) mode = game.used_mode; // applies only to inventory items, use the mode of the last click
    else if (type == 5) mode = eModePickup; // doesn't apply to inventory
    else if (type == 6) mode = eModeUsermode1; // doesn't apply to inventory
    else if (type == 7) mode = eModeUsermode2; // doesn't apply to inventory
  }
  else
  {
    // hotspots and nothing share similar type values
    if (type == 1) mode = eModeLookat;
    else if (type == 2) mode = eModeInteract;
    else if (type == 3) mode = eModeUseinv;
    else if (type == 4) mode = eModeTalkto;
    else if (type == 7) mode = eModePickup; // doesn't apply to nothing (hah, grammar)
    else if (type == 8) mode = eModeUsermode1; // doesn't apply to nothing
    else if (type == 9) mode = eModeUsermode2; // doesn't apply to nothing
  }
  // finally, call the custom function
  UnhandledEvent(locType, mode, clickedItem);
}


Khris beat me to the post, but yes, we both had the same idea about a custom function. :P

Oh, and not to knock what Khris said, but I'd actually recommend against importing unhandled_event globally, because it might cause some type of crazy conflict seeing as any script file (including room scripts) are allowed their own unhandled_event handler. As an example of how you would actually define the UnhandledEvent function that I showed above:

Code: ags
void UnhandledEvent(LocationType type, CursorMode mode, InventoryItem *clickedItem)
{
  if (type == eLocationNothing)
  {
    if (clickedItem == null) return;
    if (player.ActiveInventory != null) player.Say("I can't use the %s on the %s!", player.ActiveInventory.Name, clickedItem.Name);
    else player.Say("I can't do that to the %s!", clickedItem.Name);
  }
  else if (type == eLocationCharacter)
  {
    if (mode == eModeInteract) player.Say("I don't think I should touch them.");
    else if (mode == eModeLookat) player.Say("Looks like a generic NPC if you ask me.");
  }
  // ...
}


And you could still call it similarly to how Khris showed calling unhandled_event, but you would pass more meaningful parameters. Oh, and the InventoryItem* parameter at the end is optional, so you can leave it off when calling the function yourself.

HandsFree

I should have mentioned that I'm using the RON template and it has already a function unhandled_event in GlobalScript.asc.
In that function there is already a lot of pre-scripted code, including
if (mouse.Mode == eModeLookat){...}
if (mouse.Mode == eModeTalkto){...}

Does that make a difference? I prefer not to break up what's already there, especially as I'm working on the last finishing touches.
Importing the function is no problem of course (I hope).

SMF spam blocked by CleanTalk