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