diff --git a/builtin/game/item.lua b/builtin/game/item.lua index 44ec35cc9..6c2214ef6 100644 --- a/builtin/game/item.lua +++ b/builtin/game/item.lua @@ -347,6 +347,10 @@ function core.item_place(itemstack, placer, pointed_thing, param2) return itemstack end +function core.item_secondary_use(itemstack, placer) + return itemstack +end + function core.item_drop(itemstack, dropper, pos) if dropper and dropper:is_player() then local v = dropper:get_look_dir() @@ -605,6 +609,7 @@ core.craftitemdef_default = { -- Interaction callbacks on_place = redef_wrapper(core, 'item_place'), -- core.item_place on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop + on_secondary_use = redef_wrapper(core, 'item_secondary_use'), on_use = nil, } @@ -622,6 +627,7 @@ core.tooldef_default = { -- Interaction callbacks on_place = redef_wrapper(core, 'item_place'), -- core.item_place + on_secondary_use = redef_wrapper(core, 'item_secondary_use'), on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop on_use = nil, } @@ -640,6 +646,7 @@ core.noneitemdef_default = { -- This is used for the hand and unknown items -- Interaction callbacks on_place = redef_wrapper(core, 'item_place'), + on_secondary_use = redef_wrapper(core, 'item_secondary_use'), on_drop = nil, on_use = nil, } diff --git a/builtin/game/register.lua b/builtin/game/register.lua index 00bb23278..992fdf744 100644 --- a/builtin/game/register.lua +++ b/builtin/game/register.lua @@ -272,6 +272,7 @@ core.register_item(":unknown", { description = "Unknown Item", inventory_image = "unknown_item.png", on_place = core.item_place, + on_secondary_use = core.item_secondary_use, on_drop = core.item_drop, groups = {not_in_creative_inventory=1}, diggable = true, diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 9ffb497d7..11f90ba03 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -3303,6 +3303,11 @@ Definition tables --[[ ^ Shall place item and return the leftover itemstack ^ default: minetest.item_place ]] + on_secondary_use = func(itemstack, user, pointed_thing), + --[[ + ^ Same as on_place but called when pointing at nothing. + ^ pointed_thing : always { type = "nothing" } + ]] on_drop = func(itemstack, dropper, pos), --[[ ^ Shall drop item and return the leftover itemstack diff --git a/src/client.cpp b/src/client.cpp index 5c04632d1..8e49ee3ba 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -946,6 +946,7 @@ void Client::interact(u8 action, const PointedThing& pointed) 2: digging completed 3: place block or item (to abovesurface) 4: use item + 5: perform secondary action of item */ NetworkPacket pkt(TOSERVER_INTERACT, 1 + 2 + 0); diff --git a/src/game.cpp b/src/game.cpp index e6a1a2256..5e4f4cacf 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1525,6 +1525,7 @@ protected: void processPlayerInteraction(std::vector &highlight_boxes, GameRunData *runData, f32 dtime, bool show_hud, bool show_debug); + void handlePointingAtNothing(GameRunData *runData, const ItemStack &playerItem); void handlePointingAtNode(GameRunData *runData, const PointedThing &pointed, const ItemDefinition &playeritem_def, const ToolCapabilities &playeritem_toolcap, f32 dtime); @@ -3603,6 +3604,8 @@ void Game::processPlayerInteraction(std::vector &highlight_boxes, } else if (input->getLeftState()) { // When button is held down in air, show continuous animation runData->left_punch = true; + } else if (input->getRightClicked()) { + handlePointingAtNothing(runData, playeritem); } runData->pointed_old = pointed; @@ -3618,6 +3621,15 @@ void Game::processPlayerInteraction(std::vector &highlight_boxes, } +void Game::handlePointingAtNothing(GameRunData *runData, const ItemStack &playerItem) +{ + infostream << "Right Clicked in Air" << std::endl; + PointedThing fauxPointed; + fauxPointed.type = POINTEDTHING_NOTHING; + client->interact(5, fauxPointed); +} + + void Game::handlePointingAtNode(GameRunData *runData, const PointedThing &pointed, const ItemDefinition &playeritem_def, const ToolCapabilities &playeritem_toolcap, f32 dtime) diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index a4fa502ae..a5aaf1ecb 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1653,6 +1653,23 @@ void Server::handleCommand_Interact(NetworkPacket* pkt) } } // action == 4 + + /* + 5: rightclick air + */ + else if (action == 5) { + ItemStack item = playersao->getWieldedItem(); + + actionstream << player->getName() << " activates " + << item.name << std::endl; + + if (m_script->item_OnSecondaryUse( + item, playersao)) { + if( playersao->setWieldedItem(item)) { + SendInventory(playersao); + } + } + } /* diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp index d9a545b4f..3c84fb8cf 100644 --- a/src/script/cpp_api/s_item.cpp +++ b/src/script/cpp_api/s_item.cpp @@ -110,6 +110,32 @@ bool ScriptApiItem::item_OnUse(ItemStack &item, return true; } +bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, ServerActiveObject *user) +{ + SCRIPTAPI_PRECHECKHEADER + + int error_handler = PUSH_ERROR_HANDLER(L); + + if (!getItemCallback(item.name.c_str(), "on_secondary_use")) + return false; + + LuaItemStack::create(L, item); + objectrefGetOrCreate(L, user); + PointedThing pointed; + pointed.type = POINTEDTHING_NOTHING; + pushPointedThing(pointed); + PCALL_RES(lua_pcall(L, 3, 1, error_handler)); + if (!lua_isnil(L, -1)) { + try { + item = read_item(L, -1, getServer()); + } catch (LuaError &e) { + throw LuaError(std::string(e.what()) + ". item=" + item.name); + } + } + lua_pop(L, 2); // Pop item and error handler + return true; +} + bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user, const InventoryList *old_craft_grid, const InventoryLocation &craft_inv) { diff --git a/src/script/cpp_api/s_item.h b/src/script/cpp_api/s_item.h index 88cc1909d..7350a71c5 100644 --- a/src/script/cpp_api/s_item.h +++ b/src/script/cpp_api/s_item.h @@ -42,6 +42,8 @@ public: ServerActiveObject *placer, const PointedThing &pointed); bool item_OnUse(ItemStack &item, ServerActiveObject *user, const PointedThing &pointed); + bool item_OnSecondaryUse(ItemStack &item, + ServerActiveObject *user); bool item_OnCraft(ItemStack &item, ServerActiveObject *user, const InventoryList *old_craft_grid, const InventoryLocation &craft_inv); bool item_CraftPredict(ItemStack &item, ServerActiveObject *user,