]> git.lizzy.rs Git - dragonfireclient.git/blob - src/content_nodemeta.cpp
e79ff6d54c14762772542612f403f8588cdea34b
[dragonfireclient.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 #include "inventory.h"
22 #include "content_mapnode.h"
23
24 /*
25         SignNodeMetadata
26 */
27
28 // Prototype
29 SignNodeMetadata proto_SignNodeMetadata("");
30
31 SignNodeMetadata::SignNodeMetadata(std::string text):
32         m_text(text)
33 {
34         NodeMetadata::registerType(typeId(), create);
35 }
36 u16 SignNodeMetadata::typeId() const
37 {
38         return CONTENT_SIGN_WALL;
39 }
40 NodeMetadata* SignNodeMetadata::create(std::istream &is)
41 {
42         std::string text = deSerializeString(is);
43         return new SignNodeMetadata(text);
44 }
45 NodeMetadata* SignNodeMetadata::clone()
46 {
47         return new SignNodeMetadata(m_text);
48 }
49 void SignNodeMetadata::serializeBody(std::ostream &os)
50 {
51         os<<serializeString(m_text);
52 }
53 std::string SignNodeMetadata::infoText()
54 {
55         return std::string("\"")+m_text+"\"";
56 }
57
58 /*
59         ChestNodeMetadata
60 */
61
62 // Prototype
63 ChestNodeMetadata proto_ChestNodeMetadata;
64
65 ChestNodeMetadata::ChestNodeMetadata()
66 {
67         NodeMetadata::registerType(typeId(), create);
68         
69         m_inventory = new Inventory();
70         m_inventory->addList("0", 8*4);
71 }
72 ChestNodeMetadata::~ChestNodeMetadata()
73 {
74         delete m_inventory;
75 }
76 u16 ChestNodeMetadata::typeId() const
77 {
78         return CONTENT_CHEST;
79 }
80 NodeMetadata* ChestNodeMetadata::create(std::istream &is)
81 {
82         ChestNodeMetadata *d = new ChestNodeMetadata();
83         d->m_inventory->deSerialize(is);
84         return d;
85 }
86 NodeMetadata* ChestNodeMetadata::clone()
87 {
88         ChestNodeMetadata *d = new ChestNodeMetadata();
89         *d->m_inventory = *m_inventory;
90         return d;
91 }
92 void ChestNodeMetadata::serializeBody(std::ostream &os)
93 {
94         m_inventory->serialize(os);
95 }
96 std::string ChestNodeMetadata::infoText()
97 {
98         return "Chest";
99 }
100 bool ChestNodeMetadata::nodeRemovalDisabled()
101 {
102         /*
103                 Disable removal if chest contains something
104         */
105         InventoryList *list = m_inventory->getList("0");
106         if(list == NULL)
107                 return false;
108         if(list->getUsedSlots() == 0)
109                 return false;
110         return true;
111 }
112 std::string ChestNodeMetadata::getInventoryDrawSpecString()
113 {
114         return
115                 "invsize[8,9;]"
116                 "list[current_name;0;0,0;8,4;]"
117                 "list[current_player;main;0,5;8,4;]";
118 }
119
120 /*
121         LockingChestNodeMetadata
122 */
123
124 // Prototype
125 LockingChestNodeMetadata proto_LockingChestNodeMetadata;
126
127 LockingChestNodeMetadata::LockingChestNodeMetadata()
128 {
129         NodeMetadata::registerType(typeId(), create);
130
131         m_inventory = new Inventory();
132         m_inventory->addList("0", 8*4);
133 }
134 LockingChestNodeMetadata::~LockingChestNodeMetadata()
135 {
136         delete m_inventory;
137 }
138 u16 LockingChestNodeMetadata::typeId() const
139 {
140         return CONTENT_LOCKABLE_CHEST;
141 }
142 NodeMetadata* LockingChestNodeMetadata::create(std::istream &is)
143 {
144         LockingChestNodeMetadata *d = new LockingChestNodeMetadata();
145         d->setOwner(deSerializeString(is));
146         d->m_inventory->deSerialize(is);
147         return d;
148 }
149 NodeMetadata* LockingChestNodeMetadata::clone()
150 {
151         LockingChestNodeMetadata *d = new LockingChestNodeMetadata();
152         *d->m_inventory = *m_inventory;
153         return d;
154 }
155 void LockingChestNodeMetadata::serializeBody(std::ostream &os)
156 {
157         os<<serializeString(m_text);
158         m_inventory->serialize(os);
159 }
160 std::string LockingChestNodeMetadata::infoText()
161 {
162         return "Locking Chest";
163 }
164 bool LockingChestNodeMetadata::nodeRemovalDisabled()
165 {
166         /*
167                 Disable removal if chest contains something
168         */
169         InventoryList *list = m_inventory->getList("0");
170         if(list == NULL)
171                 return false;
172         if(list->getUsedSlots() == 0)
173                 return false;
174         return true;
175 }
176 std::string LockingChestNodeMetadata::getInventoryDrawSpecString()
177 {
178         return
179                 "invsize[8,9;]"
180                 "list[current_name;0;0,0;8,4;]"
181                 "list[current_player;main;0,5;8,4;]";
182 }
183
184 /*
185         FurnaceNodeMetadata
186 */
187
188 // Prototype
189 FurnaceNodeMetadata proto_FurnaceNodeMetadata;
190
191 FurnaceNodeMetadata::FurnaceNodeMetadata()
192 {
193         NodeMetadata::registerType(typeId(), create);
194         
195         m_inventory = new Inventory();
196         m_inventory->addList("fuel", 1);
197         m_inventory->addList("src", 1);
198         m_inventory->addList("dst", 4);
199
200         m_step_accumulator = 0;
201         m_fuel_totaltime = 0;
202         m_fuel_time = 0;
203         m_src_totaltime = 0;
204         m_src_time = 0;
205 }
206 FurnaceNodeMetadata::~FurnaceNodeMetadata()
207 {
208         delete m_inventory;
209 }
210 u16 FurnaceNodeMetadata::typeId() const
211 {
212         return CONTENT_FURNACE;
213 }
214 NodeMetadata* FurnaceNodeMetadata::clone()
215 {
216         FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
217         *d->m_inventory = *m_inventory;
218         return d;
219 }
220 NodeMetadata* FurnaceNodeMetadata::create(std::istream &is)
221 {
222         FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
223
224         d->m_inventory->deSerialize(is);
225
226         int temp;
227         is>>temp;
228         d->m_fuel_totaltime = (float)temp/10;
229         is>>temp;
230         d->m_fuel_time = (float)temp/10;
231
232         return d;
233 }
234 void FurnaceNodeMetadata::serializeBody(std::ostream &os)
235 {
236         m_inventory->serialize(os);
237         os<<itos(m_fuel_totaltime*10)<<" ";
238         os<<itos(m_fuel_time*10)<<" ";
239 }
240 std::string FurnaceNodeMetadata::infoText()
241 {
242         //return "Furnace";
243         if(m_fuel_time >= m_fuel_totaltime)
244         {
245                 const InventoryList *src_list = m_inventory->getList("src");
246                 assert(src_list);
247                 const InventoryItem *src_item = src_list->getItem(0);
248
249                 if(src_item && src_item->isCookable()) {
250                         InventoryList *dst_list = m_inventory->getList("dst");
251                         if(!dst_list->roomForCookedItem(src_item))
252                                 return "Furnace is overloaded";
253                         return "Furnace is out of fuel";
254                 }
255                 else
256                         return "Furnace is inactive";
257         }
258         else
259         {
260                 std::string s = "Furnace is active";
261                 // Do this so it doesn't always show (0%) for weak fuel
262                 if(m_fuel_totaltime > 3) {
263                         s += " (";
264                         s += itos(m_fuel_time/m_fuel_totaltime*100);
265                         s += "%)";
266                 }
267                 return s;
268         }
269 }
270 bool FurnaceNodeMetadata::nodeRemovalDisabled()
271 {
272         /*
273                 Disable removal if furnace is not empty
274         */
275         InventoryList *list[3] = {m_inventory->getList("src"),
276         m_inventory->getList("dst"), m_inventory->getList("fuel")};
277         
278         for(int i = 0; i < 3; i++) {
279                 if(list[i] == NULL)
280                         continue;
281                 if(list[i]->getUsedSlots() == 0)
282                         continue;
283                 return true;
284         }
285         return false;
286         
287 }
288 void FurnaceNodeMetadata::inventoryModified()
289 {
290         dstream<<"Furnace inventory modification callback"<<std::endl;
291 }
292 bool FurnaceNodeMetadata::step(float dtime)
293 {
294         if(dtime > 60.0)
295                 dstream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
296         // Update at a fixed frequency
297         const float interval = 2.0;
298         m_step_accumulator += dtime;
299         bool changed = false;
300         while(m_step_accumulator > interval)
301         {
302                 m_step_accumulator -= interval;
303                 dtime = interval;
304
305                 //dstream<<"Furnace step dtime="<<dtime<<std::endl;
306                 
307                 InventoryList *dst_list = m_inventory->getList("dst");
308                 assert(dst_list);
309
310                 InventoryList *src_list = m_inventory->getList("src");
311                 assert(src_list);
312                 InventoryItem *src_item = src_list->getItem(0);
313                 
314                 bool room_available = false;
315                 
316                 if(src_item && src_item->isCookable())
317                         room_available = dst_list->roomForCookedItem(src_item);
318                 
319                 // Start only if there are free slots in dst, so that it can
320                 // accomodate any result item
321                 if(room_available)
322                 {
323                         m_src_totaltime = 3;
324                 }
325                 else
326                 {
327                         m_src_time = 0;
328                         m_src_totaltime = 0;
329                 }
330                 
331                 /*
332                         If fuel is burning, increment the burn counters.
333                         If item finishes cooking, move it to result.
334                 */
335                 if(m_fuel_time < m_fuel_totaltime)
336                 {
337                         //dstream<<"Furnace is active"<<std::endl;
338                         m_fuel_time += dtime;
339                         m_src_time += dtime;
340                         if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
341                                         && src_item)
342                         {
343                                 InventoryItem *cookresult = src_item->createCookResult();
344                                 dst_list->addItem(cookresult);
345                                 src_list->decrementMaterials(1);
346                                 m_src_time = 0;
347                                 m_src_totaltime = 0;
348                         }
349                         changed = true;
350                         
351                         // If the fuel was not used up this step, just keep burning it
352                         if(m_fuel_time < m_fuel_totaltime)
353                                 continue;
354                 }
355                 
356                 /*
357                         Get the source again in case it has all burned
358                 */
359                 src_item = src_list->getItem(0);
360                 
361                 /*
362                         If there is no source item, or the source item is not cookable,
363                         or the furnace is still cooking, or the furnace became overloaded, stop loop.
364                 */
365                 if(src_item == NULL || !room_available || m_fuel_time < m_fuel_totaltime ||
366                         dst_list->roomForCookedItem(src_item) == false)
367                 {
368                         m_step_accumulator = 0;
369                         break;
370                 }
371                 
372                 //dstream<<"Furnace is out of fuel"<<std::endl;
373
374                 InventoryList *fuel_list = m_inventory->getList("fuel");
375                 assert(fuel_list);
376                 const InventoryItem *fuel_item = fuel_list->getItem(0);
377
378                 if(ItemSpec(ITEM_MATERIAL, CONTENT_TREE).checkItem(fuel_item))
379                 {
380                         m_fuel_totaltime = 30;
381                         m_fuel_time = 0;
382                         fuel_list->decrementMaterials(1);
383                         changed = true;
384                 }
385                 else if(ItemSpec(ITEM_MATERIAL, CONTENT_JUNGLETREE).checkItem(fuel_item))
386                 {
387                         m_fuel_totaltime = 30;
388                         m_fuel_time = 0;
389                         fuel_list->decrementMaterials(1);
390                         changed = true;
391                 }
392                 else if(ItemSpec(ITEM_MATERIAL, CONTENT_FENCE).checkItem(fuel_item))
393                 {
394                         m_fuel_totaltime = 30/2;
395                         m_fuel_time = 0;
396                         fuel_list->decrementMaterials(1);
397                         changed = true;
398                 }
399                 else if(ItemSpec(ITEM_MATERIAL, CONTENT_WOOD).checkItem(fuel_item))
400                 {
401                         m_fuel_totaltime = 30/4;
402                         m_fuel_time = 0;
403                         fuel_list->decrementMaterials(1);
404                         changed = true;
405                 }
406                 else if(ItemSpec(ITEM_MATERIAL, CONTENT_BOOKSHELF).checkItem(fuel_item))
407                 {
408                         m_fuel_totaltime = 30/4;
409                         m_fuel_time = 0;
410                         fuel_list->decrementMaterials(1);
411                         changed = true;
412                 }
413                 else if(ItemSpec(ITEM_MATERIAL, CONTENT_LEAVES).checkItem(fuel_item))
414                 {
415                         m_fuel_totaltime = 30/16;
416                         m_fuel_time = 0;
417                         fuel_list->decrementMaterials(1);
418                         changed = true;
419                 }
420                 else if(ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS).checkItem(fuel_item))
421                 {
422                         m_fuel_totaltime = 30/32;
423                         m_fuel_time = 0;
424                         fuel_list->decrementMaterials(1);
425                         changed = true;
426                 }
427                 else if(ItemSpec(ITEM_MATERIAL, CONTENT_JUNGLEGRASS).checkItem(fuel_item))
428                 {
429                         m_fuel_totaltime = 30/32;
430                         m_fuel_time = 0;
431                         fuel_list->decrementMaterials(1);
432                         changed = true;
433                 }
434                 else if(ItemSpec(ITEM_MATERIAL, CONTENT_CACTUS).checkItem(fuel_item))
435                 {
436                         m_fuel_totaltime = 30/4;
437                         m_fuel_time = 0;
438                         fuel_list->decrementMaterials(1);
439                         changed = true;
440                 }
441                 else if(ItemSpec(ITEM_CRAFT, "Stick").checkItem(fuel_item))
442                 {
443                         m_fuel_totaltime = 30/4/4;
444                         m_fuel_time = 0;
445                         fuel_list->decrementMaterials(1);
446                         changed = true;
447                 }
448                 else if(ItemSpec(ITEM_CRAFT, "lump_of_coal").checkItem(fuel_item))
449                 {
450                         m_fuel_totaltime = 40;
451                         m_fuel_time = 0;
452                         fuel_list->decrementMaterials(1);
453                         changed = true;
454                 }
455                 else
456                 {
457                         //dstream<<"No fuel found"<<std::endl;
458                         // No fuel, stop loop.
459                         m_step_accumulator = 0;
460                         break;
461                 }
462         }
463         return changed;
464 }
465 std::string FurnaceNodeMetadata::getInventoryDrawSpecString()
466 {
467         return
468                 "invsize[8,9;]"
469                 "list[current_name;fuel;2,3;1,1;]"
470                 "list[current_name;src;2,1;1,1;]"
471                 "list[current_name;dst;5,1;2,2;]"
472                 "list[current_player;main;0,5;8,4;]";
473 }
474
475