diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 20a6dc0a8..a1e3ff998 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -35,6 +35,7 @@ void set_default_settings(Settings *settings) settings->setDefault("keymap_right", "KEY_KEY_D"); settings->setDefault("keymap_jump", "KEY_SPACE"); settings->setDefault("keymap_sneak", "KEY_LSHIFT"); + settings->setDefault("keymap_drop", "KEY_KEY_Q"); settings->setDefault("keymap_inventory", "KEY_KEY_I"); settings->setDefault("keymap_special1", "KEY_KEY_E"); settings->setDefault("keymap_chat", "KEY_KEY_T"); diff --git a/src/game.cpp b/src/game.cpp index a7e1ccd82..1c555dbee 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1215,9 +1215,19 @@ void the_game( input->step(dtime); /* - Launch menus according to keys + Launch menus and trigger stuff according to keys */ - if(input->wasKeyDown(getKeySetting("keymap_inventory"))) + if(input->wasKeyDown(getKeySetting("keymap_drop"))) + { + // drop selected item + IDropAction *a = new IDropAction(); + a->count = 0; + a->from_inv = "current_player"; + a->from_list = "main"; + a->from_i = g_selected_item; + client.inventoryAction(a); + } + else if(input->wasKeyDown(getKeySetting("keymap_inventory"))) { infostream<<"the_game: " <<"Launching inventory"< rect(0, 0, 100, 20); + rect += topleft + v2s32(offset.X, offset.Y); + Environment->addStaticText(wgettext("Drop"), rect, false, true, this, -1); + //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT); + } + + { + core::rect < s32 > rect(0, 0, 100, 30); + rect += topleft + v2s32(offset.X + 105, offset.Y - 5); + this->dropbtn = Environment->addButton(rect, this, GUI_ID_KEY_DROP_BUTTON, + wgettext(key_drop.name())); + } + offset += v2s32(0, 25); { core::rect < s32 > rect(0, 0, 100, 20); @@ -352,6 +367,7 @@ bool GUIKeyChangeMenu::acceptInput() g_settings->set("keymap_right", key_right.sym()); g_settings->set("keymap_jump", key_jump.sym()); g_settings->set("keymap_sneak", key_sneak.sym()); + g_settings->set("keymap_drop", key_drop.sym()); g_settings->set("keymap_inventory", key_inventory.sym()); g_settings->set("keymap_chat", key_chat.sym()); g_settings->set("keymap_cmd", key_cmd.sym()); @@ -371,6 +387,7 @@ void GUIKeyChangeMenu::init_keys() key_right = getKeySetting("keymap_right"); key_jump = getKeySetting("keymap_jump"); key_sneak = getKeySetting("keymap_sneak"); + key_drop = getKeySetting("keymap_drop"); key_inventory = getKeySetting("keymap_inventory"); key_chat = getKeySetting("keymap_chat"); key_cmd = getKeySetting("keymap_cmd"); @@ -407,6 +424,9 @@ bool GUIKeyChangeMenu::resetMenu() case GUI_ID_KEY_SNEAK_BUTTON: this->sneak->setText(wgettext(key_sneak.name())); break; + case GUI_ID_KEY_DROP_BUTTON: + this->dropbtn->setText(wgettext(key_drop.name())); + break; case GUI_ID_KEY_INVENTORY_BUTTON: this->inventory->setText( wgettext(key_inventory.name())); @@ -476,6 +496,11 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event) this->sneak->setText(wgettext(kp.name())); this->key_sneak = kp; } + else if (activeKey == GUI_ID_KEY_DROP_BUTTON) + { + this->dropbtn->setText(wgettext(kp.name())); + this->key_drop = kp; + } else if (activeKey == GUI_ID_KEY_INVENTORY_BUTTON) { this->inventory->setText(wgettext(kp.name())); @@ -590,6 +615,11 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event) activeKey = event.GUIEvent.Caller->getID(); this->jump->setText(wgettext("press Key")); break; + case GUI_ID_KEY_DROP_BUTTON: + resetMenu(); + activeKey = event.GUIEvent.Caller->getID(); + this->dropbtn->setText(wgettext("press Key")); + break; case GUI_ID_KEY_CHAT_BUTTON: resetMenu(); activeKey = event.GUIEvent.Caller->getID(); diff --git a/src/guiKeyChangeMenu.h b/src/guiKeyChangeMenu.h index 2e8773a77..a3d8b4743 100644 --- a/src/guiKeyChangeMenu.h +++ b/src/guiKeyChangeMenu.h @@ -45,6 +45,7 @@ enum GUI_ID_KEY_CHAT_BUTTON, GUI_ID_KEY_CMD_BUTTON, GUI_ID_KEY_SNEAK_BUTTON, + GUI_ID_KEY_DROP_BUTTON, GUI_ID_KEY_INVENTORY_BUTTON, GUI_ID_KEY_DUMP_BUTTON, GUI_ID_KEY_RANGE_BUTTON @@ -82,6 +83,7 @@ private: gui::IGUIButton *use; gui::IGUIButton *sneak; gui::IGUIButton *jump; + gui::IGUIButton *dropbtn; gui::IGUIButton *inventory; gui::IGUIButton *fly; gui::IGUIButton *fast; @@ -98,6 +100,7 @@ private: KeyPress key_use; KeyPress key_sneak; KeyPress key_jump; + KeyPress key_drop; KeyPress key_inventory; KeyPress key_fly; KeyPress key_fast; diff --git a/src/inventory.cpp b/src/inventory.cpp index c7dd2a87b..f3b81090b 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content_mapnode.h" #include "content_inventory.h" #include "content_sao.h" +#include "environment.h" +#include "mapblock.h" #include "player.h" #include "log.h" #include "nodedef.h" @@ -173,7 +175,7 @@ std::string InventoryItem::getItemString() { return os.str(); } -ServerActiveObject* InventoryItem::createSAO(ServerEnvironment *env, u16 id, v3f pos) +ServerActiveObject* InventoryItem::createSAO(ServerEnvironment *env, v3f pos) { /* Create an ItemSAO @@ -307,14 +309,14 @@ video::ITexture * CraftItem::getImage() const } #endif -ServerActiveObject* CraftItem::createSAO(ServerEnvironment *env, u16 id, v3f pos) +ServerActiveObject* CraftItem::createSAO(ServerEnvironment *env, v3f pos) { // Special cases ServerActiveObject *obj = item_craft_create_object(m_subname, env, pos); if(obj) return obj; // Default - return InventoryItem::createSAO(env, id, pos); + return InventoryItem::createSAO(env, pos); } u16 CraftItem::getDropCount() const @@ -884,6 +886,10 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is) { a = new IMoveAction(is); } + else if(type == "Drop") + { + a = new IDropAction(is); + } return a; } @@ -918,7 +924,8 @@ IMoveAction::IMoveAction(std::istream &is) to_i = stoi(ts); } -void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr) +void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr, + ServerEnvironment *env) { Inventory *inv_from = mgr->getInventory(c, from_inv); Inventory *inv_to = mgr->getInventory(c, to_inv); @@ -1022,6 +1029,100 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr) <getInventory(c, from_inv); + + if(!inv_from){ + infostream<<"IDropAction::apply(): FAIL: source inventory not found: " + <<"context=["<getList(from_list); + + /* + If a list doesn't exist or the source item doesn't exist + */ + if(!list_from){ + infostream<<"IDropAction::apply(): FAIL: source list not found: " + <<"context=["<getItem(from_i) == NULL) + { + infostream<<"IDropAction::apply(): FAIL: source item not found: " + <<"context=["<getItem(from_i)->getDropCount(); + InventoryItem *item1 = list_from->takeItem(from_i, count); + + // Create an active object + ServerActiveObject *obj = item1->createSAO(env, pos); + if(obj == NULL) + { + infostream<<"IDropAction::apply(): item resulted in NULL object, " + <<"not placing onto map" + <addActiveObject(obj); + + infostream<<"Dropped object"<inventoryModified(c, from_inv); + + infostream<<"IDropAction::apply(): dropped " + <<"["<createSAO(m_env, 0, pos); + ServerActiveObject *obj = item->createSAO(m_env, pos); if(obj == NULL) { @@ -3243,7 +3243,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Disallow moving items if not allowed to build else if((getPlayerPrivs(player) & PRIV_BUILD) == 0) { - return; + disable_action = true; } // if it's a locking chest, only allow the owner or server admins to move items else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0) @@ -3260,7 +3260,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(meta && meta->typeId() == LEGN(m_nodedef, "CONTENT_LOCKABLE_CHEST")) { LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta; if (lcm->getOwner() != player->getName()) - return; + disable_action = true; } } } @@ -3278,7 +3278,36 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(meta && meta->typeId() == LEGN(m_nodedef, "CONTENT_LOCKABLE_CHEST")) { LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta; if (lcm->getOwner() != player->getName()) - return; + disable_action = true; + } + } + } + } + + if(a->getType() == IACTION_DROP) + { + IDropAction *da = (IDropAction*)a; + // Disallow dropping items if not allowed to build + if((getPlayerPrivs(player) & PRIV_BUILD) == 0) + { + disable_action = true; + } + // if it's a locking chest, only allow the owner or server admins to drop items + else if (da->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0) + { + Strfnd fn(da->from_inv); + std::string id0 = fn.next(":"); + if(id0 == "nodemeta") + { + v3s16 p; + p.X = stoi(fn.next(",")); + p.Y = stoi(fn.next(",")); + p.Z = stoi(fn.next(",")); + NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); + if(meta && meta->typeId() == LEGN(m_nodedef, "CONTENT_LOCKABLE_CHEST")) { + LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta; + if (lcm->getOwner() != player->getName()) + disable_action = true; } } } @@ -3287,9 +3316,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(disable_action == false) { // Feed action to player inventory - a->apply(&c, this); - // Eat the action - delete a; + a->apply(&c, this, m_env); } else { @@ -3297,6 +3324,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) UpdateCrafting(player->peer_id); SendInventory(player->peer_id); } + + // Eat the action + delete a; } else {