From c6b06f04d82e7735f7762a630aa4ba1c109ca0ff Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 5 Mar 2024 22:21:24 +0300 Subject: [PATCH] items: on_use event --- src/items/ItemDef.h | 3 +- src/logic/PlayerController.cpp | 132 +++++++++++++++++------------- src/logic/scripting/scripting.cpp | 12 +++ src/logic/scripting/scripting.h | 53 ++++++++---- 4 files changed, 125 insertions(+), 75 deletions(-) diff --git a/src/items/ItemDef.h b/src/items/ItemDef.h index 9603bce0..64b7690f 100644 --- a/src/items/ItemDef.h +++ b/src/items/ItemDef.h @@ -7,7 +7,8 @@ #include "../typedefs.h" struct item_funcs_set { - bool init: 1; + bool init: 1; + bool on_use: 1; bool on_use_on_block: 1; bool on_block_break_by: 1; }; diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 5ff48153..b44378d4 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -205,14 +205,52 @@ void PlayerController::updateControls(float delta){ player->updateInput(level, input, delta); } +static int determine_rotation(Block* def, glm::ivec3& norm, glm::vec3& camDir) { + if (def && def->rotatable){ + const std::string& name = def->rotations.name; + if (name == "pipe") { + if (norm.x < 0.0f) return BLOCK_DIR_WEST; + else if (norm.x > 0.0f) return BLOCK_DIR_EAST; + else if (norm.y > 0.0f) return BLOCK_DIR_UP; + else if (norm.y < 0.0f) return BLOCK_DIR_DOWN; + else if (norm.z > 0.0f) return BLOCK_DIR_NORTH; + else if (norm.z < 0.0f) return BLOCK_DIR_SOUTH; + } + else if (name == "pane") { + if (abs(camDir.x) > abs(camDir.z)){ + if (camDir.x > 0.0f) return BLOCK_DIR_EAST; + if (camDir.x < 0.0f) return BLOCK_DIR_WEST; + } + if (abs(camDir.x) < abs(camDir.z)){ + if (camDir.z > 0.0f) return BLOCK_DIR_SOUTH; + if (camDir.z < 0.0f) return BLOCK_DIR_NORTH; + } + } + } + return 0; +} + +static void pick_block(ContentIndices* indices, Chunks* chunks, Player* player, int x, int y, int z) { + Block* block = indices->getBlockDef(chunks->get(x,y,z)->id); + itemid_t id = block->rt.pickingItem; + auto inventory = player->getInventory(); + size_t slotid = inventory->findSlotByItem(id, 0, 10); + if (slotid == Inventory::npos) { + slotid = player->getChosenSlot(); + } else { + player->setChosenSlot(slotid); + } + ItemStack& stack = inventory->getSlot(slotid); + if (stack.getItemId() != id) { + stack.set(ItemStack(id, 1)); + } +} + void PlayerController::updateInteraction(){ auto indices = level->content->getIndices(); Chunks* chunks = level->chunks.get(); Lighting* lighting = level->lighting.get(); Camera* camera = player->camera.get(); - glm::vec3 end; - glm::ivec3 iend; - glm::ivec3 norm; bool xkey = Events::pressed(keycode::X); bool lclick = Events::jactive(BIND_PLAYER_ATTACK) || @@ -223,11 +261,19 @@ void PlayerController::updateInteraction(){ if (xkey) { maxDistance *= 20.0f; } + auto inventory = player->getInventory(); + ItemStack& stack = inventory->getSlot(player->getChosenSlot()); + ItemDef* item = indices->getItemDef(stack.getItemId()); - voxel* vox = chunks->rayCast(camera->position, - camera->front, - maxDistance, - end, norm, iend); + glm::vec3 end; + glm::ivec3 iend; + glm::ivec3 norm; + voxel* vox = chunks->rayCast( + camera->position, + camera->front, + maxDistance, + end, norm, iend + ); if (vox != nullptr){ player->selectedVoxel = *vox; selectedBlockId = vox->id; @@ -238,50 +284,31 @@ void PlayerController::updateInteraction(){ int x = iend.x; int y = iend.y; int z = iend.z; - uint8_t states = 0; - auto inventory = player->getInventory(); - ItemStack& stack = inventory->getSlot(player->getChosenSlot()); - ItemDef* item = indices->getItemDef(stack.getItemId()); Block* def = indices->getBlockDef(item->rt.placingBlock); - if (def && def->rotatable){ - const std::string& name = def->rotations.name; - if (name == "pipe") { - if (norm.x < 0.0f) states = BLOCK_DIR_WEST; - else if (norm.x > 0.0f) states = BLOCK_DIR_EAST; - else if (norm.y > 0.0f) states = BLOCK_DIR_UP; - else if (norm.y < 0.0f) states = BLOCK_DIR_DOWN; - else if (norm.z > 0.0f) states = BLOCK_DIR_NORTH; - else if (norm.z < 0.0f) states = BLOCK_DIR_SOUTH; - } else if (name == "pane") { - glm::vec3 vec = camera->dir; - if (abs(vec.x) > abs(vec.z)){ - if (vec.x > 0.0f) states = BLOCK_DIR_EAST; - if (vec.x < 0.0f) states = BLOCK_DIR_WEST; - } - if (abs(vec.x) < abs(vec.z)){ - if (vec.z > 0.0f) states = BLOCK_DIR_SOUTH; - if (vec.z < 0.0f) states = BLOCK_DIR_NORTH; - } - } - } + uint8_t states = determine_rotation(def, norm, camera->dir); - if (lclick) { - if (!input.shift && item->rt.funcsset.on_block_break_by) { - if (scripting::on_item_break_block(player.get(), item, x, y, z)) - return; - } + if (lclick && !input.shift && item->rt.funcsset.on_block_break_by) { + if (scripting::on_item_break_block(player.get(), item, x, y, z)) + return; } Block* target = indices->getBlockDef(vox->id); if (lclick && target->breakable){ blocksController->breakBlock(player.get(), target, x, y, z); } - if (rclick) { - if (!input.shift && item->rt.funcsset.on_use_on_block) { - if (scripting::on_item_use_on_block(player.get(), item, x, y, z)) - return; - } + if (rclick && !input.shift) { + bool preventDefault = false; + + if (item->rt.funcsset.on_use) { + preventDefault |= scripting::on_item_use(player.get(), item); + } + if (item->rt.funcsset.on_use_on_block) { + preventDefault |= scripting::on_item_use_on_block(player.get(), item, x, y, z); + } + if (preventDefault) { + return; + } } if (def && rclick){ if (!input.shift && target->rt.funcsset.oninteract) { @@ -316,25 +343,18 @@ void PlayerController::updateInteraction(){ } } } - if (Events::jactive(BIND_PLAYER_PICK)){ - Block* block = indices->getBlockDef(chunks->get(x,y,z)->id); - itemid_t id = block->rt.pickingItem; - auto inventory = player->getInventory(); - size_t slotid = inventory->findSlotByItem(id, 0, 10); - if (slotid == Inventory::npos) { - slotid = player->getChosenSlot(); - } else { - player->setChosenSlot(slotid); - } - ItemStack& stack = inventory->getSlot(slotid); - if (stack.getItemId() != id) { - stack.set(ItemStack(id, 1)); - } + if (Events::jactive(BIND_PLAYER_PICK)) { + pick_block(indices, chunks, player.get(), x, y, z); } } else { selectedBlockId = -1; selectedBlockStates = 0; } + if (rclick) { + if (item->rt.funcsset.on_use) { + scripting::on_item_use(player.get(), item); + } + } } Player* PlayerController::getPlayer() { diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index b659be19..023c9488 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -187,6 +187,17 @@ bool scripting::on_block_interact(Player* player, const Block* block, int x, int return false; } +bool scripting::on_item_use(Player* player, const ItemDef* item) { + std::string name = item->name+".use"; + if (state->getglobal(name)) { + state->pushinteger(player->getId()); + if (state->callNoThrow(4)) { + return state->toboolean(-1); + } + } + return false; +} + bool scripting::on_item_use_on_block(Player* player, const ItemDef* item, int x, int y, int z) { std::string name = item->name+".useon"; if (state->getglobal(name)) { @@ -263,6 +274,7 @@ void scripting::load_item_script(int env, std::string prefix, fs::path file, ite state->execute(env, src, file.u8string()); funcsset.init = register_event(env, "init", prefix+".init"); + funcsset.on_use = register_event(env, "on_use", prefix+".use"); funcsset.on_use_on_block = register_event(env, "on_use_on_block", prefix+".useon"); funcsset.on_block_break_by = register_event(env, "on_block_break_by", prefix+".blockbreakby"); } diff --git a/src/logic/scripting/scripting.h b/src/logic/scripting/scripting.h index 36869c23..b4d8c312 100644 --- a/src/logic/scripting/scripting.h +++ b/src/logic/scripting/scripting.h @@ -30,7 +30,7 @@ namespace scripting { extern Level* level; extern BlocksController* blocks; - /* Lua environment wrapper for automatic deletion */ + /// @brief Lua environment wrapper for automatic deletion class Environment { int env; public: @@ -58,34 +58,51 @@ namespace scripting { void on_block_broken(Player* player, const Block* block, int x, int y, int z); bool on_block_interact(Player* player, const Block* block, int x, int y, int z); - /** Called on RMB click on block with the item selected - @return true if prevents default action */ + /// @brief Called on RMB click with the item selected + /// @return true if prevents default action + bool on_item_use(Player* player, const ItemDef* item); + + /// @brief Called on RMB click on block with the item selected + /// @return true if prevents default action bool on_item_use_on_block(Player* player, const ItemDef* item, int x, int y, int z); - /** Called on LMB click on block with the item selected - @return true if prevents default action */ + + /// @brief Called on LMB click on block with the item selected + /// @return true if prevents default action bool on_item_break_block(Player* player, const ItemDef* item, int x, int y, int z); - /** Called on UI view show */ + /// @brief Called on UI view show void on_ui_open(UiDocument* layout, Inventory* inventory, glm::ivec3 blockcoord); - /** Called on UI view close*/ + + /// @brief Called on UI view close void on_ui_close(UiDocument* layout, Inventory* inventory); - /** Load script associated with a Block */ + /// @brief Load script associated with a Block + /// @param env environment id + /// @param prefix pack id + /// @param file item script file + /// @param funcsset block callbacks set void load_block_script(int env, std::string prefix, fs::path file, block_funcs_set& funcsset); - /** Load script associated with an Item */ - void load_item_script(int env, std::string prefix, fs::path file, item_funcs_set& funcsset); - /** - * Load package-specific world script - * @param env environment id - * @param packid content-pack id - * @param file script file path - */ + /// @brief Load script associated with an Item + /// @param env environment id + /// @param prefix pack id + /// @param file item script file + /// @param funcsset item callbacks set + void load_item_script(int env, std::string prefix, fs::path file, item_funcs_set& funcsset); + + /// @brief Load package-specific world script + /// @param env environment id + /// @param packid content-pack id + /// @param file script file path void load_world_script(int env, std::string packid, fs::path file); - /** Load script associated with an UiDocument */ + /// @brief Load script associated with an UiDocument + /// @param env environment id + /// @param prefix pack id + /// @param file item script file + /// @param script document script info void load_layout_script(int env, std::string prefix, fs::path file, uidocscript& script); - /** Finalize lua state. Using scripting after will lead to Lua panic */ + /// @brief Finalize lua state. Using scripting after will lead to Lua panic void close(); }