Changes in Verb Coin Code

Started by DBoyWheeler, Wed 13/09/2023 11:55:27

Previous topic - Next topic

DBoyWheeler

So I saw the newer verb coin set up when you start making a new game.  But the way it set up with directions (North, West, etc.) might not work well with the verb coin I want to use.

Here's what I plan as a set up.

(I've made separate buttons with a snowflake style background--the bottom three are special buttons.)

And I've already commented out the stuff in the verb coin code for directions.
Spoiler
Code: ags
// Script header for VerbCoin script module
#define VERBCOIN_DEFAULT_RADIUS 38
#define VERBCOIN_DEFAULT_BACKGROUND_TRANSPARENCY 80
#define VERBCOIN_DEFAULT_BACKGROUND_COLOR 32089
#define VERBCOIN_DEFAULT_BORDER_COLOR 19248
#define VERBCOIN_DEFAULT_BORDER_WIDTH 1

#ifdef SCRIPT_API_v3507
#define SCREEN_WIDTH Screen.Width
#define SCREEN_HEIGHT Screen.Height
#endif
#ifndef SCRIPT_API_v3507
#define SCREEN_WIDTH System.ViewportWidth
#define SCREEN_HEIGHT System.ViewportHeight
#endif

//enum VerbCoinPosition {
//  eVerbCoinPositionNorth,
//  eVerbCoinPositionEast,
//  eVerbCoinPositionSouth,
//  eVerbCoinPositionWest
//};

struct VerbCoin {
  import static attribute int Radius;
  import static attribute int BackgroundTransparency;
  import static attribute int BackgroundColor;
  import static attribute int BorderColor;
  import static attribute int BorderWidth;
  import static function OnClick(GUIControl* control, MouseButton button);
  import static function RegisterButton(GUIControl* control, VerbCoinPosition position, CursorMode mode, String verbtext);
  import static attribute GUI* InterfaceGui;
  import static attribute GUI* InventoryGui;
  import static attribute Label* ActionLabel;
  import static function Enable();
  import static function Disable();
  import static function IsEnabled();
  import static function Open();
  import static function Close();
  import static function IsOpen();
  import static function CleanUp();
  import static attribute bool ButtonAutoDisable;
};
[close]
And
Spoiler
Code: ags
// sprite for the GUI background
DynamicSprite* sprite;

// GUI to use for the verbcoin
GUI* interface;

// inventory GUI to use
GUI* interface_inv;

// label to use for text actions
Label* action_label;

// default settings
int radius = VERBCOIN_DEFAULT_RADIUS;
int background_color = VERBCOIN_DEFAULT_BACKGROUND_COLOR;
int background_transparency = VERBCOIN_DEFAULT_BACKGROUND_TRANSPARENCY;
int border_color = VERBCOIN_DEFAULT_BORDER_COLOR;
int border_width = VERBCOIN_DEFAULT_BORDER_WIDTH;
int redraw = false;

// track where the interface was opened from
int context_x;
int context_y;
String context_text;

// map GUI controls against cursor modes
int modemap[];

// map GUI controls against text descrptions
String actionmap[];

// enable click handling and action label updates
bool enabled = false;

// whether buttons will be disabled if clicking them would result in an unhandled event
bool button_auto_disable = false;

function Clamp(static Maths, int value, int min, int max)
{
  if (value < min)
  {
    value = min;
  }

  if (value > max)
  {
    value = max;
  }

  return value;
}

function Min(static Maths, int value1, int value2)
{
  if (value1 > value2)
  {
    return value2;
  }

  return value1;
}

function set_buttons_enabled(bool state)
{
  for (int i; i < interface.ControlCount; i ++)
  {
    if (interface.Controls[i].AsButton != null)
    {
      interface.Controls[i].Enabled = state;
    }
  }
}

void set_Radius(static VerbCoin, int newradius)
{
  if (newradius < 1)
  {
    newradius = 1;
  }

  if (newradius != radius)
  {
    radius = newradius;
    redraw = true;
  }
}

int get_Radius(static VerbCoin)
{
  return radius;
}

void set_BackgroundTransparency(static VerbCoin, int transparency)
{
  transparency = Maths.Clamp(transparency, 0, 100);

  if (transparency != background_transparency)
  {
    background_transparency = transparency;
    redraw = true;
  }
}

int get_BackgroundTransparency(static VerbCoin)
{
  return background_transparency;
}

void set_BackgroundColor(static VerbCoin, int color)
{
  color = Maths.Clamp(color, 0, 65535);

  if (color != background_color)
  {
    background_color = color;
    redraw = true;
  }
}

int get_BackgroundColor(static VerbCoin)
{
  return background_color;
}

void set_BorderColor(static VerbCoin, int color)
{
  color = Maths.Clamp(color, 0, 65535);

  if (color != border_color)
  {
    border_color = color;
    redraw = true;
  }
}

int get_BorderColor(static VerbCoin)
{
  return border_color;
}

void set_BorderWidth(static VerbCoin, int width)
{
  width = Maths.Clamp(width, 0, radius);

  if (width != border_width)
  {
    border_width = width;
    redraw = true;
  }
}

int get_BorderWidth(static VerbCoin)
{
  return border_width;
}

static function VerbCoin::OnClick(GUIControl* control, MouseButton button)
{
  if (interface != null)
  {
    interface.Visible = false;
  }

  if (modemap != null && (button == eMouseLeft || button == eMouseRight))
  {
    Room.ProcessClick(context_x, context_y, modemap[control.ID]);
  }
}

function place_button(GUIControl* control, VerbCoinPosition position)
{
  float edge;

  if (position == eVerbCoinPositionNorth || position == eVerbCoinPositionSouth)
  {
    edge = IntToFloat(control.Width) / 2.0;
  }
  else
  {
    edge = IntToFloat(control.Height) / 2.0;
  }

  float squared = Maths.RaiseToPower(IntToFloat(radius), 2.0) - Maths.RaiseToPower(edge, 2.0);

  if (squared < 0.0)
  {
    squared = 0.0;
  }

  float offset = Maths.Sqrt(squared);

  //if (position == eVerbCoinPositionNorth)
  //{
  //  control.X = radius - FloatToInt(edge);
  //  control.Y = radius - FloatToInt(offset, eRoundDown);
  //}
  //else if (position == eVerbCoinPositionEast)
  //{
  //  control.X = radius + FloatToInt(offset, eRoundUp) - control.Width;
  //  control.Y = radius - FloatToInt(edge);
  //}
  //else if (position == eVerbCoinPositionSouth)
  //{
  //  control.X = radius - FloatToInt(edge);
  //  control.Y = radius + FloatToInt(offset, eRoundUp) - control.Height;
  //}
  //else if (position == eVerbCoinPositionWest)
  //{
  //  control.X = radius - FloatToInt(offset, eRoundDown);
  //  control.Y = radius - FloatToInt(edge);
  //}
}

//static function VerbCoin::RegisterButton(GUIControl* control, VerbCoinPosition position, CursorMode mode, String action)
//{
//  if (control.OwningGUI == interface && control.AsButton != null)
//  {
//    place_button(control, position);
//    modemap[control.ID] = mode;
//    actionmap[control.ID] = action;
//    control.Visible = true;
//  }
//}

function render()
{
  // resize the GUI to fit the sprite
  int gui_size = radius * 2;
  gui_size = Maths.Min(gui_size, SCREEN_HEIGHT);
  gui_size = Maths.Min(gui_size, SCREEN_WIDTH);
  gui_size ++;
  interface.Width = gui_size;
  interface.Height = gui_size;

  DynamicSprite* background = DynamicSprite.Create(interface.Width, interface.Height, true);
  DrawingSurface* surface;

  // redraw the sprite
  surface = background.GetDrawingSurface();
  surface.DrawingColor = border_color;
  surface.DrawCircle(radius, radius, radius);
  surface.DrawingColor = background_color;
  surface.DrawCircle(radius, radius, radius - border_width);
  surface.Release();

  sprite = DynamicSprite.Create(interface.Width, interface.Height, true);
  surface = sprite.GetDrawingSurface();
  surface.DrawImage(0, 0, background.Graphic, background_transparency);
  background.Delete();
  surface.Release();
  interface.BackgroundGraphic = sprite.Graphic;
}

void set_InterfaceGui(static VerbCoin, GUI* interface_gui)
{
  interface = interface_gui;

  for (int i; i < interface.ControlCount; i ++)
  {
    if (interface.Controls[i].AsButton != null)
    {
      interface.Controls[i].Visible = false;
    }
  }

  modemap = new int[interface.ControlCount];
  actionmap = new String[interface.ControlCount];
  enabled = true;
  render();
}

GUI* get_InterfaceGui(static VerbCoin)
{
  return interface;
}

void set_InventoryGui(static VerbCoin, GUI* inventory_gui)
{
  interface_inv = inventory_gui;
}

GUI* get_InventoryGui(static VerbCoin)
{
  return interface_inv;
}

void set_ActionLabel(static VerbCoin, Label* label)
{
  action_label = label;
  action_label.Text = "";
}

Label* get_ActionLabel(static VerbCoin)
{
  return action_label;
}

static function VerbCoin::Enable()
{
  enabled = true;
  set_buttons_enabled(true);
}

static function VerbCoin::Disable()
{
  enabled = false;
  set_buttons_enabled(false);
}

static function VerbCoin::IsEnabled()
{
  return enabled;
}

static function VerbCoin::Open()
{
  if (interface != null)
  {
    interface.Visible = true;
  }
}

static function VerbCoin::Close()
{
  if (interface != null)
  {
    interface.Visible = false;
  }
}

static function VerbCoin::IsOpen()
{
  return interface != null && interface.Visible;
}

static function VerbCoin::CleanUp() {
  if (sprite != null) sprite.Delete();
}

void set_ButtonAutoDisable(static VerbCoin, bool autodisable)
{
  button_auto_disable = autodisable;
}

bool get_ButtonAutoDisable(static VerbCoin)
{
  return button_auto_disable;
}

function on_mouse_click(MouseButton button)
{
  if (interface == null || !enabled)
  {
    // don't do anything if GUI isn't set or is disabled
  }
  else if (button == eMouseLeft)
  {
    if (GetLocationType(mouse.x, mouse.y) != eLocationNothing)
    {
      if (player.ActiveInventory != null)
      {
        Room.ProcessClick(mouse.x, mouse.y, eModeUseinv);
      }
      else if (interface.Visible)
      {
        interface.Visible = false;
      }
      else if (interface_inv != null && interface_inv.Visible)
      {
        interface_inv.Visible = false;
      }
      else if (Character.GetAtScreenXY(mouse.x, mouse.y) != player)
      {
        context_x = mouse.x;
        context_y = mouse.y;
        interface.X = Maths.Clamp(context_x - radius, 0, SCREEN_WIDTH - interface.Width);
        interface.Y = Maths.Clamp(context_y - radius, 0, SCREEN_HEIGHT - interface.Height);

        if (button_auto_disable)
        {
          for (int i; i < interface.ControlCount; i ++)
          {
            if (interface.Controls[i].AsButton != null)
            {
              interface.Controls[i].Enabled = IsInteractionAvailable(context_x, context_y, modemap[interface.Controls[i].ID]);
            }
          }
        }

        interface.Visible = true;
      }
    }
    // close windows or unset the active inventory item
    else if (interface.Visible)
    {
      interface.Visible = false;
    }
    else if (interface_inv != null && interface_inv.Visible)
    {
      interface_inv.Visible = false;
    }
    else if (player.ActiveInventory != null)
    {
      player.ActiveInventory = null;
    }
    else
    {
      // ...except when there is no nothing to deselect or close,
      // so just walk to this position
      Room.ProcessClick(mouse.x, mouse.y, eModeWalkto);
    }
  }
  else if (button == eMouseRight)
  {
    // close windows or unset the active inventory item
    if (interface.Visible)
    {
      interface.Visible = false;
    }
    else if (player.ActiveInventory != null)
    {
      player.ActiveInventory = null;
    }
    else if (interface_inv != null && interface_inv.Visible)
    {
      interface_inv.Visible = false;
    }
    else if (interface_inv != null)
    {
      // ...except when there is no nothing to deselect or close,
      // so a right click is also how the inventory is opened
      interface_inv.Visible = true;
    }
  }
  else if (button == eMouseLeftInv)
  {
    // InventoryItem.GetAtScreenXY could return null here
    // so using game.inv_activated instead is a safer option
    InventoryItem* item = inventory[game.inv_activated];

    if (player.ActiveInventory == null)
    {
      // left click to set active inventory
      player.ActiveInventory = item;
    }
    else if (item.ID != player.ActiveInventory.ID)
    {
      // left click to 'combine' items
      item.RunInteraction(eModeUseinv);
    }
    else if (interface_inv != null)
    {
      // clicking an item on itself closes the inventory window
      // (this is just a shortcut to avoid moving the cursor, as it means
      // you can just double click an item to also close the window)
      interface_inv.Visible = false;
    }
  }
  else if (button == eMouseRightInv)
  {
    // InventoryItem.GetAtScreenXY could return null here
    // so using game.inv_activated instead is a safer option
    InventoryItem* item = inventory[game.inv_activated];

    if (player.ActiveInventory == null && item != null)
    {
      // right click to look at item
      item.RunInteraction(eModeLookat);
    }
    else
    {
      // right click to deselect
      player.ActiveInventory = null;
    }
  }
}

function repeatedly_execute_always()
{
  if (redraw)
  {
    render();
    redraw = false;
  }
}

function repeatedly_execute()
{
  if (interface == null || !enabled)
  {
    // don't do anything if GUI isn't set or is disabled
  }
  else if (player.ActiveInventory == null)
  {
    if (interface.Visible)
    {
      // update text label for verb coin actions
      GUIControl* control = GUIControl.GetAtScreenXY(mouse.x, mouse.y);

      if (action_label == null)
      {
        // pass
      }
      else if (control != null && control.AsButton != null && control.Enabled && context_text != null)
      {
        action_label.Text = String.Format("%s %s", actionmap[control.ID], context_text);
      }
      else if (context_text != null)
      {
        action_label.Text = context_text;
      }
    }
    else if ((interface_inv != null && !interface_inv.Visible) || GetLocationType(mouse.x, mouse.y) == eLocationNothing)
    {
      // update regular text label
      context_text = Game.GetLocationName(mouse.x, mouse.y);

      if (action_label != null)
      {
        action_label.Text = context_text;
      }
    }
  }
  else
  {
    if (interface_inv != null && interface_inv.Visible && GUI.GetAtScreenXY(mouse.x, mouse.y) != interface_inv)
    {
      // close inventory window once the cursor leaves
      interface_inv.Visible = false;
    }

    // update text label for 'combining' items
    String location = Game.GetLocationName(mouse.x, mouse.y);
    InventoryItem *i = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);

    if ((i != null && i.ID == player.ActiveInventory.ID) || location == "")
    {
      location = "...";
    }

    if (action_label != null)
    {
      action_label.Text = String.Format("Use %s with %s", player.ActiveInventory.Name, location);
    }
  }
}

function on_event(EventType event, int data)
{
  if (event == eEventLeaveRoom && interface != null)
  {
    // hide interface when changing rooms
    interface.Visible = false;
  }
  else if (event == eEventGUIMouseDown &&
      interface_inv != null &&
      data == interface_inv.ID &&
      InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null)
  {
    // handle clicks in the inventory area that are not on an inventory item
    GUIControl* control = GUIControl.GetAtScreenXY(mouse.x, mouse.y);

    if (control == null || control.AsInvWindow == null)
    {
      // pass
    }
    else if (player.ActiveInventory != null)
    {
      player.ActiveInventory = null;
    }
    else
    {
      interface_inv.Visible = false;
    }
  }
}
[close]

What else do I need to change in the verb coin code to make my custom-made verb coin work?  (Once I know this part, I'll post the lines in the global script and ask what changes need to be there as well.)

Khris

This won't work. You still need a way to reference the positions.
(Also note that you can comment out multiple lines using /* and */ instead of putting // in each line)

Simply expand the enum like this:
Code: ags
enum VerbCoinPosition {
  eVerbCoinPositionNorth,
  eVerbCoinPositionNorthEast,
  eVerbCoinPositionSouthEast,
  eVerbCoinPositionSouth,
  eVerbCoinPositionSouthWest,
  eVerbCoinPositionNorthWest
};

You will now get errors where eVerbCoinPositionWest and eVerbCoinPositionEast are referenced, you can use these errors to find the lines you need to fix / add to.

DBoyWheeler

Okay.  For the directions, do I need to use the X and Y coordinates of the buttons to get them set up right?

Khris

The module calculates the four positions based on a given radius. You can skip that and manually place the buttons on your GUI, then remove the place_button(control, position); line from VerbCoin::RegisterButton.

DBoyWheeler

#4
I made the changes... when I get the chance, I'll test it out, and update this post if I encounter any problems.

[Update time] Okay, so I got out some fixes, but now I have this issue.

I get this weird verb coin (and one that don't work)



I want the verb coin to look like this:


If I need to make a serious change in the verb coin template, so be it.  I really want this verb coin to work.

Khris

In the verb coin template, the setup happens in the Global Script's game_start function.
Can you show what you have in there?

DBoyWheeler

Here's what I put in the game_start function.

Code: ags
function game_start()
{
  // setup VerbCoin GUI and buttons
  VerbCoin.InterfaceGui = gVerbcoin;
  //Will need to update verb buttons later.
  VerbCoin.RegisterButton(btnLook, eVerbCoinPositionNorthWest, eModeLookat, "Look at");
  VerbCoin.RegisterButton(btnUse, eVerbCoinPositionNorth, eModeInteract, "Use");
  VerbCoin.RegisterButton(btnTalk, eVerbCoinPositionNorthEast, eModeTalkto, "Talk to");
  VerbCoin.RegisterButton(btnDarkStar, eVerbCoinPositionSouthWest, eModeDarkStar, "Use Dark Star on");
  VerbCoin.RegisterButton(btnDDSpore, eVerbCoinPositionSouth, eModeDDSpore, "Use DandiiDooDad Spore on");
  VerbCoin.RegisterButton(btnSpFlcn, eVerbCoinPositionSouthEast, eModeSpFalcon, "Use Spirit Falcon on");
  // select the inventory GUI and action label
  VerbCoin.InventoryGui = gInventoryGUI;
  VerbCoin.ActionLabel = lblText;

  // disable buttons where click events would be unhandled
  VerbCoin.ButtonAutoDisable = true;
}

Khris

So have you changed the place_button function accordingly / removed the call from the RegisterButton function?

Plus it looks like the GUI is set to block the game? Can you check its visibility setting?

DBoyWheeler

Quote from: Khris on Thu 05/10/2023 07:45:11So have you changed the place_button function accordingly / removed the call from the RegisterButton function?

Plus it looks like the GUI is set to block the game? Can you check its visibility setting?

Yes, I removed the place_button call from the RegisterButton function, and its visibility is set to "False" when not in use.

Khris

At this point it's probably easiest if you upload your game source somewhere and PM me the link so I can take a look.

DBoyWheeler

Okay, I'll put it in Google Drive, and send the link in a PM.

Khris

#11
Alright, fixed the issues.

1. The main mouse cursor didn't have its hotspot at the center of the sprite
2. I changed the VerbCoin's main script according to your pre-made GUI requirements
3. you have VerbCoin.ButtonAutoDisable = true; in your setup in game_start, this disables buttons that don't have interactions; the plane's hotspots don't have any interactions set up, so the visible buttons were disabled
4. the GUI was cut off because it was still using the default radius and drawing a circle instead of using the background image and its dimensions; I fixed this in the code
5. the gVerbcoin buttons were missing their On_Click event handler, I had to put VerbCoinButton_OnClick in each button's event field so the click is forwarded to the module
6. I also added an unhandled_event function to the start of the module to handle the three custom cursor modes and put example code in there that distinguishes between mode and location type.

I'm going to send a PM with the fixed source.

DBoyWheeler

#12
Thank you.  I look forward to seeing the fixes.  This verb coin issue was kind of a choke point in the making of this game.  Hopefully once I get the fixes, I can really start getting more stuff worked on with this.

[Update] Okay, rather interesting question here.
See, I have some food items in game inventory.  And similar to Curse of Monkey Island, I want to make it so the "Talk" button in the Verb Coin GUI could change to "Eat" [Item name here.]  Is there a way to change the action text or whatever it is called for certain items or objects?

Khris

Yes, the text is set in the VerbCoin script's repeatedly_execute. You could add a custom property, a bool "isFood" with a default value of false, the set it to true for each edible item. The rep_exe will read this property and set the text accordingly.

I checked your game and override inv click handling was still set to false. I changed that but left-clicking an item only makes it active, as opposed to opening the VerbCoin. So you'd have to also implement that somehow.

DBoyWheeler

Quote from: Khris on Sun 22/10/2023 09:16:06Yes, the text is set in the VerbCoin script's repeatedly_execute. You could add a custom property, a bool "isFood" with a default value of false, the set it to true for each edible item. The rep_exe will read this property and set the text accordingly.

I checked your game and override inv click handling was still set to false. I changed that but left-clicking an item only makes it active, as opposed to opening the VerbCoin. So you'd have to also implement that somehow.

Ah, so that's how it works.  I might have to experiment with variables to change stuff around.

DBoyWheeler

Okay, I've been trying to get some more done with the verb coin (namely, to make the hand button display different things, be it a door to open, an item to pick up, or something to inspect).  I need to specify which button, otherwise it might read something weird when I want to use the Look Button or Talk Button.

But I've been getting error messages when I try.

Here's the section of code (in the Repeated_Execute of the Verbcoin script).

Code: ags
 else if (control != null && control.AsButton != null && control.Enabled && context_text != null)
      {
        if(button == btnUse)
        {if(ThingToPickUp){action_label.Text = String.Format("Pick up %s", context_text);}
        else if (DoorToOpen){action_label.Text = String.Format("Open %s", context_text);}
        else if (PlaceToInspect){action_label.Text = String.Format("Check %s", context_text);}}
        else action_label.Text = String.Format("%s %s", actionmap[control.ID], context_text);
      }
      else if (context_text != null)
      {
        action_label.Text = context_text;
      }

But I keep getting this Error Message:
Quoteundefined symbol "button"

How do I set the code so that there can be special cases for a particular button, depending on what hotspot or object there is?

morganw

'control' is a pointer to the button.

You should probably also include the fix for checking which GUI owns the button:
https://www.adventuregamestudio.co.uk/forums/index.php?msg=636657503

Khris

This was my bad, I sent a PM with "if (button == btnUse)" in it.

It was supposed to be a generic method of solving the "how to address a specific button" issue, not a line to be literally added to the script.

Anyway, like morgan says, you can most likely fix this by simply replacing "button" with "control".

DBoyWheeler

Okay, I did the change from "button" to "control", but now some weird crap is happening.

The code is similar (tried to get creative with the booleans).

Here is the code I did.

In the Mouse Click section
Code: ags
        if(GetLocationType(context_x, context_y) == eLocationObject)
        {
          Hotspot* h = Hotspot.GetAtScreenXY(context_x, context_y);
          Object* o = Object.GetAtScreenXY(context_x, context_y);
          if (o.GetProperty("CanObjectBePickedUp") == 1){ThingToPickUp = true;} else {ThingToPickUp = false;}
          if (o.GetProperty("ADoorToOpen") == 1){DoorToOpen = true;} else {DoorToOpen = false;}
          if (h.GetProperty("PlaceToInspect") == 1){PlaceToInspect = true;} else {PlaceToInspect = false;}
        }

And in the repeatedly execute:
Code: ags
        if(control == btnUse)
        {if(ThingToPickUp == true){action_label.Text = String.Format("Pick up %s", context_text);}
        else if (DoorToOpen == true){action_label.Text = String.Format("Open %s", context_text);}
        else if (PlaceToInspect == true){action_label.Text = String.Format("Check %s", context_text);}}
        else action_label.Text = String.Format("%s %s", actionmap[control.ID], context_text);

The Look and Talk buttons work okay.



But the Do/Interact button just shows the spot and doesn't show any action at all.


What am I missing in the code?

morganw

I would guess that your boolean flags are not being set correctly. The code which you've shown doesn't look it would work:
Code: ags
        if(GetLocationType(context_x, context_y) == eLocationObject)
        {
          Hotspot* h = Hotspot.GetAtScreenXY(context_x, context_y);
If no flags are set unless the context position is over an object, how can it work where there is no object?

DBoyWheeler

Okay, I made the changes for the hotspot flag, but even then, no action verb is appearing before the target hotspot or object.

Khris

Did you fix the cursor hotspots? You could also consider using a sprite that isn't a massive X and completely obscuring the thing you want to click?

Also check your code and make sure that it always puts new text on the label, regardless of which path the execution takes.

DBoyWheeler

I shrank down the pointer (hopefully it won't be TOO small).

Um, would the code that I need to check be in the main (global) script, or somewhere in the verbcoin script?  I'm a little lost here.

Khris

Was referring to the code that changes the action line, the one you added.

DBoyWheeler

I'm assuming it's this code in the verb coin script
Code: ags
function repeatedly_execute()
{
  if (interface == null || !enabled)
  {
    // don't do anything if GUI isn't set or is disabled
  }
  else if (player.ActiveInventory == null)
  {
    if (interface.Visible)
    {
      // update text label for verb coin actions
      GUIControl* control = GUIControl.GetAtScreenXY(mouse.x, mouse.y);

      if (action_label == null)
      {
        // pass
      }
      else if (control != null && control.AsButton != null && control.Enabled && context_text != null)
      {
        if(control == btnUse)
        {if(ThingToPickUp == true){action_label.Text = String.Format("Pick up %s", context_text);}
        else if (DoorToOpen == true){action_label.Text = String.Format("Open %s", context_text);}
        else if (PlaceToInspect == true){action_label.Text = String.Format("Check %s", context_text);}}
        else action_label.Text = String.Format("%s %s", actionmap[control.ID], context_text);
      }
      else if (context_text != null)
      {
        action_label.Text = context_text;
      }
    }
    else if ((interface_inv != null && !interface_inv.Visible) || GetLocationType(mouse.x, mouse.y) == eLocationNothing)
    {
      // update regular text label
      context_text = Game.GetLocationName(mouse.x, mouse.y);

      if (action_label != null)
      {
        action_label.Text = context_text;
      }
    }
  }
  else
  {
    if (interface_inv != null && interface_inv.Visible && GUI.GetAtScreenXY(mouse.x, mouse.y) != interface_inv)
    {
      // close inventory window once the cursor leaves
      interface_inv.Visible = false;
    }

    // update text label for 'combining' items
    String location = Game.GetLocationName(mouse.x, mouse.y);
    InventoryItem *i = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);

    if ((i != null && i.ID == player.ActiveInventory.ID) || location == "")
    {
      location = "...";
    }

    if (action_label != null)
    {
      action_label.Text = String.Format("Use %s with %s", player.ActiveInventory.Name, location);
    }
  }
}

Is there something that might be out of order that is messing things up?

Khris

#25
The problem seems to be this part:

Code: ags
        if (control == btnUse) {
          if (ThingToPickUp == true) {
            action_label.Text = String.Format("Pick up %s", context_text);
          } else if (DoorToOpen == true) {
            action_label.Text = String.Format("Open %s", context_text);
          } else if (PlaceToInspect == true) {
            action_label.Text = String.Format("Check %s", context_text);
          }
        } else action_label.Text = String.Format("%s %s", actionmap[control.ID], context_text);

Using proper indentation you can now see that if the execution enters the control == btnUse block but then neither of the three variables are true, the code simply does nothing.
You need to change the code so that some label text is always assigned. The easiest way to do this is to simply execute the default line first, then let the special handling overwrite the label:

Code: ags
        action_label.Text = String.Format("%s %s", actionmap[control.ID], context_text);
        if (control == btnUse) {
          if (ThingToPickUp == true) {
            action_label.Text = String.Format("Pick up %s", context_text);
          } else if (DoorToOpen == true) {
            action_label.Text = String.Format("Open %s", context_text);
          } else if (PlaceToInspect == true) {
            action_label.Text = String.Format("Check %s", context_text);
          }
        }

Also note that this can be refactored into:

Code: ags
        String action = actionmap[control.ID]; // default verb
        if (control == btnUse) {
          if (ThingToPickUp) action = "Pick up";
          else if (DoorToOpen) action = "Open";
          else if (PlaceToInspect) action = "Check";
        }
        action_label.Text = String.Format("%s %s", action, context_text);

DBoyWheeler

Okay, something is REALLY screwed up.

The verbs are working again, but when I got to the opened door (a HotSpot), the interact command is still "Use Opened Door" (instead of "Check Opened Door").  When the Dark Star appears after getting the inventory bag, when I click on the revealed Dark Star, it ends up saying "Check Dark Star" (instead of "Pick up Dark Star", which is what it is supposed to read; again the "Check" verb is for certain hotspots, not objects).  Do I need to change the Booleans into some other variables to make them work properly?

Khris

You also need to reset your variables to false.

At the point where you do
Code: ags
  if (some_condition) ThingToPickUp = true;

do this instead:
Code: ags
  ThingToPickUp = some_condition;

Otherwise ThingToPickUp will remain true and unexpected results will occur.

DBoyWheeler

Would I put that resetting the values in this section of the repeatedly_execute code?

Code: ags
if (interface == null || !enabled)
  {
    // don't do anything if GUI isn't set or is disabled
  }

Khris

I don't think that's going to work.

But like I said, just change the code you yourself added to the script, the part where you set the three flags to true.
If you simply also set them to false if the condition isn't true, that should do it.
The code should be in the module's on_mouse_click function, in the block that ends with
Code: ags
        interface.Visible = true;

DBoyWheeler

It's gone back to "Use" [object] (regardless of what the spot or object is).

Khris

I'm going to go out on a limb and say it's your code that's causing this.
Could you post the relevant lines...?

DBoyWheeler

Yeah, I don't know what the heck I'm doing wrong with the code.

Here's the mouse click one (well, the portion of the mouse click that's important here):
Code: ags
function on_mouse_click(MouseButton button)
{
  if (interface == null || !enabled)
  {
    // don't do anything if GUI isn't set or is disabled
  }
  else if (button == eMouseLeft)
  {
    if (GetLocationType(mouse.x, mouse.y) != eLocationNothing)
    {
      if (player.ActiveInventory != null)
      {
        Room.ProcessClick(mouse.x, mouse.y, eModeUseinv);
      }
      else if (interface.Visible)
      {
        interface.Visible = false;
      }
      else if (interface_inv != null && interface_inv.Visible)
      {
        interface_inv.Visible = false;
      }
      else if (Character.GetAtScreenXY(mouse.x, mouse.y) != player)
      {
        if(GetLocationType(context_x, context_y) == eLocationObject)
        {
          Object* o = Object.GetAtScreenXY(context_x, context_y);
          ThingToPickUp = o.GetProperty("CanObjectBePickedUp");
          DoorToOpen = o.GetProperty("ADoorToOpen");
        }
        if(GetLocationType(context_x, context_y) == eLocationHotspot)
        {
          Hotspot* h = Hotspot.GetAtScreenXY(context_x, context_y);
          PlaceToInspect = h.GetProperty("PlaceToInspect");
        }
        context_x = mouse.x;
        context_y = mouse.y;
        interface.X = Maths.Clamp(context_x - interface.Width / 2, 0, SCREEN_WIDTH - interface.Width);
        interface.Y = Maths.Clamp(context_y - interface.Height / 2, 0, SCREEN_HEIGHT - interface.Height);

        if (button_auto_disable)
        {
          for (int i; i < interface.ControlCount; i ++)
          {
            if (interface.Controls[i].AsButton != null)
            {
              interface.Controls[i].Enabled = IsInteractionAvailable(context_x, context_y, modemap[interface.Controls[i].ID]);
            }
          }
        }

        interface.Visible = true;
        ThingToPickUp = false;
        DoorToOpen = false;
        PlaceToInspect = false;
      }
    }
    // close windows or unset the active inventory item
    else if (interface.Visible)
    {
      interface.Visible = false;
    }
    else if (interface_inv != null && interface_inv.Visible)
    {
      interface_inv.Visible = false;
    }
    else if (player.ActiveInventory != null)
    {
      player.ActiveInventory = null;
    }
    else
    {
      // ...except when there is no nothing to deselect or close,
      // so just walk to this position
      Room.ProcessClick(mouse.x, mouse.y, eModeWalkto);
    }
  }

And here's the repeatedly execute code (again, the portion that's important here)
Code: ags
if (interface.Visible)
    {
      // update text label for verb coin actions
      GUIControl* control = GUIControl.GetAtScreenXY(mouse.x, mouse.y);

      if (action_label == null)
      {
        // pass
      }
      else if (control != null && control.AsButton != null && control.Enabled && context_text != null)
      {
        String action = actionmap[control.ID];
        if (control == btnUse)
        {
          if (ThingToPickUp) action = "Pick up";
          else if (DoorToOpen) action = "Open";
          else if (PlaceToInspect) action = "Check";
        }
        action_label.Text = String.Format("%s %s", action, context_text);
      }
      else if (context_text != null)
      {
        action_label.Text = context_text;
      }
    }
    else if ((interface_inv != null && !interface_inv.Visible) || GetLocationType(mouse.x, mouse.y) == eLocationNothing)
    {
      // update regular text label
      context_text = Game.GetLocationName(mouse.x, mouse.y);

      if (action_label != null)
      {
        action_label.Text = context_text;
      }
    }
  }

What am I screwing up?

Khris

#33
The code that sets your flags based on the properties uses old coordinates.
You need to do
Code: ags
        context_x = mouse.x;
        context_y = mouse.y;

first. Move these two lines up, above the two blocks that check the properties.

Also, resetting the flags needs to happen right before they are potentially set.
Move up the three lines below interface.Visible = true;, also above the mentioned two blocks.

Referring to the first snippet, cut lines 36, 37, 53, 54 and 55 and paste them between lines 24 and 25.

DBoyWheeler

#34
I think it's working now.  I'll test it on doors next time I do testing.  Thanks.  I'll let you know if I run into any more trouble.

[Update]
Now I have a new issue.

There's a part in my "intro tutorial" where I show the player how to use the "Spirit Falcon".
Code: ags
function cLara_AnyClick()
{if(mouse.Mode == eModeSpFalcon)
  {if((cLara.Room == 2)&&(LaraAwakened == false))
  {
    player.FaceCharacter(cLara, eBlock);
    player.Say("Spirit Falcon, this dear child needs help!");
    cLara.Animate(1, 5, eOnce, eBlock, eForwards);
    Wait(20);
    cLara.Animate(2, 5, eOnce, eBlock, eForwards);
    cLara.UnlockView();
    cLara.FaceDirection(eDirectionDown, eBlock);
    LaraAwakened = true;
    cLara.Name = "Lara Blaapeppe";
    cLara.Say("Where am I?");
    player.Say("I'm curious to that myself, but I got you out of that bag.");
    player.Say("My name is Sarimento.");
    cLara.Say("Thank you, Mr. Sarimento.  My name is Lara.  Lara Blaapeppe.");
    cLara.FaceDirection(eDirectionRight, eBlock);
    cLara.Say("My home town is not too far away.  Follow me.");
    Display("This is where we would transport to the Blaapeppe neighborhood.  For now, we'll end here.");
    QuitGame(0);
    }
  else
  {
    player.Say("She's already awoken from my Spirit Falcon's powers.");
  }}
}

But when I test it in game, nothing happens.  No error messages, no animations... nothing.  What could I be doing wrong?

Crimson Wizard

It's worth mentioning, referring to the conversation on Discord, that mouse.Mode turned out to be 0 in this function. This means that the problem is not in cLara_AnyClick, but in how mouse.Mode is set elsewhere.

DBoyWheeler

The new idea from CrimsonWizard (on Discord) helped.  Thanks.  I'll let you know if I run into any more problems.

SMF spam blocked by CleanTalk