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