Hello
I am trying to find a method to allow keyboard control of an inventory window.
I currently have it so pressing Tab opens the inventory window and sets mouse cursor to eModeInteract. In the repeatedly execute I have a small code to move the mouse cursor to a relative grid position on arrow press, and then the following code to click the button at that position when spacebar is pressed.
if(IsKeyPressed (eKeySpace) == true){
ProcessClick (mouse.x, mouse.y, eModeInteract);
}
This doesn't seem do anything. Does anyone know if ProcessClick be used in this manner, or is there something else wrong?
Thank you!
The manual entry for ProcessClick states:
QuoteNOTE: This function ignores all interfaces and acts as though the point is directly visible. In other words, if the co-ordinates you pass happen to lie on a button on an interface, what actually happens will be as if the user clicked behind the interface onto the actual screen.
The
interface it's referring to is a
graphical user interface (aka, a GU
I). The InvWindow (and indeed the InventoryItem itself) are displayed
on said GUI, so you can't use ProcessClick for this.
Instead, you'll need to handle it manually:
function on_key_press(eKeyCode keycode)
{
if (keycode == eKeySpace)
{
InventoryItem *iat = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
if (iat != null) iat.RunInteraction(eModeInteract);
// else { /* do whatever else for non-inventory items... */ }
}
}
Note that I used on_key_press instead of repeatedly_execute for this. Moving the cursor in rep_ex by using IsKeyPressed is fine, but you don't want to trigger a dozen interactions, so that's what on_key_press is for instead. GetLocationType will return a type of eLocationNothing for InventoryItems, so you have to use the GetAtScreenXY function directly, which will return null if the cursor (or whatever other coordinates you supply) is not over an InventoryItem.
If you want to handle pressing space while not over an InventoryItem, then just add and use an else clause to your if-statement there. ;)
Thanks very much for this, it's just what I needed and has sent me in the right direction for many other things! For reasons I can't quite pin down right now, RunInteraction(eModeInteract) doesn't actually select the item, but if I assign the item to cEgo that gets around it (fully expect I have chosen the wrong mouse mode!)
if (keycode == eKeySpace)
{
InventoryItem *iat = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
if (iat != null) cEgo.ActiveInventory = iat;
// else { /* do whatever else for non-inventory items... */ }
}
RunInteraction(eModeInteract) will simply trigger the inventory item's "interact with item" event. It has no connection to how the mouse works or what clicks do.
To make an inventory active, you have to do exactly what you did.
Thank you, makes sense now.
This is one of the cases where the engine doesn't prescribe to any type of default logic and leaves it up to you. There are conceivable cases where you might want to actually allow the player to interact with a particular inventory item, but for other items you might want that same interact cursor to simply set the active item. You had asked about processing a mouse-click, and if ProcessClick didn't simply ignore inventory items this is pretty much what it would do. For every cursor mode except eModeWalkto, all ProcessClick does is check what's under the mouse and then call the equivalent "RunInteraction"-esque method. The logic behind what occurs at that point is still up to you to define in the event handlers.
In this case it is simpler to just set the active inventory directly, assuming that you don't want any separate interaction modes to be processed by this key-press. If you did, you could use InventoryItem.IsInteractionAvailable to check for handled interactions, and fall back on setting the active inventory as the default behavior.