#include "main.h" // for g_settings
#include "settings.h"
#include "utility.h"
+#include "craftdef.h"
/*
InventoryLocation
{
a = new IDropAction(is);
}
+ else if(type == "Craft")
+ {
+ a = new ICraftAction(is);
+ }
return a;
}
+/*
+ IMoveAction
+*/
+
IMoveAction::IMoveAction(std::istream &is)
{
std::string ts;
to_i = stoi(ts);
}
-void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player)
+void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
{
Inventory *inv_from = mgr->getInventory(from_inv);
Inventory *inv_to = mgr->getInventory(to_inv);
<<", to_list=\""<<to_list<<"\""<<std::endl;
return;
}
- if(list_from->getItem(from_i).empty())
- {
- infostream<<"IMoveAction::apply(): FAIL: source item not found: "
- <<"from_inv=\""<<from_inv.dump()<<"\""
- <<", from_list=\""<<from_list<<"\""
- <<" from_i="<<from_i<<std::endl;
- return;
- }
/*
- If the source and the destination slots are the same
- */
- if(inv_from == inv_to && list_from == list_to && from_i == to_i)
- {
- infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
- <<"are the same: inv=\""<<from_inv.dump()
- <<"\" list=\""<<from_list
- <<"\" i="<<from_i<<std::endl;
- return;
- }
-
- // Take item from source list
- ItemStack item1;
- if(count == 0)
- item1 = list_from->changeItem(from_i, ItemStack());
- else
- item1 = list_from->takeItem(from_i, count);
-
- // Try to add the item to destination list
- int oldcount = item1.count;
- item1 = list_to->addItem(to_i, item1);
+ This performs the actual movement
- // If something is returned, the item was not fully added
- if(!item1.empty())
- {
- // If olditem is returned, nothing was added.
- bool nothing_added = (item1.count == oldcount);
-
- // If something else is returned, part of the item was left unadded.
- // Add the other part back to the source item
- list_from->addItem(from_i, item1);
-
- // If olditem is returned, nothing was added.
- // Swap the items
- if(nothing_added)
- {
- // Take item from source list
- item1 = list_from->changeItem(from_i, ItemStack());
- // Adding was not possible, swap the items.
- ItemStack item2 = list_to->changeItem(to_i, item1);
- // Put item from destination list to the source list
- list_from->changeItem(from_i, item2);
- }
- }
+ 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);
mgr->setInventoryModified(from_inv);
if(inv_from != inv_to)
<<std::endl;
}
+void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
+{
+ // Optional InventoryAction operation that is run on the client
+ // to make lag less apparent.
+
+ Inventory *inv_from = mgr->getInventory(from_inv);
+ Inventory *inv_to = mgr->getInventory(to_inv);
+ if(!inv_from || !inv_to)
+ return;
+
+ InventoryLocation current_player;
+ current_player.setCurrentPlayer();
+ Inventory *inv_player = mgr->getInventory(current_player);
+ if(inv_from != inv_player || inv_to != inv_player)
+ return;
+
+ InventoryList *list_from = inv_from->getList(from_list);
+ InventoryList *list_to = inv_to->getList(to_list);
+ if(!list_from || !list_to)
+ return;
+
+ list_from->moveItem(from_i, list_to, to_i, count);
+
+ mgr->setInventoryModified(from_inv);
+ if(inv_from != inv_to)
+ mgr->setInventoryModified(to_inv);
+}
+
+/*
+ IDropAction
+*/
+
IDropAction::IDropAction(std::istream &is)
{
std::string ts;
from_i = stoi(ts);
}
-void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player)
+void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
{
Inventory *inv_from = mgr->getInventory(from_inv);
<<" i="<<from_i
<<std::endl;
}
+
+void IDropAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
+{
+ // Optional InventoryAction operation that is run on the client
+ // to make lag less apparent.
+
+ Inventory *inv_from = mgr->getInventory(from_inv);
+ if(!inv_from)
+ return;
+
+ InventoryLocation current_player;
+ current_player.setCurrentPlayer();
+ Inventory *inv_player = mgr->getInventory(current_player);
+ if(inv_from != inv_player)
+ return;
+
+ InventoryList *list_from = inv_from->getList(from_list);
+ if(!list_from)
+ return;
+
+ if(count == 0)
+ list_from->changeItem(from_i, ItemStack());
+ else
+ list_from->takeItem(from_i, count);
+
+ mgr->setInventoryModified(from_inv);
+}
+
+/*
+ ICraftAction
+*/
+
+ICraftAction::ICraftAction(std::istream &is)
+{
+ std::string ts;
+
+ std::getline(is, ts, ' ');
+ count = stoi(ts);
+
+ std::getline(is, ts, ' ');
+ craft_inv.deSerialize(ts);
+}
+
+void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
+{
+ Inventory *inv_craft = mgr->getInventory(craft_inv);
+
+ if(!inv_craft){
+ infostream<<"ICraftAction::apply(): FAIL: inventory not found: "
+ <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+ return;
+ }
+
+ InventoryList *list_craft = inv_craft->getList("craft");
+ InventoryList *list_craftresult = inv_craft->getList("craftresult");
+
+ /*
+ If a list doesn't exist or the source item doesn't exist
+ */
+ if(!list_craft){
+ infostream<<"ICraftAction::apply(): FAIL: craft list not found: "
+ <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+ return;
+ }
+ if(!list_craftresult){
+ infostream<<"ICraftAction::apply(): FAIL: craftresult list not found: "
+ <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+ return;
+ }
+ if(list_craftresult->getSize() < 1){
+ infostream<<"ICraftAction::apply(): FAIL: craftresult list too short: "
+ <<"craft_inv=\""<<craft_inv.dump()<<"\""<<std::endl;
+ return;
+ }
+
+ ItemStack crafted;
+ int count_remaining = count;
+ bool found = getCraftingResult(inv_craft, crafted, false, gamedef);
+
+ while(found && list_craftresult->itemFits(0, crafted))
+ {
+ // Decrement input and add crafting output
+ getCraftingResult(inv_craft, crafted, true, gamedef);
+ list_craftresult->addItem(0, crafted);
+ mgr->setInventoryModified(craft_inv);
+
+ actionstream<<player->getDescription()
+ <<" crafts "
+ <<crafted.getItemString()
+ <<std::endl;
+
+ // Decrement counter
+ if(count_remaining == 1)
+ break;
+ else if(count_remaining > 1)
+ count_remaining--;
+
+ // Get next crafting result
+ found = getCraftingResult(inv_craft, crafted, false, gamedef);
+ }
+
+ infostream<<"ICraftAction::apply(): crafted "
+ <<" craft_inv=\""<<craft_inv.dump()<<"\""
+ <<std::endl;
+}
+
+void ICraftAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
+{
+ // Optional InventoryAction operation that is run on the client
+ // to make lag less apparent.
+}
+
+
+// Crafting helper
+bool getCraftingResult(Inventory *inv, ItemStack& result,
+ bool decrementInput, IGameDef *gamedef)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ result.clear();
+
+ // TODO: Allow different sizes of crafting grids
+
+ // Get the InventoryList in which we will operate
+ InventoryList *clist = inv->getList("craft");
+ if(!clist || clist->getSize() != 9)
+ return false;
+
+ // Mangle crafting grid to an another format
+ CraftInput ci;
+ ci.method = CRAFT_METHOD_NORMAL;
+ ci.width = 3;
+ for(u16 i=0; i<9; i++)
+ ci.items.push_back(clist->getItem(i));
+
+ // Find out what is crafted and add it to result item slot
+ CraftOutput co;
+ bool found = gamedef->getCraftDefManager()->getCraftResult(
+ ci, co, decrementInput, gamedef);
+ if(found)
+ result.deSerialize(co.item, gamedef->getItemDefManager());
+
+ if(found && decrementInput)
+ {
+ // CraftInput has been changed, apply changes in clist
+ for(u16 i=0; i<9; i++)
+ {
+ clist->changeItem(i, ci.items[i]);
+ }
+ }
+
+ return found;
+}
+