Initial files
[oweals/minetest.git] / src / inventory.cpp
1 /*
2 (c) 2010 Perttu Ahola <celeron55@gmail.com>
3 */
4
5 #include "inventory.h"
6 #include "serialization.h"
7 #include "utility.h"
8 #include "debug.h"
9 #include <sstream>
10 #include "main.h"
11
12 /*
13         InventoryItem
14 */
15
16 InventoryItem::InventoryItem()
17 {
18 }
19
20 InventoryItem::~InventoryItem()
21 {
22 }
23
24 InventoryItem* InventoryItem::deSerialize(std::istream &is)
25 {
26         DSTACK(__FUNCTION_NAME);
27
28         //is.imbue(std::locale("C"));
29         // Read name
30         std::string name;
31         std::getline(is, name, ' ');
32         
33         if(name == "MaterialItem")
34         {
35                 // u16 reads directly as a number (u8 doesn't)
36                 u16 material;
37                 is>>material;
38                 u16 count;
39                 is>>count;
40                 if(material > 255)
41                         throw SerializationError("Too large material number");
42                 return new MaterialItem(material, count);
43         }
44         else if(name == "MBOItem")
45         {
46                 std::string inventorystring;
47                 std::getline(is, inventorystring, '|');
48                 return new MapBlockObjectItem(inventorystring);
49         }
50         else
51         {
52                 dstream<<"Unknown InventoryItem name=\""<<name<<"\""<<std::endl;
53                 throw SerializationError("Unknown InventoryItem name");
54         }
55 }
56
57 /*
58         MapBlockObjectItem
59 */
60
61 video::ITexture * MapBlockObjectItem::getImage()
62 {
63         if(m_inventorystring.substr(0,3) == "Rat")
64                 return g_device->getVideoDriver()->getTexture("../data/rat.png");
65         
66         if(m_inventorystring.substr(0,4) == "Sign")
67                 return g_device->getVideoDriver()->getTexture("../data/sign.png");
68
69         return NULL;
70 }
71 std::string MapBlockObjectItem::getText()
72 {
73         if(m_inventorystring.substr(0,3) == "Rat")
74                 return "";
75         
76         if(m_inventorystring.substr(0,4) == "Sign")
77                 return "";
78
79         return "obj";
80 }
81
82 MapBlockObject * MapBlockObjectItem::createObject
83                 (v3f pos, f32 player_yaw, f32 player_pitch)
84 {
85         std::istringstream is(m_inventorystring);
86         std::string name;
87         std::getline(is, name, ' ');
88         
89         if(name == "None")
90         {
91                 return NULL;
92         }
93         else if(name == "Sign")
94         {
95                 std::string text;
96                 std::getline(is, text, '|');
97                 SignObject *obj = new SignObject(NULL, -1, pos);
98                 obj->setText(text);
99                 obj->setYaw(-player_yaw);
100                 return obj;
101         }
102         else if(name == "Rat")
103         {
104                 RatObject *obj = new RatObject(NULL, -1, pos);
105                 return obj;
106         }
107         else
108         {
109                 return NULL;
110         }
111 }
112
113 /*
114         Inventory
115 */
116
117 Inventory::Inventory(u32 size)
118 {
119         m_size = size;
120         clearItems();
121 }
122
123 Inventory::~Inventory()
124 {
125         for(u32 i=0; i<m_items.size(); i++)
126         {
127                 delete m_items[i];
128         }
129 }
130
131 void Inventory::clearItems()
132 {
133         m_items.clear();
134         for(u32 i=0; i<m_size; i++)
135         {
136                 m_items.push_back(NULL);
137         }
138 }
139
140 void Inventory::serialize(std::ostream &os)
141 {
142         //os.imbue(std::locale("C"));
143         
144         for(u32 i=0; i<m_items.size(); i++)
145         {
146                 InventoryItem *item = m_items[i];
147                 if(item != NULL)
148                 {
149                         os<<"Item ";
150                         item->serialize(os);
151                 }
152                 else
153                 {
154                         os<<"Empty";
155                 }
156                 os<<"\n";
157         }
158
159         os<<"end\n";
160 }
161
162 void Inventory::deSerialize(std::istream &is)
163 {
164         //is.imbue(std::locale("C"));
165
166         clearItems();
167         u32 item_i = 0;
168
169         for(;;)
170         {
171                 std::string line;
172                 std::getline(is, line, '\n');
173
174                 std::istringstream iss(line);
175                 //iss.imbue(std::locale("C"));
176
177                 std::string name;
178                 std::getline(iss, name, ' ');
179
180                 if(name == "end")
181                 {
182                         break;
183                 }
184                 else if(name == "Item")
185                 {
186                         if(item_i > getSize() - 1)
187                                 throw SerializationError("too many items");
188                         InventoryItem *item = InventoryItem::deSerialize(iss);
189                         m_items[item_i++] = item;
190                 }
191                 else if(name == "Empty")
192                 {
193                         if(item_i > getSize() - 1)
194                                 throw SerializationError("too many items");
195                         m_items[item_i++] = NULL;
196                 }
197                 else
198                 {
199                         throw SerializationError("Unknown inventory identifier");
200                 }
201         }
202 }
203
204 Inventory & Inventory::operator = (Inventory &other)
205 {
206         m_size = other.m_size;
207         clearItems();
208         for(u32 i=0; i<other.m_items.size(); i++)
209         {
210                 InventoryItem *item = other.m_items[i];
211                 if(item != NULL)
212                 {
213                         m_items[i] = item->clone();
214                 }
215         }
216
217         return *this;
218 }
219
220 u32 Inventory::getSize()
221 {
222         return m_items.size();
223 }
224
225 u32 Inventory::getUsedSlots()
226 {
227         u32 num = 0;
228         for(u32 i=0; i<m_items.size(); i++)
229         {
230                 InventoryItem *item = m_items[i];
231                 if(item != NULL)
232                         num++;
233         }
234         return num;
235 }
236
237 InventoryItem * Inventory::getItem(u32 i)
238 {
239         if(i > m_items.size() - 1)
240                 return NULL;
241         return m_items[i];
242 }
243
244 InventoryItem * Inventory::changeItem(u32 i, InventoryItem *newitem)
245 {
246         assert(i < m_items.size());
247
248         InventoryItem *olditem = m_items[i];
249         m_items[i] = newitem;
250         return olditem;
251 }
252
253 void Inventory::deleteItem(u32 i)
254 {
255         assert(i < m_items.size());
256         InventoryItem *item = changeItem(i, NULL);
257         if(item)
258                 delete item;
259 }
260
261 bool Inventory::addItem(InventoryItem *newitem)
262 {
263         // If it is a MaterialItem, try to find an already existing one
264         // and just increment the counter
265         if(std::string("MaterialItem") == newitem->getName())
266         {
267                 u8 material = ((MaterialItem*)newitem)->getMaterial();
268                 u8 count = ((MaterialItem*)newitem)->getCount();
269                 for(u32 i=0; i<m_items.size(); i++)
270                 {
271                         InventoryItem *item2 = m_items[i];
272                         if(item2 == NULL)
273                                 continue;
274                         if(std::string("MaterialItem") != item2->getName())
275                                 continue;
276                         // Found one. Check if it is of the right material and has
277                         // free space
278                         MaterialItem *mitem2 = (MaterialItem*)item2;
279                         if(mitem2->getMaterial() != material)
280                                 continue;
281                         //TODO: Add all that can be added and add remaining part
282                         // to another place
283                         if(mitem2->freeSpace() < count)
284                                 continue;
285                         // Add to the counter
286                         mitem2->add(count);
287                         // Dump the parameter
288                         delete newitem;
289                         return true;
290                 }
291         }
292         // Else find an empty position
293         for(u32 i=0; i<m_items.size(); i++)
294         {
295                 InventoryItem *item = m_items[i];
296                 if(item != NULL)
297                         continue;
298                 m_items[i] = newitem;
299                 return true;
300         }
301         // Failed
302         return false;
303 }
304
305 void Inventory::print(std::ostream &o)
306 {
307         o<<"Player inventory:"<<std::endl;
308         for(u32 i=0; i<m_items.size(); i++)
309         {
310                 InventoryItem *item = m_items[i];
311                 if(item != NULL)
312                 {
313                         o<<i<<": ";
314                         item->serialize(o);
315                         o<<"\n";
316                 }
317         }
318 }
319         
320 //END