Add IDropAction and related stuff
authorKahrl <kahrl@gmx.net>
Sun, 27 Nov 2011 03:01:38 +0000 (05:01 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Tue, 29 Nov 2011 17:13:54 +0000 (19:13 +0200)
src/defaultsettings.cpp
src/game.cpp
src/guiKeyChangeMenu.cpp
src/guiKeyChangeMenu.h
src/inventory.cpp
src/inventory.h
src/server.cpp

index 20a6dc0a8a71dcc689c2d8e7307a0f276d74b02c..a1e3ff99853864d2ac30edc7e7ecd15834a41069 100644 (file)
@@ -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");
index a7e1ccd8200cdbb71dcc113bf4bd070dc4f140f0..1c555dbee631d3288461c7c0ff413c38cd065d51 100644 (file)
@@ -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"<<std::endl;
index 4a92e61e9313dc2d41573ca5957af4bf5297044a..01f583a0175dc8d79976079d5c62679b41aa8fd2 100644 (file)
@@ -202,6 +202,21 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
                                wgettext(key_jump.name()));
        }
 
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > 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();
index 2e8773a779e4469663a4371e93c25a906a59a3d4..a3d8b474351b1bfd8ee74884a766d2603ce0e48f 100644 (file)
@@ -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;
index c7dd2a87b92325c12469f55b3257a6cd51cebed6..f3b81090be892e561dca924cb4f6a9dcd6b109e4 100644 (file)
@@ -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)
                        <<std::endl;
 }
 
+IDropAction::IDropAction(std::istream &is)
+{
+       std::string ts;
+
+       std::getline(is, ts, ' ');
+       count = stoi(ts);
+
+       std::getline(is, from_inv, ' ');
+
+       std::getline(is, from_list, ' ');
+
+       std::getline(is, ts, ' ');
+       from_i = stoi(ts);
+}
+
+void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
+               ServerEnvironment *env)
+{
+       Inventory *inv_from = mgr->getInventory(c, from_inv);
+       
+       if(!inv_from){
+               infostream<<"IDropAction::apply(): FAIL: source inventory not found: "
+                               <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""<<std::endl;
+               return;
+       }
+
+       InventoryList *list_from = inv_from->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=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
+                               <<", from_list=\""<<from_list<<"\""<<std::endl;
+               return;
+       }
+       if(list_from->getItem(from_i) == NULL)
+       {
+               infostream<<"IDropAction::apply(): FAIL: source item not found: "
+                               <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
+                               <<", from_list=\""<<from_list<<"\""
+                               <<" from_i="<<from_i<<std::endl;
+               return;
+       }
+
+       v3f pos = c->current_player->getPosition();
+       pos.Y += 0.5*BS;
+       v3s16 blockpos = getNodeBlockPos(floatToInt(pos, BS));
+
+       /*
+               Ensure that the block is loaded so that the item
+               can properly be added to the static list too
+       */
+       MapBlock *block = env->getMap().emergeBlock(blockpos, false);
+       if(block==NULL)
+       {
+               infostream<<"IDropAction::apply(): FAIL: block not found: "
+                               <<blockpos.X<<","<<blockpos.Y<<","<<blockpos.Z
+                               <<std::endl;
+               return;
+       }
+
+       // Take item from source list
+       if(count == 0)
+               count = list_from->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"
+                       <<std::endl;
+       }
+       else
+       {
+               // Add the object to the environment
+               env->addActiveObject(obj);
+
+               infostream<<"Dropped object"<<std::endl;
+       }
+
+       mgr->inventoryModified(c, from_inv);
+
+       infostream<<"IDropAction::apply(): dropped "
+                       <<"["<<describeC(c)<<"]"
+                       <<" from inv=\""<<from_inv<<"\""
+                       <<" list=\""<<from_list<<"\""
+                       <<" i="<<from_i
+                       <<std::endl;
+}
+
 /*
        Craft checking system
 */
index d6049f52fd9ca0fb943da77b8fd0c5453413dfeb..441b2ca4d09035bc1f28b208bc47a6ff451c230d 100644 (file)
@@ -62,7 +62,7 @@ public:
        // Returns the string used for inventory
        virtual std::string getItemString();
        // Creates an object from the item, to be placed in the world.
-       virtual ServerActiveObject* createSAO(ServerEnvironment *env, u16 id, v3f pos);
+       virtual ServerActiveObject* createSAO(ServerEnvironment *env, v3f pos);
        // Gets amount of items that dropping one SAO will decrement
        virtual u16 getDropCount() const { return getCount(); }
 
@@ -252,7 +252,7 @@ public:
                return os.str();
        }
 
-       ServerActiveObject* createSAO(ServerEnvironment *env, u16 id, v3f pos);
+       ServerActiveObject* createSAO(ServerEnvironment *env, v3f pos);
        u16 getDropCount() const;
 
        virtual bool addableTo(const InventoryItem *other) const
@@ -535,6 +535,7 @@ public:
 };
 
 #define IACTION_MOVE 0
+#define IACTION_DROP 1
 
 struct InventoryAction
 {
@@ -542,7 +543,8 @@ struct InventoryAction
        
        virtual u16 getType() const = 0;
        virtual void serialize(std::ostream &os) const = 0;
-       virtual void apply(InventoryContext *c, InventoryManager *mgr) = 0;
+       virtual void apply(InventoryContext *c, InventoryManager *mgr,
+                       ServerEnvironment *env) = 0;
 };
 
 struct IMoveAction : public InventoryAction
@@ -582,7 +584,42 @@ struct IMoveAction : public InventoryAction
                os<<to_i;
        }
 
-       void apply(InventoryContext *c, InventoryManager *mgr);
+       void apply(InventoryContext *c, InventoryManager *mgr,
+                       ServerEnvironment *env);
+};
+
+struct IDropAction : public InventoryAction
+{
+       // count=0 means "everything"
+       u16 count;
+       std::string from_inv;
+       std::string from_list;
+       s16 from_i;
+       
+       IDropAction()
+       {
+               count = 0;
+               from_i = -1;
+       }
+       
+       IDropAction(std::istream &is);
+
+       u16 getType() const
+       {
+               return IACTION_DROP;
+       }
+
+       void serialize(std::ostream &os) const
+       {
+               os<<"Drop ";
+               os<<count<<" ";
+               os<<from_inv<<" ";
+               os<<from_list<<" ";
+               os<<from_i;
+       }
+
+       void apply(InventoryContext *c, InventoryManager *mgr,
+                       ServerEnvironment *env);
 };
 
 /*
index 7581f7a2b04a7ee4dbcc9f540201f312da4ca852..66cc099e3d612bad8f0144c15d3da95055be4daf 100644 (file)
@@ -3032,7 +3032,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                /*
                                        Create the object
                                */
-                               ServerActiveObject *obj = item->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
                {