Use inventory item A with B and viceversa (SOLVED!!)

Started by PERXEO, Wed 05/04/2023 07:26:56

Previous topic - Next topic

PERXEO

What is the best way so that when using an inventory object A, with an inventory object B, the resulting action is the same as if we do it the other way around, that is, use the inventory object B with the inventory object A ? When there are a lot of objects in a game, what is the best way to implement this?

Khris

#1
I guess you're asking how to avoid a bunch of duplicate code? You can use a custom function:

Code: ags
function HookRope() {
  // combine items here
}

function iHook_Useinv() {
  if (player.ActiveInventory == iRope) HookRope();
  else ...
}

function iRope_Useinv() {
  if (player.ActiveInventory == iHook) HookRope();
  else ...
}

You could also intercept the click in on_mouse_click:
Code: ags
InventoryItem* one, two;

bool IsItems(InventoryItem* a, InventoryItem* b) { return a == one && b == two || a == two && b == one; }

bool Combine() {
  if (IsItems(iHook, iRope)) { // order doesn't matter here
    ...
    return true;
  }
  ...
  return false;
}

  // in on_mouse_click
  if (button == eMouseLeftInv) {
    if (mouse.Mode == eModeUseinv && player.ActiveInventory != null) {
      one = inventory[game.inv_activated];
      two = player.ActiveInventory;
      if (!Combine()) one.RunInteraction(eModeUseinv);
    }
  }

Edit: code fixed


PERXEO

I've tried to use this code but ... i Can't not understand it. Maybe it's a bit confused to me. I don't know exactly where must I insert every snippet of code, and I don't understand what means this part: 

Code: ags
  if (button == eMouseLeftInv) {
    if (mouse.Mode == eModeUseinv && player.ActiveInventory != null) {
      one = inventory[game.inv_activated];
      two = player.ActiveInventory;
      if (!Combine()) one.RunInteraction(eModeUseinv);
    }
  }

If (!Combine()) one.RunInteraction(eModeUseInv); ... it's not finished and I don't understand what exactly means 

Khris

#4
Lines 1-12 go into the Global script. Either at the top or above the on_mouse_click function (or anywhere in between, but outside any function).
Then you extend the Combine function by handling all the possible combinations that actually work. For each successful combination, make sure to "return true;" eventually.

Lines 15-21 go inside the on_mouse_click function. By default it has if blocks for eMouseLeft and eMouseRight. Just add the eMouseLeftInv code below (you can always check the indentation of my snippets, I always write my code with indentation that already matches the place where it's supposed to be pasted).

 The Combine line is complete, here's the longer version:

Code: ags
      if (Combine() == false) {
        one.RunInteraction(eModeUseinv);
      }

It means: if Combine() returns false because the player tried to combine two items that don't actually combine, fall back to default behavior (i.e. run the clicked item's eModeUseinv handler).

PERXEO

I've obtained this error:

Code: ags
Error (line 664): Variable 'bool' is already defined

in this line:

Code: ags
function bool Combine() {
  if (IsItems(iLicuadora, iNaranja)) { // el orden no importa aqui 
    return true;
  }
  else
  {
    return false;
  }
}

Khris

Right, remove "function":

Code: ags
bool Combine() {

However you need to add code in there, like

Code: ags
bool Combine() {
  if (IsItems(iLicuadora, iNaranja)) { // el orden no importa aqui 
    player.LoseInventory(iLicuadora);
    player.LoseInventory(iNaranja);
    player.AddInventory(iJugo);
    player.Say("blah");
    return true;
  }
  return false;
}

PERXEO

I understand all that you wrote me, but in this snippet
Code: ags
/ called when a mouse button is clicked
function on_mouse_click(MouseButton button)
{
  if (IsGamePaused())
  {
    // game is paused, so do nothing (i.e. don't process mouse clicks)
  }
  else if (button == eMouseLeft)
  {
    player.Say("USING LEFT BUTTON NORMALLY");
    // left-click, so try using the current mouse cursor mode at this position
    Room.ProcessClick(mouse.x, mouse.y, mouse.Mode);
  }
  else if (button == eMouseRight)
  {
    // right-click, so cycle the mouse cursor mode
    Mouse.SelectNextMode();
  }
  else if (button == eMouseLeftInv)
  {
    player.Say("USING LEFT BUTTON ON INVENTORY");
     if (mouse.Mode == eModeUseinv && player.ActiveInventory != null) {
      objetoUno = inventory[game.inv_activated];
      objetoDos = player.ActiveInventory;
      if (Combine() == false) 
      {
        player.Say("COMBINE == FALSE");
        objetoUno.RunInteraction(eModeUseinv);
      }else
      {
        player.Say("ELSE");
       }
    } 
  }
}

 I can't get the code to go through the else if (button == eMouseLeftInv) check regardless of whether the inventory is open or not. It always goes through the above check: else if (button == eMouseLeft) and I don't know what I'm doing wrong...

Khris

You probably need to turn on custom inventory click handling in General Settings

PERXEO

I understand that you mean this, right?

Even though I'm setting it to true, it still doesn't work for me....

Khris

Yes, setting this to true means that AGS should call on_mouse_click passing eMouseLeftInv as button if you left click on an inventory item.
If that doesn't work, there's a bunch of possible reasons.

1. the inv GUI is covered by something else (which is transparent though)
2. the inv GUI isn't set to clickable
3. the inv window's itemwidth/itemheight is too small and you're clicking outside the item

PERXEO


If I have this parameter



set to true, what is the cursor mode that should be used to be able to interact with the inventory objects?
If my inventory butom for select inventory objects is gInvSelect, this is the correct code?

Code: ags
function gInvSelect_OnClick(GUIControl *control, MouseButton button)
{
  mouse.Mode = eModeInteract;
  //mouse.Mode = eModePickup;
}

Khris

This setting does not concern buttons, it's for handling the clicks you make on inventory items inside an InvWindow.
My code deals with the player combining an item with another item, which is why I check for the mouse mode being eModeUseinv.

I don't know what your button does. Also, why does it start with a "g" like a GUI? You should use "btn" instead.

PERXEO

Thanks for your answer. What I have in the scene is an inventory that appears in the middle of the scene.


This inventory has a button mistakenly called gInvSelect (the one I marked with a green arrow) that when pressed, calls the function that I put below.
Code: ags
function gInvSelect_OnClick(GUIControl *control, MouseButton button)
{
  //mouse.Mode = eModeInteract;
  //mouse.Mode = eModePickup;
  mouse.Mode= eModeUseinv;
}
It is at that moment when the cursor should be put in interact mode to be able to choose an object of inventory and being able to use it with another inventory object for example to be able to apply your snippet of combined use of two objects, in both directions.

From what you tell me then, by activating the option "Override built-in inventory window click handling" my button should no longer be necessary, but I would like that when I press my button, I could already connect it with the code you gave me before for the combined use of objects in both directions.
And this is where I am lost...

PERXEO

Sorry to be insistent and boring with this topic... but I'm pretty stuck and I can't move on.
I have an inventory that appears to be fine. If I set the parameter "Override built-in inventory window click handling" to false, but only for inventory objects to which I have assigned a function that is:
Code: ags
function useGeneric()
{
  InventoryItem * currentThing = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
  String nameCurrentThing=CurrentThing.Name;
  String whatThing=player.ActiveInventory.Name;
  player.Say("I'll use %s with %s.", whatThing, currentThingname);
}

 Conversely, if I set the parameter "Override built-in inventory window click handling" to true, to apply your methods, this doesn't work well.
When I open the inventory window whit this function
Code: ags
function btnInvSelect_OnClick(GUIControl *control, MouseButton button)
{
  player.Say("PULSO BOTON INVSELECT DEL INVENTARIO");
  mouse.Mode = eModeInteract;
  //mouse.Mode = eModePickup;
  //mouse.Mode= eModeUseinv;
}

the only one mode I can use is eModeInteract. The others dont's work!!.

If I try to use your method

Code: ags
function on_mouse_click(MouseButton button)
{

  if (IsGamePaused())
  {
    // game is paused, so do nothing (i.e. don't process mouse clicks)
  }
  else if (button == eMouseLeftInv)
  {
    player.Say("USING LEFT BUTTON ON INVENTORY on %d ", game.inv_activated);
     if (mouse.Mode == eModeUseinv && player.ActiveInventory != null) {
      objetoUno = inventory[game.inv_activated];
      objetoDos = player.ActiveInventory;
      if (Combine() == false) 
      {
        player.Say("COMBINE == FALSE");
        objetoUno.RunInteraction(eModeUseinv);
      }else
      {
        player.Say("ELSE");
       }
    } 
  }
}

I can't never enter in if (mouse.Mode == eModeUseinv && player.ActiveInventory != null) because the mouse.Mode is not eModeUseinv...and I don't know how to set it!!!

Thanks for your help!!! and sorry for my insistence!!
Could I be missing some code or some event in the inventory objects?
Am I missing some way to use the buttons?
Will it have to do with the standard mode of the cursors?

Khris

Sorry, I should've thought of that way earlier. My code only works when you turn on custom inv click handling, but that means you now have to handle an interact click manually, too:

Code: ags
  if (button == eMouseLeftInv) {
    one = inventory[game.inv_activated];
    if (player.ActiveInventory == null) {
      // interacting with an item makes it active, this should also set the mouse mode to eModeUseinv
      if (mouse.Mode == eModeInteract) player.ActiveInventory = one;
      else one.RunInteraction(mouse.Mode); // other modes
    }
    else if (mouse.Mode == eModeUseinv) {
      two = player.ActiveInventory;
      if (!Combine()) one.RunInteraction(eModeUseinv);
    }
  }

If you want the player to be able to interact with an inventory item (like turning on a flashlight for instance), you need to use a different cursor mode to make the item active, like eModePointer


PERXEO

Hi Khris!! Thanks a million for your patience! Now it works and it's fantastic, but I still have some residual doubts that still have me a little absorbed.
1) Why can't I click the right mouse button when I've the cursor over the inventory GUI area, in order to change the cursor mode with the function

Code: ags
....
 else if (button == eMouseRight)
  {
    // right-click, so cycle the mouse cursor mode
    Mouse.SelectNextMode();
   
  }
....

2) Why when I try to open the inventory from the button of a status bar GUI, with the function  ....
Code: ags
function btnInvOut_OnClick(GUIControl *control, MouseButton button)
{
 // player.Say("OPEN THE INVENTORY");
 
 gInv.X=(Screen.Width-gInv.Width)/2;
 gInv.Y=(Screen.Height-gInv.Height)/2;
 //Mouse.Mode = eModeInteract;
 Mouse.EnableMode(eModeUseinv);
 Mouse.Mode = eModeUseinv;
 gInv.Visible=true;
 
}


....the mode of the cursor to which I am indicating is not changed?

3) Why can't I change the cursor mode to eModeUseInv using the inventory gui button called "btnChangeMode" that I have for it, with this function?

Code: ags
function btnChangeMode_OnClick(GUIControl *control, MouseButton button)
{
  player.Say("CLICK TO CHANGE MODE");
  player.ActiveInventory=null;
  mouse.Mode=eModeUseinv;
  mouse.EnableMode(eModeUseinv);
  
}


Khris

#18
The first problem is easily solved, just use
Code: ags
  else if (button == eMouseRight || button == eMouseRightInv)

As for the other two, eModeUseinv requires an active inventory item. If player.ActiveInventory is null, AGS simply ignores your setting the mode to that.
However it's pointless to switch to that mode as soon as the player opens the inventory anyway. eModeUseinv is not the mode you use to pick an item, it's the mode used when an already active item is used with something else.
My code expects the game to use eModeInteract to pick an item from the inventory, so that's the mode you should switch to when the player opens it.

Crimson Wizard

Also, not sure if relevant, but

Quote from: PERXEO on Sun 16/04/2023 20:37:21
Code: ags
function btnChangeMode_OnClick(GUIControl *control, MouseButton button)
{
  player.Say("CLICK TO CHANGE MODE");
  player.ActiveInventory=null;
  mouse.Mode=eModeUseinv;
  mouse.EnableMode(eModeUseinv);
  
}

Here you are setting mouse.Mode=eModeUseinv before enabling it, which makes no sense.

SMF spam blocked by CleanTalk