Tune caves
[oweals/minetest.git] / src / content_nodemeta.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 #include "content_nodemeta.h"
21
22 #include <map>
23 #include "inventory.h"
24 #include "log.h"
25 #include "utility.h"
26 #include "craftdef.h"
27 #include "gamedef.h"
28
29 class Inventory;
30
31 #define NODEMETA_GENERIC 1
32 #define NODEMETA_SIGN 14
33 #define NODEMETA_CHEST 15
34 #define NODEMETA_FURNACE 16
35 #define NODEMETA_LOCKABLE_CHEST 17
36
37 core::map<u16, NodeMetadata::Factory> NodeMetadata::m_types;
38 core::map<std::string, NodeMetadata::Factory2> NodeMetadata::m_names;
39
40 class SignNodeMetadata : public NodeMetadata
41 {
42 public:
43         SignNodeMetadata(IGameDef *gamedef, std::string text);
44         //~SignNodeMetadata();
45         
46         virtual u16 typeId() const;
47         virtual const char* typeName() const
48         { return "sign"; }
49         static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
50         static NodeMetadata* create(IGameDef *gamedef);
51         virtual NodeMetadata* clone(IGameDef *gamedef);
52         virtual void serializeBody(std::ostream &os);
53         virtual std::string infoText();
54
55         virtual bool allowsTextInput(){ return true; }
56         virtual std::string getText(){ return m_text; }
57         virtual void setText(const std::string &t){ m_text = t; }
58
59 private:
60         std::string m_text;
61 };
62
63 class ChestNodeMetadata : public NodeMetadata
64 {
65 public:
66         ChestNodeMetadata(IGameDef *gamedef);
67         ~ChestNodeMetadata();
68         
69         virtual u16 typeId() const;
70         virtual const char* typeName() const
71         { return "chest"; }
72         static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
73         static NodeMetadata* create(IGameDef *gamedef);
74         virtual NodeMetadata* clone(IGameDef *gamedef);
75         virtual void serializeBody(std::ostream &os);
76         virtual std::string infoText();
77         virtual Inventory* getInventory() {return m_inventory;}
78         virtual bool nodeRemovalDisabled();
79         virtual std::string getInventoryDrawSpecString();
80         
81 private:
82         Inventory *m_inventory;
83 };
84
85 class LockingChestNodeMetadata : public NodeMetadata
86 {
87 public:
88         LockingChestNodeMetadata(IGameDef *gamedef);
89         ~LockingChestNodeMetadata();
90
91         virtual u16 typeId() const;
92         virtual const char* typeName() const
93         { return "locked_chest"; }
94         static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
95         static NodeMetadata* create(IGameDef *gamedef);
96         virtual NodeMetadata* clone(IGameDef *gamedef);
97         virtual void serializeBody(std::ostream &os);
98         virtual std::string infoText();
99         virtual Inventory* getInventory() {return m_inventory;}
100         virtual bool nodeRemovalDisabled();
101         virtual std::string getInventoryDrawSpecString();
102
103         virtual std::string getOwner(){ return m_text; }
104         virtual void setOwner(std::string t){ m_text = t; }
105
106 private:
107         Inventory *m_inventory;
108         std::string m_text;
109 };
110
111 class FurnaceNodeMetadata : public NodeMetadata
112 {
113 public:
114         FurnaceNodeMetadata(IGameDef *gamedef);
115         ~FurnaceNodeMetadata();
116         
117         virtual u16 typeId() const;
118         virtual const char* typeName() const
119         { return "furnace"; }
120         virtual NodeMetadata* clone(IGameDef *gamedef);
121         static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
122         static NodeMetadata* create(IGameDef *gamedef);
123         virtual void serializeBody(std::ostream &os);
124         virtual std::string infoText();
125         virtual Inventory* getInventory() {return m_inventory;}
126         virtual void inventoryModified();
127         virtual bool step(float dtime);
128         virtual bool nodeRemovalDisabled();
129         virtual std::string getInventoryDrawSpecString();
130         
131 protected:
132         bool getCookResult(bool remove, std::string &cookresult, float &cooktime);
133         bool getBurnResult(bool remove, float &burntime);
134
135 private:
136         Inventory *m_inventory;
137         std::string m_infotext;
138         float m_step_accumulator;
139         float m_fuel_totaltime;
140         float m_fuel_time;
141         float m_src_totaltime;
142         float m_src_time;
143 };
144
145 /*
146         SignNodeMetadata
147 */
148
149 // Prototype
150 SignNodeMetadata proto_SignNodeMetadata(NULL, "");
151
152 SignNodeMetadata::SignNodeMetadata(IGameDef *gamedef, std::string text):
153         NodeMetadata(gamedef),
154         m_text(text)
155 {
156         NodeMetadata::registerType(typeId(), typeName(), create, create);
157 }
158 u16 SignNodeMetadata::typeId() const
159 {
160         return NODEMETA_SIGN;
161 }
162 NodeMetadata* SignNodeMetadata::create(std::istream &is, IGameDef *gamedef)
163 {
164         std::string text = deSerializeString(is);
165         return new SignNodeMetadata(gamedef, text);
166 }
167 NodeMetadata* SignNodeMetadata::create(IGameDef *gamedef)
168 {
169         return new SignNodeMetadata(gamedef, "");
170 }
171 NodeMetadata* SignNodeMetadata::clone(IGameDef *gamedef)
172 {
173         return new SignNodeMetadata(gamedef, m_text);
174 }
175 void SignNodeMetadata::serializeBody(std::ostream &os)
176 {
177         os<<serializeString(m_text);
178 }
179 std::string SignNodeMetadata::infoText()
180 {
181         return std::string("\"")+m_text+"\"";
182 }
183
184 /*
185         ChestNodeMetadata
186 */
187
188 // Prototype
189 ChestNodeMetadata proto_ChestNodeMetadata(NULL);
190
191 ChestNodeMetadata::ChestNodeMetadata(IGameDef *gamedef):
192         NodeMetadata(gamedef)
193 {
194         NodeMetadata::registerType(typeId(), typeName(), create, create);
195         m_inventory = NULL;
196 }
197 ChestNodeMetadata::~ChestNodeMetadata()
198 {
199         delete m_inventory;
200 }
201 u16 ChestNodeMetadata::typeId() const
202 {
203         return NODEMETA_CHEST;
204 }
205 NodeMetadata* ChestNodeMetadata::create(std::istream &is, IGameDef *gamedef)
206 {
207         ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
208         d->m_inventory = new Inventory(gamedef->idef());
209         d->m_inventory->deSerialize(is);
210         return d;
211 }
212 NodeMetadata* ChestNodeMetadata::create(IGameDef *gamedef)
213 {
214         ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
215         d->m_inventory = new Inventory(gamedef->idef());
216         d->m_inventory->addList("0", 8*4);
217         return d;
218 }
219 NodeMetadata* ChestNodeMetadata::clone(IGameDef *gamedef)
220 {
221         ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
222         d->m_inventory = new Inventory(*m_inventory);
223         return d;
224 }
225 void ChestNodeMetadata::serializeBody(std::ostream &os)
226 {
227         m_inventory->serialize(os);
228 }
229 std::string ChestNodeMetadata::infoText()
230 {
231         return "Chest";
232 }
233 bool ChestNodeMetadata::nodeRemovalDisabled()
234 {
235         /*
236                 Disable removal if chest contains something
237         */
238         InventoryList *list = m_inventory->getList("0");
239         if(list == NULL)
240                 return false;
241         if(list->getUsedSlots() == 0)
242                 return false;
243         return true;
244 }
245 std::string ChestNodeMetadata::getInventoryDrawSpecString()
246 {
247         return
248                 "invsize[8,9;]"
249                 "list[current_name;0;0,0;8,4;]"
250                 "list[current_player;main;0,5;8,4;]";
251 }
252
253 /*
254         LockingChestNodeMetadata
255 */
256
257 // Prototype
258 LockingChestNodeMetadata proto_LockingChestNodeMetadata(NULL);
259
260 LockingChestNodeMetadata::LockingChestNodeMetadata(IGameDef *gamedef):
261         NodeMetadata(gamedef)
262 {
263         NodeMetadata::registerType(typeId(), typeName(), create, create);
264         m_inventory = NULL;
265 }
266 LockingChestNodeMetadata::~LockingChestNodeMetadata()
267 {
268         delete m_inventory;
269 }
270 u16 LockingChestNodeMetadata::typeId() const
271 {
272         return NODEMETA_LOCKABLE_CHEST;
273 }
274 NodeMetadata* LockingChestNodeMetadata::create(std::istream &is, IGameDef *gamedef)
275 {
276         LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
277         d->setOwner(deSerializeString(is));
278         d->m_inventory = new Inventory(gamedef->idef());
279         d->m_inventory->deSerialize(is);
280         return d;
281 }
282 NodeMetadata* LockingChestNodeMetadata::create(IGameDef *gamedef)
283 {
284         LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
285         d->m_inventory = new Inventory(gamedef->idef());
286         d->m_inventory->addList("0", 8*4);
287         return d;
288 }
289 NodeMetadata* LockingChestNodeMetadata::clone(IGameDef *gamedef)
290 {
291         LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
292         d->m_inventory = new Inventory(*m_inventory);
293         return d;
294 }
295 void LockingChestNodeMetadata::serializeBody(std::ostream &os)
296 {
297         os<<serializeString(m_text);
298         m_inventory->serialize(os);
299 }
300 std::string LockingChestNodeMetadata::infoText()
301 {
302         return "Locking Chest";
303 }
304 bool LockingChestNodeMetadata::nodeRemovalDisabled()
305 {
306         /*
307                 Disable removal if chest contains something
308         */
309         InventoryList *list = m_inventory->getList("0");
310         if(list == NULL)
311                 return false;
312         if(list->getUsedSlots() == 0)
313                 return false;
314         return true;
315 }
316 std::string LockingChestNodeMetadata::getInventoryDrawSpecString()
317 {
318         return
319                 "invsize[8,9;]"
320                 "list[current_name;0;0,0;8,4;]"
321                 "list[current_player;main;0,5;8,4;]";
322 }
323
324 /*
325         FurnaceNodeMetadata
326 */
327
328 // Prototype
329 FurnaceNodeMetadata proto_FurnaceNodeMetadata(NULL);
330
331 FurnaceNodeMetadata::FurnaceNodeMetadata(IGameDef *gamedef):
332         NodeMetadata(gamedef)
333 {
334         NodeMetadata::registerType(typeId(), typeName(), create, create);
335         
336         m_inventory = NULL;
337
338         m_infotext = "Furnace is inactive";
339
340         m_step_accumulator = 0;
341         m_fuel_totaltime = 0;
342         m_fuel_time = 0;
343         m_src_totaltime = 0;
344         m_src_time = 0;
345 }
346 FurnaceNodeMetadata::~FurnaceNodeMetadata()
347 {
348         delete m_inventory;
349 }
350 u16 FurnaceNodeMetadata::typeId() const
351 {
352         return NODEMETA_FURNACE;
353 }
354 NodeMetadata* FurnaceNodeMetadata::clone(IGameDef *gamedef)
355 {
356         FurnaceNodeMetadata *d = new FurnaceNodeMetadata(m_gamedef);
357         d->m_inventory = new Inventory(*m_inventory);
358         return d;
359 }
360 NodeMetadata* FurnaceNodeMetadata::create(std::istream &is, IGameDef *gamedef)
361 {
362         FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef);
363
364         d->m_inventory = new Inventory(gamedef->idef());
365         d->m_inventory->deSerialize(is);
366
367         int temp = 0;
368         is>>temp;
369         d->m_fuel_totaltime = (float)temp/10;
370         temp = 0;
371         is>>temp;
372         d->m_fuel_time = (float)temp/10;
373         temp = 0;
374         is>>temp;
375         d->m_src_totaltime = (float)temp/10;
376         temp = 0;
377         is>>temp;
378         d->m_src_time = (float)temp/10;
379
380         if(is.eof())
381         {
382                 // Old furnaces didn't serialize src_totaltime and src_time
383                 d->m_src_totaltime = 0;
384                 d->m_src_time = 0;
385                 d->m_infotext = "";
386         }
387         else
388         {
389                 // New furnaces also serialize the infotext (so that the
390                 // client doesn't need to have the list of cooking recipes).
391                 d->m_infotext = deSerializeJsonString(is);
392         }
393
394         return d;
395 }
396 NodeMetadata* FurnaceNodeMetadata::create(IGameDef *gamedef)
397 {
398         FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef);
399         d->m_inventory = new Inventory(gamedef->idef());
400         d->m_inventory->addList("fuel", 1);
401         d->m_inventory->addList("src", 1);
402         d->m_inventory->addList("dst", 4);
403         return d;
404 }
405 void FurnaceNodeMetadata::serializeBody(std::ostream &os)
406 {
407         m_inventory->serialize(os);
408         os<<itos(m_fuel_totaltime*10)<<" ";
409         os<<itos(m_fuel_time*10)<<" ";
410         os<<itos(m_src_totaltime*10)<<" ";
411         os<<itos(m_src_time*10)<<" ";
412         os<<serializeJsonString(m_infotext);
413 }
414 std::string FurnaceNodeMetadata::infoText()
415 {
416         return m_infotext;
417 }
418 bool FurnaceNodeMetadata::nodeRemovalDisabled()
419 {
420         /*
421                 Disable removal if furnace is not empty
422         */
423         InventoryList *list[3] = {m_inventory->getList("src"),
424         m_inventory->getList("dst"), m_inventory->getList("fuel")};
425         
426         for(int i = 0; i < 3; i++) {
427                 if(list[i] == NULL)
428                         continue;
429                 if(list[i]->getUsedSlots() == 0)
430                         continue;
431                 return true;
432         }
433         return false;
434         
435 }
436 void FurnaceNodeMetadata::inventoryModified()
437 {
438         infostream<<"Furnace inventory modification callback"<<std::endl;
439 }
440 bool FurnaceNodeMetadata::step(float dtime)
441 {
442         if(dtime > 60.0)
443                 infostream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
444
445         InventoryList *dst_list = m_inventory->getList("dst");
446         assert(dst_list);
447
448         // Update at a fixed frequency
449         const float interval = 2.0;
450         m_step_accumulator += dtime;
451         bool changed = false;
452         while(m_step_accumulator > interval)
453         {
454                 m_step_accumulator -= interval;
455                 dtime = interval;
456
457                 //infostream<<"Furnace step dtime="<<dtime<<std::endl;
458
459                 bool changed_this_loop = false;
460
461                 // Check
462                 // 1. if the source item is cookable
463                 // 2. if there is room for the cooked item
464                 std::string cookresult;
465                 float cooktime;
466                 bool cookable = getCookResult(false, cookresult, cooktime);
467                 ItemStack cookresult_item;
468                 bool room_available = false;
469                 if(cookable)
470                 {
471                         cookresult_item.deSerialize(cookresult, m_gamedef->idef());
472                         room_available = dst_list->roomForItem(cookresult_item);
473                 }
474
475                 // Step fuel time
476                 bool burning = (m_fuel_time < m_fuel_totaltime);
477                 if(burning)
478                 {
479                         changed_this_loop = true;
480                         m_fuel_time += dtime;
481                 }
482
483                 std::string infotext;
484                 if(room_available)
485                 {
486                         float burntime;
487                         if(burning)
488                         {
489                                 changed_this_loop = true;
490                                 m_src_time += dtime;
491                                 m_src_totaltime = cooktime;
492                                 infotext = "Furnace is cooking";
493                         }
494                         else if(getBurnResult(true, burntime))
495                         {
496                                 // Fuel inserted
497                                 changed_this_loop = true;
498                                 m_fuel_time = 0;
499                                 m_fuel_totaltime = burntime;
500                                 //m_src_time += dtime;
501                                 //m_src_totaltime = cooktime;
502                                 infotext = "Furnace is cooking";
503                         }
504                         else
505                         {
506                                 m_src_time = 0;
507                                 m_src_totaltime = 0;
508                                 infotext = "Furnace is out of fuel";
509                         }
510                         if(m_src_totaltime > 0.001 && m_src_time >= m_src_totaltime)
511                         {
512                                 // One item fully cooked
513                                 changed_this_loop = true;
514                                 dst_list->addItem(cookresult_item);
515                                 getCookResult(true, cookresult, cooktime); // decrement source
516                                 m_src_totaltime = 0;
517                                 m_src_time = 0;
518                         }
519                 }
520                 else
521                 {
522                         // Not cookable or no room available
523                         m_src_totaltime = 0;
524                         m_src_time = 0;
525                         if(cookable)
526                                 infotext = "Furnace is overloaded";
527                         else if(burning)
528                                 infotext = "Furnace is active";
529                         else
530                         {
531                                 infotext = "Furnace is inactive";
532                                 m_fuel_totaltime = 0;
533                                 m_fuel_time = 0;
534                         }
535                 }
536
537                 // Do this so it doesn't always show (0%) for weak fuel
538                 if(m_fuel_totaltime > 3) {
539                         infotext += " (";
540                         infotext += itos(m_fuel_time/m_fuel_totaltime*100);
541                         infotext += "%)";
542                 }
543
544                 if(infotext != m_infotext)
545                 {
546                         m_infotext = infotext;
547                         changed_this_loop = true;
548                 }
549
550                 if(burning && m_fuel_time >= m_fuel_totaltime)
551                 {
552                         m_fuel_time = 0;
553                         m_fuel_totaltime = 0;
554                 }
555
556                 if(changed_this_loop)
557                 {
558                         changed = true;
559                 }
560                 else
561                 {
562                         m_step_accumulator = 0;
563                         break;
564                 }
565         }
566         return changed;
567 }
568 std::string FurnaceNodeMetadata::getInventoryDrawSpecString()
569 {
570         return
571                 "invsize[8,9;]"
572                 "list[current_name;fuel;2,3;1,1;]"
573                 "list[current_name;src;2,1;1,1;]"
574                 "list[current_name;dst;5,1;2,2;]"
575                 "list[current_player;main;0,5;8,4;]";
576 }
577 bool FurnaceNodeMetadata::getCookResult(bool remove,
578                 std::string &cookresult, float &cooktime)
579 {
580         std::vector<ItemStack> items;
581         InventoryList *src_list = m_inventory->getList("src");
582         assert(src_list);
583         items.push_back(src_list->getItem(0));
584
585         CraftInput ci(CRAFT_METHOD_COOKING, 1, items);
586         CraftOutput co;
587         bool found = m_gamedef->getCraftDefManager()->getCraftResult(
588                         ci, co, remove, m_gamedef);
589         if(remove)
590                 src_list->changeItem(0, ci.items[0]);
591
592         cookresult = co.item;
593         cooktime = co.time;
594         return found;
595 }
596 bool FurnaceNodeMetadata::getBurnResult(bool remove, float &burntime)
597 {
598         std::vector<ItemStack> items;
599         InventoryList *fuel_list = m_inventory->getList("fuel");
600         assert(fuel_list);
601         items.push_back(fuel_list->getItem(0));
602
603         CraftInput ci(CRAFT_METHOD_FUEL, 1, items);
604         CraftOutput co;
605         bool found = m_gamedef->getCraftDefManager()->getCraftResult(
606                         ci, co, remove, m_gamedef);
607         if(remove)
608                 fuel_list->changeItem(0, ci.items[0]);
609
610         burntime = co.time;
611         return found;
612 }
613
614
615 /*
616         GenericNodeMetadata
617 */
618
619 class GenericNodeMetadata : public NodeMetadata
620 {
621 private:
622         Inventory *m_inventory;
623         std::string m_text;
624         std::string m_owner;
625
626         std::string m_infotext;
627         std::string m_inventorydrawspec;
628         bool m_allow_text_input;
629         bool m_removal_disabled;
630         bool m_enforce_owner;
631
632         bool m_inventory_modified;
633         bool m_text_modified;
634
635         std::map<std::string, std::string> m_stringvars;
636
637 public:
638         u16 typeId() const
639         {
640                 return NODEMETA_GENERIC;
641         }
642         const char* typeName() const
643         {
644                 return "generic";
645         }
646
647         GenericNodeMetadata(IGameDef *gamedef):
648                 NodeMetadata(gamedef),
649
650                 m_inventory(NULL),
651                 m_text(""),
652                 m_owner(""),
653
654                 m_infotext("GenericNodeMetadata"),
655                 m_inventorydrawspec(""),
656                 m_allow_text_input(false),
657                 m_removal_disabled(false),
658                 m_enforce_owner(false),
659
660                 m_inventory_modified(false),
661                 m_text_modified(false)
662         {
663                 NodeMetadata::registerType(typeId(), typeName(), create, create);
664         }
665         virtual ~GenericNodeMetadata()
666         {
667                 delete m_inventory;
668         }
669         NodeMetadata* clone(IGameDef *gamedef)
670         {
671                 GenericNodeMetadata *d = new GenericNodeMetadata(m_gamedef);
672
673                 d->m_inventory = new Inventory(*m_inventory);
674                 d->m_text = m_text;
675                 d->m_owner = m_owner;
676
677                 d->m_infotext = m_infotext;
678                 d->m_inventorydrawspec = m_inventorydrawspec;
679                 d->m_allow_text_input = m_allow_text_input;
680                 d->m_removal_disabled = m_removal_disabled;
681                 d->m_enforce_owner = m_enforce_owner;
682                 d->m_inventory_modified = m_inventory_modified;
683                 d->m_text_modified = m_text_modified;
684                 return d;
685         }
686         static NodeMetadata* create(IGameDef *gamedef)
687         {
688                 GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
689                 d->m_inventory = new Inventory(gamedef->idef());
690                 return d;
691         }
692         static NodeMetadata* create(std::istream &is, IGameDef *gamedef)
693         {
694                 GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
695                 
696                 d->m_inventory = new Inventory(gamedef->idef());
697                 d->m_inventory->deSerialize(is);
698                 d->m_text = deSerializeLongString(is);
699                 d->m_owner = deSerializeString(is);
700                 
701                 d->m_infotext = deSerializeString(is);
702                 d->m_inventorydrawspec = deSerializeString(is);
703                 d->m_allow_text_input = readU8(is);
704                 d->m_removal_disabled = readU8(is);
705                 d->m_enforce_owner = readU8(is);
706
707                 int num_vars = readU32(is);
708                 for(int i=0; i<num_vars; i++){
709                         std::string name = deSerializeString(is);
710                         std::string var = deSerializeLongString(is);
711                         d->m_stringvars[name] = var;
712                 }
713
714                 return d;
715         }
716         void serializeBody(std::ostream &os)
717         {
718                 m_inventory->serialize(os);
719                 os<<serializeLongString(m_text);
720                 os<<serializeString(m_owner);
721
722                 os<<serializeString(m_infotext);
723                 os<<serializeString(m_inventorydrawspec);
724                 writeU8(os, m_allow_text_input);
725                 writeU8(os, m_removal_disabled);
726                 writeU8(os, m_enforce_owner);
727
728                 int num_vars = m_stringvars.size();
729                 writeU32(os, num_vars);
730                 for(std::map<std::string, std::string>::iterator
731                                 i = m_stringvars.begin(); i != m_stringvars.end(); i++){
732                         os<<serializeString(i->first);
733                         os<<serializeLongString(i->second);
734                 }
735         }
736
737         std::string infoText()
738         {
739                 return m_infotext;
740         }
741         Inventory* getInventory()
742         {
743                 return m_inventory;
744         }
745         void inventoryModified()
746         {
747                 m_inventory_modified = true;
748         }
749         bool step(float dtime)
750         {
751                 return false;
752         }
753         bool nodeRemovalDisabled()
754         {
755                 return m_removal_disabled;
756         }
757         std::string getInventoryDrawSpecString()
758         {
759                 return m_inventorydrawspec;
760         }
761         bool allowsTextInput()
762         {
763                 return m_allow_text_input;
764         }
765         std::string getText()
766         {
767                 return m_text;
768         }
769         void setText(const std::string &t)
770         {
771                 m_text = t;
772                 m_text_modified = true;
773         }
774         std::string getOwner()
775         {
776                 if(m_enforce_owner)
777                         return m_owner;
778                 else
779                         return "";
780         }
781         void setOwner(std::string t)
782         {
783                 m_owner = t;
784         }
785         
786         /* Interface for GenericNodeMetadata */
787
788         void setInfoText(const std::string &text)
789         {
790                 infostream<<"GenericNodeMetadata::setInfoText(\""
791                                 <<text<<"\")"<<std::endl;
792                 m_infotext = text;
793         }
794         void setInventoryDrawSpec(const std::string &text)
795         {
796                 m_inventorydrawspec = text;
797         }
798         void setAllowTextInput(bool b)
799         {
800                 m_allow_text_input = b;
801         }
802         void setRemovalDisabled(bool b)
803         {
804                 m_removal_disabled = b;
805         }
806         void setEnforceOwner(bool b)
807         {
808                 m_enforce_owner = b;
809         }
810         bool isInventoryModified()
811         {
812                 return m_inventory_modified;
813         }
814         void resetInventoryModified()
815         {
816                 m_inventory_modified = false;
817         }
818         bool isTextModified()
819         {
820                 return m_text_modified;
821         }
822         void resetTextModified()
823         {
824                 m_text_modified = false;
825         }
826         void setString(const std::string &name, const std::string &var)
827         {
828                 m_stringvars[name] = var;
829         }
830         std::string getString(const std::string &name)
831         {
832                 std::map<std::string, std::string>::iterator i;
833                 i = m_stringvars.find(name);
834                 if(i == m_stringvars.end())
835                         return "";
836                 return i->second;
837         }
838 };
839
840 // Prototype
841 GenericNodeMetadata proto_GenericNodeMetadata(NULL);
842