]> git.lizzy.rs Git - minetest.git/commitdiff
Add MoveSomewhere inventory action
authorest31 <MTest31@outlook.com>
Sat, 20 Jun 2015 10:55:48 +0000 (12:55 +0200)
committerest31 <MTest31@outlook.com>
Tue, 23 Jun 2015 18:18:41 +0000 (20:18 +0200)
Improve shift+click experience

src/client.h
src/guiFormSpecMenu.cpp
src/inventory.cpp
src/inventory.h
src/inventorymanager.cpp
src/inventorymanager.h

index 56f040909f1eb204341477c988cfc35e51e8aced..daeef398567ad3e9db9e5668eabb57613f99e7dc 100644 (file)
@@ -493,6 +493,9 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
        bool mediaReceived()
        { return m_media_downloader == NULL; }
 
+       u8 getProtoVersion()
+       { return m_proto_ver; }
+
        float mediaReceiveProgress();
 
        void afterContentReceived(IrrlichtDevice *device);
index c11fc303a6d6762cb399e5bdfb223e6ea927ac31..f168306191e4d626b87dcd26fb24f66334c284ff 100644 (file)
@@ -3384,31 +3384,42 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
                                        break;
                                ItemStack stack_from = list_from->getItem(s.i);
                                assert(shift_move_amount <= stack_from.count);
-
-                               // find a place (or more than one) to add the new item
-                               u32 ilt_size = list_to->getSize();
-                               ItemStack leftover;
-                               for (u32 slot_to = 0; slot_to < ilt_size
-                                               && shift_move_amount > 0; slot_to++) {
-                                       list_to->itemFits(slot_to, stack_from, &leftover);
-                                       if (leftover.count < stack_from.count) {
-                                               infostream << "Handing IACTION_MOVE to manager" << std::endl;
-                                               IMoveAction *a = new IMoveAction();
-                                               a->count = MYMIN(shift_move_amount,
-                                                       (u32) (stack_from.count - leftover.count));
-                                               shift_move_amount -= a->count;
-                                               a->from_inv = s.inventoryloc;
-                                               a->from_list = s.listname;
-                                               a->from_i = s.i;
-                                               a->to_inv = to_inv_sp.inventoryloc;
-                                               a->to_list = to_inv_sp.listname;
-                                               a->to_i = slot_to;
-                                               m_invmgr->inventoryAction(a);
-                                               stack_from = leftover;
+                               if (m_client->getProtoVersion() >= 25) {
+                                       infostream << "Handing IACTION_MOVE to manager" << std::endl;
+                                       IMoveAction *a = new IMoveAction();
+                                       a->count = shift_move_amount;
+                                       a->from_inv = s.inventoryloc;
+                                       a->from_list = s.listname;
+                                       a->from_i = s.i;
+                                       a->to_inv = to_inv_sp.inventoryloc;
+                                       a->to_list = to_inv_sp.listname;
+                                       a->move_somewhere = true;
+                                       m_invmgr->inventoryAction(a);
+                               } else {
+                                       // find a place (or more than one) to add the new item
+                                       u32 ilt_size = list_to->getSize();
+                                       ItemStack leftover;
+                                       for (u32 slot_to = 0; slot_to < ilt_size
+                                                       && shift_move_amount > 0; slot_to++) {
+                                               list_to->itemFits(slot_to, stack_from, &leftover);
+                                               if (leftover.count < stack_from.count) {
+                                                       infostream << "Handing IACTION_MOVE to manager" << std::endl;
+                                                       IMoveAction *a = new IMoveAction();
+                                                       a->count = MYMIN(shift_move_amount,
+                                                               (u32) (stack_from.count - leftover.count));
+                                                       shift_move_amount -= a->count;
+                                                       a->from_inv = s.inventoryloc;
+                                                       a->from_list = s.listname;
+                                                       a->from_i = s.i;
+                                                       a->to_inv = to_inv_sp.inventoryloc;
+                                                       a->to_list = to_inv_sp.listname;
+                                                       a->to_i = slot_to;
+                                                       m_invmgr->inventoryAction(a);
+                                                       stack_from = leftover;
+                                               }
                                        }
                                }
                        } while (0);
-
                } else if (drop_amount > 0) {
                        m_selected_content_guess = ItemStack(); // Clear
 
index 7941b3a2a7d3fbee314fbd2f4e12f2992d4f4fb1..ff2c15b651b431a5a3f333f31bfeee489e9ba54c 100644 (file)
@@ -782,11 +782,48 @@ ItemStack InventoryList::peekItem(u32 i, u32 peekcount) const
        return m_items[i].peekItem(peekcount);
 }
 
-void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
+void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count)
 {
-       if(this == dest && i == dest_i)
+       // Take item from source list
+       ItemStack item1;
+       if (count == 0)
+               item1 = changeItem(i, ItemStack());
+       else
+               item1 = takeItem(i, count);
+
+       if (item1.empty())
                return;
 
+       // Try to add the item to destination list
+       u32 oldcount = item1.count;
+       u32 dest_size = dest->getSize();
+       // First try all the non-empty slots
+       for (u32 dest_i = 0; dest_i < dest_size; dest_i++) {
+               if (!m_items[dest_i].empty()) {
+                       item1 = dest->addItem(dest_i, item1);
+                       if (item1.empty()) return;
+               }
+       }
+
+       // Then try all the empty ones
+       for (u32 dest_i = 0; dest_i < dest_size; dest_i++) {
+               if (m_items[dest_i].empty()) {
+                       item1 = dest->addItem(dest_i, item1);
+                       if (item1.empty()) return;
+               }
+       }
+
+       // If we reach this, the item was not fully added
+       // Add the remaining part back to the source item
+       addItem(i, item1);
+}
+
+u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i,
+               u32 count, bool swap_if_needed)
+{
+       if(this == dest && i == dest_i)
+               return count;
+
        // Take item from source list
        ItemStack item1;
        if(count == 0)
@@ -795,7 +832,7 @@ void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
                item1 = takeItem(i, count);
 
        if(item1.empty())
-               return;
+               return 0;
 
        // Try to add the item to destination list
        u32 oldcount = item1.count;
@@ -813,8 +850,7 @@ void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
 
                // If olditem is returned, nothing was added.
                // Swap the items
-               if(nothing_added)
-               {
+               if (nothing_added && swap_if_needed) {
                        // Take item from source list
                        item1 = changeItem(i, ItemStack());
                        // Adding was not possible, swap the items.
@@ -823,6 +859,7 @@ void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
                        changeItem(i, item2);
                }
        }
+       return (oldcount - item1.count);
 }
 
 /*
index faaa5ef95a450469c138d3e2c1c18ea215d0413e..e3c994fc3db9f8eb6f97379c1b5b62cc4ec17b4e 100644 (file)
@@ -244,7 +244,13 @@ class InventoryList
 
        // Move an item to a different list (or a different stack in the same list)
        // count is the maximum number of items to move (0 for everything)
-       void moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count = 0);
+       // returns number of moved items
+       u32 moveItem(u32 i, InventoryList *dest, u32 dest_i,
+               u32 count = 0, bool swap_if_needed = true);
+
+       // like moveItem, but without a fixed destination index
+       // also with optional rollback recording
+       void moveItemSomewhere(u32 i, InventoryList *dest, u32 count);
 
 private:
        std::vector<ItemStack> m_items;
index 640e3395be684741017b46a34bcd727e9d5f470d..96ce48086be65abfe2d73fd89503ddb60b101935 100644 (file)
@@ -121,16 +121,13 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
 
        InventoryAction *a = NULL;
 
-       if(type == "Move")
-       {
-               a = new IMoveAction(is);
-       }
-       else if(type == "Drop")
-       {
+       if (type == "Move") {
+               a = new IMoveAction(is, false);
+       } else if (type == "MoveSomewhere") {
+               a = new IMoveAction(is, true);
+       } else if (type == "Drop") {
                a = new IDropAction(is);
-       }
-       else if(type == "Craft")
-       {
+       } else if(type == "Craft") {
                a = new ICraftAction(is);
        }
 
@@ -141,9 +138,12 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
        IMoveAction
 */
 
-IMoveAction::IMoveAction(std::istream &is)
+IMoveAction::IMoveAction(std::istream &is, bool somewhere)
 {
        std::string ts;
+       move_somewhere = somewhere;
+       caused_by_move_somewhere = false;
+       move_count = 0;
 
        std::getline(is, ts, ' ');
        count = stoi(ts);
@@ -161,8 +161,10 @@ IMoveAction::IMoveAction(std::istream &is)
 
        std::getline(is, to_list, ' ');
 
-       std::getline(is, ts, ' ');
-       to_i = stoi(ts);
+       if (!somewhere) {
+               std::getline(is, ts, ' ');
+               to_i = stoi(ts);
+       }
 }
 
 void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
@@ -202,6 +204,48 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
                return;
        }
 
+       if (move_somewhere) {
+               s16 old_to_i = to_i;
+               u16 old_count = count;
+               caused_by_move_somewhere = true;
+               move_somewhere = false;
+
+               infostream << "IMoveAction::apply(): moving item somewhere"
+                       << " msom=" << move_somewhere
+                       << " count=" << count
+                       << " from inv=\"" << from_inv.dump() << "\""
+                       << " list=\"" << from_list << "\""
+                       << " i=" << from_i
+                       << " to inv=\"" << to_inv.dump() << "\""
+                       << " list=\"" << to_list << "\""
+                       << std::endl;
+
+               // Try to add the item to destination list
+               s16 dest_size = list_to->getSize();
+               // First try all the non-empty slots
+               for (s16 dest_i = 0; dest_i < dest_size && count > 0; dest_i++) {
+                       if (!list_to->getItem(dest_i).empty()) {
+                               to_i = dest_i;
+                               apply(mgr, player, gamedef);
+                               count -= move_count;
+                       }
+               }
+
+               // Then try all the empty ones
+               for (s16 dest_i = 0; dest_i < dest_size && count > 0; dest_i++) {
+                       if (list_to->getItem(dest_i).empty()) {
+                               to_i = dest_i;
+                               apply(mgr, player, gamedef);
+                               count -= move_count;
+                       }
+               }
+
+               to_i = old_to_i;
+               count = old_count;
+               caused_by_move_somewhere = false;
+               move_somewhere = true;
+               return;
+       }
        /*
                Do not handle rollback if both inventories are that of the same player
        */
@@ -324,7 +368,8 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
                If something is wrong (source item is empty, destination is the
                same as source), nothing happens
        */
-       list_from->moveItem(from_i, list_to, to_i, count);
+       move_count = list_from->moveItem(from_i,
+               list_to, to_i, count, !caused_by_move_somewhere);
 
        // If source is infinite, reset it's stack
        if(src_can_take_count == -1){
@@ -352,15 +397,17 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
                list_from->takeItem(from_i, count);
        }
 
-       infostream<<"IMoveAction::apply(): moved"
-                       <<" count="<<count
-                       <<" from inv=\""<<from_inv.dump()<<"\""
-                       <<" list=\""<<from_list<<"\""
-                       <<" i="<<from_i
-                       <<" to inv=\""<<to_inv.dump()<<"\""
-                       <<" list=\""<<to_list<<"\""
-                       <<" i="<<to_i
-                       <<std::endl;
+       infostream << "IMoveAction::apply(): moved"
+                       << " msom=" << move_somewhere
+                       << " caused=" << caused_by_move_somewhere
+                       << " count=" << count
+                       << " from inv=\"" << from_inv.dump() << "\""
+                       << " list=\"" << from_list << "\""
+                       << " i=" << from_i
+                       << " to inv=\"" << to_inv.dump() << "\""
+                       << " list=\"" << to_list << "\""
+                       << " i=" << to_i
+                       << std::endl;
 
        /*
                Record rollback information
@@ -480,7 +527,10 @@ void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
        if(!list_from || !list_to)
                return;
 
-       list_from->moveItem(from_i, list_to, to_i, count);
+       if (!move_somewhere)
+               list_from->moveItem(from_i, list_to, to_i, count);
+       else
+               list_from->moveItemSomewhere(from_i, list_to, count);
 
        mgr->setInventoryModified(from_inv);
        if(inv_from != inv_to)
index a255e979a5a9e5f4b5a9b1d2be2c35ec2f179e34..bbeb5117ca2577bd3ffb4d7c081fe4ea0a9e042c 100644 (file)
@@ -143,15 +143,24 @@ struct IMoveAction : public InventoryAction
        InventoryLocation to_inv;
        std::string to_list;
        s16 to_i;
+       bool move_somewhere;
+
+       // treat these as private
+       // related to movement to somewhere
+       bool caused_by_move_somewhere;
+       u32 move_count;
        
        IMoveAction()
        {
                count = 0;
                from_i = -1;
                to_i = -1;
+               move_somewhere = false;
+               caused_by_move_somewhere = false;
+               move_count = 0;
        }
        
-       IMoveAction(std::istream &is);
+       IMoveAction(std::istream &is, bool somewhere);
 
        u16 getType() const
        {
@@ -160,14 +169,18 @@ struct IMoveAction : public InventoryAction
 
        void serialize(std::ostream &os) const
        {
-               os<<"Move ";
-               os<<count<<" ";
-               os<<from_inv.dump()<<" ";
-               os<<from_list<<" ";
-               os<<from_i<<" ";
-               os<<to_inv.dump()<<" ";
-               os<<to_list<<" ";
-               os<<to_i;
+               if (!move_somewhere)
+                       os << "Move ";
+               else
+                       os << "MoveSomewhere ";
+               os << count << " ";
+               os << from_inv.dump() << " ";
+               os << from_list << " ";
+               os << from_i << " ";
+               os << to_inv.dump() << " ";
+               os << to_list;
+               if (!move_somewhere)
+                       os << " " << to_i;
        }
 
        void apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef);