I would like to make the activeInventory = null when the player clicks on an empty space in the inventory GUI and have the activeInventory switch with what inventory they click on.
I assume in this function, I would have to find if the player activeInventory != null, then check where the cursor is. If in an empty space, activeInventory = null. If the cursor is on an item, then activeInventory = item, and the item gets added to inventory. Something like this:
function gIconbar_onClick(GUI *theGui, MouseButton button){
if(player.ActiveInventory != null{
if(InventoryItem.GetAtScreenXY(mouse.x,mouse.y) = null {
inventory.AddActiveInventory
player.ActiveInventory = null;
} else {
player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
}
}
}
There's also this that is helpful, but I'm having a little of trouble interpreting it.
https://www.adventuregamestudio.co.uk/forums/advanced-technical-forum/putting-active-inventory-back-into-inventory-problems-solved/msg636473542/#msg636473542
Uhm, I think you can do this simply by using
function gInventoryBar_OnClick(GUI *theGui, MouseButton button)
{
player.ActiveInventory = null;
}
This is because, if something is on top of the gui that is clickable, it will run it's action instead of propagating the click to whatever is below.
I am going to comment the code you wrote, just to try to explain it - but I believe you should just use the code above.
// this is the OnClick event of the gIconbar GUI, it's on it's ⚡ event properties in the Editor
function gIconbar_onClick(GUI *theGui, MouseButton button){
// the player has some item selected, so in the next block, we know this
if(player.ActiveInventory != null{
// There is no inventory item under the mouse (we use == for equality check)
if(InventoryItem.GetAtScreenXY(mouse.x,mouse.y) == null {
// I don't know what it was the idea in this code, so I am commenting it out of actions
// inventory.AddActiveInventory
// we set so there is no active item anymore, what was on player hand is back at the bag
player.ActiveInventory = null;
} else {
// in case there was an inventory item below the mouse, we assign it as the active item for the player
player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
}
}
}
Hmm, this didnt work. I think its being called in the wrong function. I tried moving it, but still no results.
function btnIconCurInv_Click(GUIControl *control, MouseButton button)
{
//if (player.ActiveInventory != null)
//{
// mouse.Mode = eModeUseinv;
//}
if(cGoby.ActiveInventory != null){
if(InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null){
cGoby.ActiveInventory = null;
// switch to the interact cursor
mouse.Mode = eModeInteract;
// ...but override the appearance to look like the arrow
mouse.UseModeGraphic(eModePointer);
} else {
cGoby.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
mouse.Mode = eModeUseinv;
}
}
}
When you say drop inventory items in empty space, do you mean something like, an inventory where you can place items in any specific place?
Because previously I understood as just not having the item as active, meaning, the cursor returns to normal.
I mean, if you click on an empty space within the inventory GUI, and you have an activeInventory item, it goes back into your inventory and your cursor mode is now interact instead of useInventory. Additionally, if you click on another inventory item, your current activeInventory goes back in your inventory, and your activeInventory now becomes what you clicked on.
Detecting a click on an empty part of an InvWindow should work like this:
MouseButton button;
function on_event(EventType event, int data) {
if ((event == eEventGUIMouseDown || eEventGUIMouseUp) && data == gInventoryBar.ID) {
if (event == eEventGUIMouseDown) {
for (int i = eMouseLeft; i <= eMouseMiddle; i++) if (Mouse.IsButtonDown(i)) button = i;
}
if (event == eEventGUIMouseUp && button == eMouseLeft) {
int mx = mouse.x, my = mouse.y;
GUIControl *gc = GUIControl.GetAtScreenXY(mx, my);
if (gc == null) return;
InvWindow* iw = gc.AsInvWindow;
if (iw == null) return;
InventoryItem* ii = InventoryItem.GetAtScreenXY(mx, my);
if (ii == null) {
// player clicked on empty part of inv window
player.ActiveInventory = null;
}
}
}
}
Hmmm, it's still not working.
You can look at my code here: https://github.com/lishap/gobyworld/blob/main/GlobalScript.asc (https://github.com/lishap/gobyworld/blob/main/GlobalScript.asc)
I'm not seeing my code in there?
Take a look now :)
I took out your code and replaced it back with mine to try and problem solve. I think the issue is it's not receiving the click. Currently, when I click on the hand button, it does what I want it to do when it clicks on an empty space. So, I'm trying to figure out where that is, but I can't seem to locate it.
function btnInvSelect_Click(GUIControl *control, MouseButton button)
{
// switch to the interact cursor
mouse.Mode = eModeInteract;
// ...but override the appearance to look like the arrow
mouse.UseModeGraphic(eModePointer);
if (player.ActiveInventory != null){
mouse.Mode = eModeUseinv;
if(InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null){
player.ActiveInventory = null;
}
else {
player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
mouse.Mode = eModeUseinv;
}
}
}
function btnIconCurInv_Click(GUIControl *control, MouseButton button)
{
if (player.ActiveInventory != null){
mouse.Mode = eModeUseinv;
//if(InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null){
//player.ActiveInventory = null;
//}
//else {
//player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
//mouse.Mode = eModeUseinv;
//}
//}
}
I am trying to allow the player to drop the current active inventory item by clicking on an empty space within the Inventory bar and to swap the current active inventory item by clicking on an inventory item in the Inventory bar.
I've worked out the code to do this, but I believe it isn't being called in the correct location.I originally placed it in the gIconbar_onClick function but it didn't work. I think this should only work in the inventoryWindow, which is in the GUI template, but doesn't have an events properties panel.
//on click, if the mouse is not over an inventory item
if(InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null){
//drop the current inventory item
player.ActiveInventory = null;
}
else
//change the active inventory to item in which the mouse is over
player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
mouse.Mode = eModeUseinv;
}
}
I still think eri0o's first suggestion was basically correct. (I'm not sure I understand what Khris is doing, but it seems more complicated than necessary.) However, it could be affected by the project setting "Handle inventory clicks in script": if that is set to true, I think you might have to deal with it in on_mouse_click()?
I am also puzzled by your latest attempts. Going by the function names and other contents, they handle clicking on buttons on the inventory GUI for setting the cursor mode. Why would you put this code there? It needs to go in a function to handle clicking on the Inventory Window control.
Edit: Oh, I see, you couldn't find a way to add an event handler for that. It may not have an event to hook up. In that case, you do have to do it in on_mouse_click():
// called when a mouse button is clicked
function on_mouse_click(MouseButton button)
{
// called when a mouse button is clicked. button is either LEFT or RIGHT
if (IsGamePaused())
{
// game is paused, so do nothing (i.e. don't process mouse clicks)
}
else if(GUIControl.GetAtScreenXY(mouse.x, mouse.y) == invCustom) // Put the name of your Inventory Window here
{
if(InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null)
{
//drop the current inventory item
player.ActiveInventory = null;
}
else
{
//change the active inventory to item in which the mouse is over
player.ActiveInventory = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
mouse.Mode = eModeUseinv;
}
}
else if (button == eMouseLeft)
{
// 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)
{
// middle-click makes the character walk to clicked area, regardless of cursor mode
Room.ProcessClick(mouse.x, mouse.y, eModeWalkto);
}
}
Quote from: Snarky on Mon 13/03/2023 14:19:46Edit: Oh, I see, you couldn't find a way to add an event handler for that. It may not have an event to hook up. In that case, you do have to do it in on_mouse_click():
@Snarky, on_mouse_click is not called when you click on GUI. eMouseLeftInv/RightInv are only passed when you click on items themselves (in case "override inventory clicks in script" is true), but not on empty space in inventory window.
This is why there has to be these "hacks" with on_event, as in Khris's code.
Fair enough, but wouldn't it still be easier to use the OnClick event of the GUI itself?
function gInventoryBar_OnClick(GUI *theGui, MouseButton button)
{
if(GUIControl.GetAtScreenXY(mouse.x, mouse.y) == invCustom)
{
// Do stuff
}
}
No, dammit. I see that doesn't work either: the GUI doesn't get the event when you click on the Inventory Window. OK, so Khris was right. Seems to be the only way to trigger when clicking on the empty part of an inventory window.
(Incidentally, this part of AGS click handling is insane.)
Quote from: Snarky on Mon 13/03/2023 15:17:58Fair enough, but wouldn't it still be easier to use the OnClick event of the GUI itself?
GUI's On Click event is not triggered when you click on controls.
I don't know which "empty space" is OP referring to, but in case it's an empty space inside the InventoryWindow control, only on_event will work.
Quote from: Crimson Wizard on Mon 13/03/2023 15:08:53on_mouse_click is not called when you click on GUI. eMouseLeftInv/RightInv are only passed when you click on items themselves (in case "override inventory clicks in script" is true), but not on empty space in inventory window.
Are you sure? I always considered the inventory handling in AGS a bit confusing, but I got this in my on_mouse_click function and it works perfectly fine. If I click on an empty space the current active inventory becomes null:EDIT: Nevermind. This code does
not run, i.e. the clicks aren't registered. In my game right-clicking in general removes the current item, so it
seemed to work correctly.
// right click on inventory
else if (button == eMouseRightInv)
{
// put item away
if (player.ActiveInventory != null) { player.ActiveInventory = null; mouse.Mode = eModeInteract; }
// look at item
else inventory[game.inv_activated].RunInteraction(eModeLookat);
}
Quote from: Matti on Mon 13/03/2023 21:22:02Quote from: Crimson Wizard on Mon 13/03/2023 15:08:53on_mouse_click is not called when you click on GUI. eMouseLeftInv/RightInv are only passed when you click on items themselves (in case "override inventory clicks in script" is true), but not on empty space in inventory window.
Are you sure?
Frankly, I was not fully certain, so I had to test this right now. In my test game it is called when clicking on items, but not on empty space.
In our BASS template we have a "on_event" handler for right clicking over empty inv space, similar to what Khris suggested.
Given the above, I cannot explain how your code works, if you are definite that it works on empty spaces too. Can you double check that it actually works, and you don't have anything in on_event related to eEventGUIMouseDown? or perhaps in rep-exec?
EDIT: oh, I could swear we even had a ticket opened for this, and found it:
https://github.com/adventuregamestudio/ags/issues/472
Matti, are you sure that is the code that is making it happen? There could be an on_event somewhere, perhaps in a module. Because I'm testing it, and indeed it does not seem like on_mouse_click() is getting called except over actual inventory items.
Matti, your code should cause an error / cause unwanted behavior if you right-click on an empty part without an active inventory item. Probably an array out of bounds error since game.inv_activated should be -1(?).
The fact that you never got an error seems to support that your code doesn't run when an empty part of the inv window is clicked (which is how AGS has always behaved, afaik).
You're absolutely right, sorry for the confusion!
In my game right-clicking in general removes the current item, so it seemed to work correctly with the inventory too, but as you said, clicks on empty spaces in the inventory aren't actually registered.
I tried adding in the code accordant to the opened ticket. But, I need to turn override built-in inventory window click handling to True, and then write my own code for all of the other on_click events?
function on_event(EventType event, int data)
{
if (event == eEventEnterRoomBeforeFadein)
{
CursorMode mode = mouse.Mode;
if (mode == eModeWalkto) mouse.SelectNextMode();
mouse.DisableMode(eModeWalkto);
mouse.Mode = mode;
}
if (event == eEventGUIMouseDown &&
data == gIconbar.ID &&
GUIControl.GetAtScreenXY(mouse.x, mouse.y) == InventoryWindow1 &&
InventoryItem.GetAtScreenXY(mouse.x, mouse.y) == null &&
mouse.IsButtonDown(eMouseLeft)) {
cGoby.ActiveInventory = null;
}
}
Afaik overriding built-in inventory click handling is only necessary for handling eMouseLeftInv and eMouseRightInv inside on_mouse_click, but this is about detecting a click on an empty spot of the inv window, which requires on_event code instead.
So the code should work without overriding it.
Can you do some debugging? As in: add Display calls to see which parts run and which ones don't.
Like
if (event == eEventGUIMouseDown && data == gIconbar.ID) {
int mx = mouse.x, my = mouse.y;
bool leftButton = mouse.IsButtonDown(eMouseLeft);
Display("click on iconbar");
if (GUIControl.GetAtScreenXY(mx, my) == InventoryWindow1) {
Display("click on inv window");
if (InventoryItem.GetAtScreenXY(mx, my) == null) {
Display("click on empty spot");
if (leftButton) {
Display("left button was used");
cGoby.ActiveInventory = null;
}
}
}
}
Edit: I tested the above code and it works as it should. The only remaining issue is a cosmetic one: hovering over the top bar with an active inventory item will change the mouse cursor back to the pointer sprite. Which makes sense for the buttons on the right but not the "place item back into inventory" part.
Btw: I've noticed you've set GUI 7 as text window, but there is no GUI 7, therefore calling Display() causes a crash. Replace the 7 with a 0 in General settings -> Text display to use the default box.
Yes, thank you!!! Now to changing the mouse graphic back to the inventory item.
I;m going to try and override the pointer in repeatedly execute with one of the mouth functions.