3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 (c) 2010 Perttu Ahola <celeron55@gmail.com>
24 #include "inventory.h"
25 #include "serialization.h"
35 InventoryItem::InventoryItem(u16 count)
40 InventoryItem::~InventoryItem()
44 InventoryItem* InventoryItem::deSerialize(std::istream &is)
46 DSTACK(__FUNCTION_NAME);
48 //is.imbue(std::locale("C"));
51 std::getline(is, name, ' ');
53 if(name == "MaterialItem")
55 // u16 reads directly as a number (u8 doesn't)
61 throw SerializationError("Too large material number");
62 return new MaterialItem(material, count);
64 else if(name == "MBOItem")
66 std::string inventorystring;
67 std::getline(is, inventorystring, '|');
68 return new MapBlockObjectItem(inventorystring);
70 else if(name == "CraftItem")
73 std::getline(is, subname, ' ');
76 return new CraftItem(subname, count);
78 else if(name == "ToolItem")
81 std::getline(is, toolname, ' ');
84 return new ToolItem(toolname, wear);
88 dstream<<"Unknown InventoryItem name=\""<<name<<"\""<<std::endl;
89 throw SerializationError("Unknown InventoryItem name");
97 video::ITexture * MapBlockObjectItem::getImage()
101 if(m_inventorystring.substr(0,3) == "Rat")
102 //return g_device->getVideoDriver()->getTexture(porting::getDataPath("rat.png").c_str());
103 //return g_irrlicht->getTexture("rat.png");
106 if(m_inventorystring.substr(0,4) == "Sign")
107 //return g_device->getVideoDriver()->getTexture(porting::getDataPath("sign.png").c_str());
108 //return g_irrlicht->getTexture("sign.png");
114 std::string MapBlockObjectItem::getText()
116 if(m_inventorystring.substr(0,3) == "Rat")
119 if(m_inventorystring.substr(0,4) == "Sign")
125 MapBlockObject * MapBlockObjectItem::createObject
126 (v3f pos, f32 player_yaw, f32 player_pitch)
128 std::istringstream is(m_inventorystring);
130 std::getline(is, name, ' ');
136 else if(name == "Sign")
139 std::getline(is, text, '|');
140 SignObject *obj = new SignObject(NULL, -1, pos);
142 obj->setYaw(-player_yaw);
145 else if(name == "Rat")
147 RatObject *obj = new RatObject(NULL, -1, pos);
150 else if(name == "ItemObj")
153 Now we are an inventory item containing the serialization
154 string of an object that contains the serialization
155 string of an inventory item. Fuck this.
158 dstream<<__FUNCTION_NAME<<": WARNING: Ignoring ItemObj "
159 <<"because an item-object should never be inside "
160 <<"an object-item."<<std::endl;
173 InventoryList::InventoryList(std::string name, u32 size)
180 InventoryList::~InventoryList()
182 for(u32 i=0; i<m_items.size(); i++)
189 void InventoryList::clearItems()
191 for(u32 i=0; i<m_items.size(); i++)
199 for(u32 i=0; i<m_size; i++)
201 m_items.push_back(NULL);
205 void InventoryList::serialize(std::ostream &os)
207 //os.imbue(std::locale("C"));
209 for(u32 i=0; i<m_items.size(); i++)
211 InventoryItem *item = m_items[i];
224 os<<"EndInventoryList\n";
227 void InventoryList::deSerialize(std::istream &is)
229 //is.imbue(std::locale("C"));
237 std::getline(is, line, '\n');
239 std::istringstream iss(line);
240 //iss.imbue(std::locale("C"));
243 std::getline(iss, name, ' ');
245 if(name == "EndInventoryList")
249 // This is a temporary backwards compatibility fix
250 else if(name == "end")
254 else if(name == "Item")
256 if(item_i > getSize() - 1)
257 throw SerializationError("too many items");
258 InventoryItem *item = InventoryItem::deSerialize(iss);
259 m_items[item_i++] = item;
261 else if(name == "Empty")
263 if(item_i > getSize() - 1)
264 throw SerializationError("too many items");
265 m_items[item_i++] = NULL;
269 throw SerializationError("Unknown inventory identifier");
274 InventoryList::InventoryList(const InventoryList &other)
277 Do this so that the items get cloned. Otherwise the pointers
278 in the array will just get copied.
283 InventoryList & InventoryList::operator = (const InventoryList &other)
285 m_name = other.m_name;
286 m_size = other.m_size;
288 for(u32 i=0; i<other.m_items.size(); i++)
290 InventoryItem *item = other.m_items[i];
293 m_items[i] = item->clone();
300 std::string InventoryList::getName()
305 u32 InventoryList::getSize()
307 return m_items.size();
310 u32 InventoryList::getUsedSlots()
313 for(u32 i=0; i<m_items.size(); i++)
315 InventoryItem *item = m_items[i];
322 InventoryItem * InventoryList::getItem(u32 i)
324 if(i > m_items.size() - 1)
329 InventoryItem * InventoryList::changeItem(u32 i, InventoryItem *newitem)
331 assert(i < m_items.size());
333 InventoryItem *olditem = m_items[i];
334 m_items[i] = newitem;
338 void InventoryList::deleteItem(u32 i)
340 assert(i < m_items.size());
341 InventoryItem *item = changeItem(i, NULL);
346 InventoryItem * InventoryList::addItem(InventoryItem *newitem)
349 First try to find if it could be added to some existing items
351 for(u32 i=0; i<m_items.size(); i++)
353 // Ignore empty slots
354 if(m_items[i] == NULL)
357 newitem = addItem(i, newitem);
359 return NULL; // All was eaten
363 Then try to add it to empty slots
365 for(u32 i=0; i<m_items.size(); i++)
367 // Ignore unempty slots
368 if(m_items[i] != NULL)
371 newitem = addItem(i, newitem);
373 return NULL; // All was eaten
380 InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
382 // If it is an empty position, it's an easy job.
383 InventoryItem *to_item = m_items[i];
386 m_items[i] = newitem;
390 // If not addable, return the item
391 if(newitem->addableTo(to_item) == false)
394 // If the item fits fully in the slot, add counter and delete it
395 if(newitem->getCount() <= to_item->freeSpace())
397 to_item->add(newitem->getCount());
401 // Else the item does not fit fully. Add all that fits and return
405 u16 freespace = to_item->freeSpace();
406 to_item->add(freespace);
407 newitem->remove(freespace);
412 InventoryItem * InventoryList::takeItem(u32 i, u32 count)
417 InventoryItem *item = m_items[i];
418 // If it is an empty position, return NULL
422 if(count >= item->getCount())
424 // Get the item by swapping NULL to its place
425 return changeItem(i, NULL);
429 InventoryItem *item2 = item->clone();
431 item2->setCount(count);
438 void InventoryList::decrementMaterials(u16 count)
440 for(u32 i=0; i<m_items.size(); i++)
442 InventoryItem *item = takeItem(i, count);
448 void InventoryList::print(std::ostream &o)
450 o<<"InventoryList:"<<std::endl;
451 for(u32 i=0; i<m_items.size(); i++)
453 InventoryItem *item = m_items[i];
467 Inventory::~Inventory()
472 void Inventory::clear()
474 for(u32 i=0; i<m_lists.size(); i++)
481 Inventory::Inventory()
485 Inventory::Inventory(const Inventory &other)
490 Inventory & Inventory::operator = (const Inventory &other)
493 for(u32 i=0; i<other.m_lists.size(); i++)
495 m_lists.push_back(new InventoryList(*other.m_lists[i]));
500 void Inventory::serialize(std::ostream &os)
502 for(u32 i=0; i<m_lists.size(); i++)
504 InventoryList *list = m_lists[i];
505 os<<"List "<<list->getName()<<" "<<list->getSize()<<"\n";
509 os<<"EndInventory\n";
512 void Inventory::deSerialize(std::istream &is)
519 std::getline(is, line, '\n');
521 std::istringstream iss(line);
524 std::getline(iss, name, ' ');
526 if(name == "EndInventory")
530 // This is a temporary backwards compatibility fix
531 else if(name == "end")
535 else if(name == "List")
537 std::string listname;
540 std::getline(iss, listname, ' ');
543 InventoryList *list = new InventoryList(listname, listsize);
544 list->deSerialize(is);
546 m_lists.push_back(list);
550 throw SerializationError("Unknown inventory identifier");
555 InventoryList * Inventory::addList(const std::string &name, u32 size)
557 s32 i = getListIndex(name);
560 if(m_lists[i]->getSize() != size)
563 m_lists[i] = new InventoryList(name, size);
569 m_lists.push_back(new InventoryList(name, size));
570 return m_lists.getLast();
574 InventoryList * Inventory::getList(const std::string &name)
576 s32 i = getListIndex(name);
582 s32 Inventory::getListIndex(const std::string &name)
584 for(u32 i=0; i<m_lists.size(); i++)
586 if(m_lists[i]->getName() == name)
596 InventoryAction * InventoryAction::deSerialize(std::istream &is)
599 std::getline(is, type, ' ');
601 InventoryAction *a = NULL;
605 a = new IMoveAction(is);
611 void IMoveAction::apply(Inventory *inventory)
613 /*dstream<<"from_name="<<from_name<<" to_name="<<to_name<<std::endl;
614 dstream<<"from_i="<<from_i<<" to_i="<<to_i<<std::endl;*/
615 InventoryList *list_from = inventory->getList(from_name);
616 InventoryList *list_to = inventory->getList(to_name);
617 /*dstream<<"list_from="<<list_from<<" list_to="<<list_to
620 dstream<<" list_from->getItem(from_i)="<<list_from->getItem(from_i)
623 dstream<<" list_to->getItem(to_i)="<<list_to->getItem(to_i)
627 If a list doesn't exist or the source item doesn't exist
628 or the source and the destination slots are the same
630 if(!list_from || !list_to || list_from->getItem(from_i) == NULL
631 || (list_from == list_to && from_i == to_i))
633 dstream<<__FUNCTION_NAME<<": Operation not allowed"<<std::endl;
637 // Take item from source list
638 InventoryItem *item1 = NULL;
640 item1 = list_from->changeItem(from_i, NULL);
642 item1 = list_from->takeItem(from_i, count);
644 // Try to add the item to destination list
645 InventoryItem *olditem = item1;
646 item1 = list_to->addItem(to_i, item1);
648 // If nothing is returned, the item was fully added
652 // If olditem is returned, nothing was added.
653 bool nothing_added = (item1 == olditem);
655 // If something else is returned, part of the item was left unadded.
656 // Add the other part back to the source item
657 list_from->addItem(from_i, item1);
659 // If olditem is returned, nothing was added.
663 // Take item from source list
664 item1 = list_from->changeItem(from_i, NULL);
665 // Adding was not possible, swap the items.
666 InventoryItem *item2 = list_to->changeItem(to_i, item1);
667 // Put item from destination list to the source list
668 list_from->changeItem(from_i, item2);