]> git.lizzy.rs Git - minetest.git/blob - src/content_cao.cpp
bd99787c072ff98b504c4f182e1d7533c4456475
[minetest.git] / src / content_cao.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_cao.h"
21 #include "tile.h"
22 #include "environment.h"
23 #include "settings.h"
24 #include <ICameraSceneNode.h>
25 #include "serialization.h" // For decompressZlib
26
27 core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
28
29 /*
30         TestCAO
31 */
32
33 // Prototype
34 TestCAO proto_TestCAO(NULL);
35
36 TestCAO::TestCAO(IGameDef *gamedef):
37         ClientActiveObject(0, gamedef),
38         m_node(NULL),
39         m_position(v3f(0,10*BS,0))
40 {
41         ClientActiveObject::registerType(getType(), create);
42 }
43
44 TestCAO::~TestCAO()
45 {
46 }
47
48 ClientActiveObject* TestCAO::create(IGameDef *gamedef)
49 {
50         return new TestCAO(gamedef);
51 }
52
53 void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
54 {
55         if(m_node != NULL)
56                 return;
57         
58         video::IVideoDriver* driver = smgr->getVideoDriver();
59         
60         scene::SMesh *mesh = new scene::SMesh();
61         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
62         video::SColor c(255,255,255,255);
63         video::S3DVertex vertices[4] =
64         {
65                 video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
66                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
67                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
68                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
69         };
70         u16 indices[] = {0,1,2,2,3,0};
71         buf->append(vertices, 4, indices, 6);
72         // Set material
73         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
74         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
75         buf->getMaterial().setTexture
76                         (0, driver->getTexture(getTexturePath("rat.png").c_str()));
77         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
78         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
79         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
80         // Add to mesh
81         mesh->addMeshBuffer(buf);
82         buf->drop();
83         m_node = smgr->addMeshSceneNode(mesh, NULL);
84         mesh->drop();
85         updateNodePos();
86 }
87
88 void TestCAO::removeFromScene()
89 {
90         if(m_node == NULL)
91                 return;
92
93         m_node->remove();
94         m_node = NULL;
95 }
96
97 void TestCAO::updateLight(u8 light_at_pos)
98 {
99 }
100
101 v3s16 TestCAO::getLightPosition()
102 {
103         return floatToInt(m_position, BS);
104 }
105
106 void TestCAO::updateNodePos()
107 {
108         if(m_node == NULL)
109                 return;
110
111         m_node->setPosition(m_position);
112         //m_node->setRotation(v3f(0, 45, 0));
113 }
114
115 void TestCAO::step(float dtime, ClientEnvironment *env)
116 {
117         if(m_node)
118         {
119                 v3f rot = m_node->getRotation();
120                 //infostream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
121                 rot.Y += dtime * 180;
122                 m_node->setRotation(rot);
123         }
124 }
125
126 void TestCAO::processMessage(const std::string &data)
127 {
128         infostream<<"TestCAO: Got data: "<<data<<std::endl;
129         std::istringstream is(data, std::ios::binary);
130         u16 cmd;
131         is>>cmd;
132         if(cmd == 0)
133         {
134                 v3f newpos;
135                 is>>newpos.X;
136                 is>>newpos.Y;
137                 is>>newpos.Z;
138                 m_position = newpos;
139                 updateNodePos();
140         }
141 }
142
143 /*
144         ItemCAO
145 */
146
147 #include "inventory.h"
148
149 // Prototype
150 ItemCAO proto_ItemCAO(NULL);
151
152 ItemCAO::ItemCAO(IGameDef *gamedef):
153         ClientActiveObject(0, gamedef),
154         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
155         m_node(NULL),
156         m_position(v3f(0,10*BS,0))
157 {
158         ClientActiveObject::registerType(getType(), create);
159 }
160
161 ItemCAO::~ItemCAO()
162 {
163 }
164
165 ClientActiveObject* ItemCAO::create(IGameDef *gamedef)
166 {
167         return new ItemCAO(gamedef);
168 }
169
170 void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
171 {
172         if(m_node != NULL)
173                 return;
174         
175         video::IVideoDriver* driver = smgr->getVideoDriver();
176         
177         scene::SMesh *mesh = new scene::SMesh();
178         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
179         video::SColor c(255,255,255,255);
180         video::S3DVertex vertices[4] =
181         {
182                 /*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
183                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
184                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
185                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
186                 video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1),
187                 video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1),
188                 video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0),
189                 video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0),
190         };
191         u16 indices[] = {0,1,2,2,3,0};
192         buf->append(vertices, 4, indices, 6);
193         // Set material
194         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
195         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
196         //buf->getMaterial().setTexture(0, NULL);
197         // Initialize with the stick texture
198         buf->getMaterial().setTexture
199                         (0, driver->getTexture(getTexturePath("stick.png").c_str()));
200         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
201         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
202         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
203         // Add to mesh
204         mesh->addMeshBuffer(buf);
205         buf->drop();
206         m_node = smgr->addMeshSceneNode(mesh, NULL);
207         mesh->drop();
208         // Set it to use the materials of the meshbuffers directly.
209         // This is needed for changing the texture in the future
210         m_node->setReadOnlyMaterials(true);
211         updateNodePos();
212
213         /*
214                 Update image of node
215         */
216
217         // Create an inventory item to see what is its image
218         std::istringstream is(m_inventorystring, std::ios_base::binary);
219         video::ITexture *texture = NULL;
220         try{
221                 InventoryItem *item = NULL;
222                 item = InventoryItem::deSerialize(is, m_gamedef);
223                 infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
224                                 <<m_inventorystring<<"\" -> item="<<item
225                                 <<std::endl;
226                 if(item)
227                 {
228                         texture = item->getImage(tsrc);
229                         delete item;
230                 }
231         }
232         catch(SerializationError &e)
233         {
234                 infostream<<"WARNING: "<<__FUNCTION_NAME
235                                 <<": error deSerializing inventorystring \""
236                                 <<m_inventorystring<<"\""<<std::endl;
237         }
238         
239         // Set meshbuffer texture
240         buf->getMaterial().setTexture(0, texture);
241 }
242
243 void ItemCAO::removeFromScene()
244 {
245         if(m_node == NULL)
246                 return;
247
248         m_node->remove();
249         m_node = NULL;
250 }
251
252 void ItemCAO::updateLight(u8 light_at_pos)
253 {
254         if(m_node == NULL)
255                 return;
256
257         u8 li = decode_light(light_at_pos);
258         video::SColor color(255,li,li,li);
259         setMeshVerticesColor(m_node->getMesh(), color);
260 }
261
262 v3s16 ItemCAO::getLightPosition()
263 {
264         return floatToInt(m_position, BS);
265 }
266
267 void ItemCAO::updateNodePos()
268 {
269         if(m_node == NULL)
270                 return;
271
272         m_node->setPosition(m_position);
273 }
274
275 void ItemCAO::step(float dtime, ClientEnvironment *env)
276 {
277         if(m_node)
278         {
279                 /*v3f rot = m_node->getRotation();
280                 rot.Y += dtime * 120;
281                 m_node->setRotation(rot);*/
282                 LocalPlayer *player = env->getLocalPlayer();
283                 assert(player);
284                 v3f rot = m_node->getRotation();
285                 rot.Y = 180.0 - (player->getYaw());
286                 m_node->setRotation(rot);
287         }
288 }
289
290 void ItemCAO::processMessage(const std::string &data)
291 {
292         infostream<<"ItemCAO: Got message"<<std::endl;
293         std::istringstream is(data, std::ios::binary);
294         // command
295         u8 cmd = readU8(is);
296         if(cmd == 0)
297         {
298                 // pos
299                 m_position = readV3F1000(is);
300                 updateNodePos();
301         }
302 }
303
304 void ItemCAO::initialize(const std::string &data)
305 {
306         infostream<<"ItemCAO: Got init data"<<std::endl;
307         
308         {
309                 std::istringstream is(data, std::ios::binary);
310                 // version
311                 u8 version = readU8(is);
312                 // check version
313                 if(version != 0)
314                         return;
315                 // pos
316                 m_position = readV3F1000(is);
317                 // inventorystring
318                 m_inventorystring = deSerializeString(is);
319         }
320         
321         updateNodePos();
322 }
323
324 /*
325         RatCAO
326 */
327
328 #include "inventory.h"
329
330 // Prototype
331 RatCAO proto_RatCAO(NULL);
332
333 RatCAO::RatCAO(IGameDef *gamedef):
334         ClientActiveObject(0, gamedef),
335         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
336         m_node(NULL),
337         m_position(v3f(0,10*BS,0)),
338         m_yaw(0)
339 {
340         ClientActiveObject::registerType(getType(), create);
341 }
342
343 RatCAO::~RatCAO()
344 {
345 }
346
347 ClientActiveObject* RatCAO::create(IGameDef *gamedef)
348 {
349         return new RatCAO(gamedef);
350 }
351
352 void RatCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
353 {
354         if(m_node != NULL)
355                 return;
356         
357         video::IVideoDriver* driver = smgr->getVideoDriver();
358         
359         scene::SMesh *mesh = new scene::SMesh();
360         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
361         video::SColor c(255,255,255,255);
362         video::S3DVertex vertices[4] =
363         {
364                 video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
365                 video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
366                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
367                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
368         };
369         u16 indices[] = {0,1,2,2,3,0};
370         buf->append(vertices, 4, indices, 6);
371         // Set material
372         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
373         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
374         //buf->getMaterial().setTexture(0, NULL);
375         buf->getMaterial().setTexture
376                         (0, driver->getTexture(getTexturePath("rat.png").c_str()));
377         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
378         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
379         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
380         // Add to mesh
381         mesh->addMeshBuffer(buf);
382         buf->drop();
383         m_node = smgr->addMeshSceneNode(mesh, NULL);
384         mesh->drop();
385         // Set it to use the materials of the meshbuffers directly.
386         // This is needed for changing the texture in the future
387         m_node->setReadOnlyMaterials(true);
388         updateNodePos();
389 }
390
391 void RatCAO::removeFromScene()
392 {
393         if(m_node == NULL)
394                 return;
395
396         m_node->remove();
397         m_node = NULL;
398 }
399
400 void RatCAO::updateLight(u8 light_at_pos)
401 {
402         if(m_node == NULL)
403                 return;
404
405         u8 li = decode_light(light_at_pos);
406         video::SColor color(255,li,li,li);
407         setMeshVerticesColor(m_node->getMesh(), color);
408 }
409
410 v3s16 RatCAO::getLightPosition()
411 {
412         return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
413 }
414
415 void RatCAO::updateNodePos()
416 {
417         if(m_node == NULL)
418                 return;
419
420         //m_node->setPosition(m_position);
421         m_node->setPosition(pos_translator.vect_show);
422
423         v3f rot = m_node->getRotation();
424         rot.Y = 180.0 - m_yaw;
425         m_node->setRotation(rot);
426 }
427
428 void RatCAO::step(float dtime, ClientEnvironment *env)
429 {
430         pos_translator.translate(dtime);
431         updateNodePos();
432 }
433
434 void RatCAO::processMessage(const std::string &data)
435 {
436         //infostream<<"RatCAO: Got message"<<std::endl;
437         std::istringstream is(data, std::ios::binary);
438         // command
439         u8 cmd = readU8(is);
440         if(cmd == 0)
441         {
442                 // pos
443                 m_position = readV3F1000(is);
444                 pos_translator.update(m_position);
445                 // yaw
446                 m_yaw = readF1000(is);
447                 updateNodePos();
448         }
449 }
450
451 void RatCAO::initialize(const std::string &data)
452 {
453         //infostream<<"RatCAO: Got init data"<<std::endl;
454         
455         {
456                 std::istringstream is(data, std::ios::binary);
457                 // version
458                 u8 version = readU8(is);
459                 // check version
460                 if(version != 0)
461                         return;
462                 // pos
463                 m_position = readV3F1000(is);
464                 pos_translator.init(m_position);
465         }
466         
467         updateNodePos();
468 }
469
470 /*
471         Oerkki1CAO
472 */
473
474 #include "inventory.h"
475
476 // Prototype
477 Oerkki1CAO proto_Oerkki1CAO(NULL);
478
479 Oerkki1CAO::Oerkki1CAO(IGameDef *gamedef):
480         ClientActiveObject(0, gamedef),
481         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
482         m_node(NULL),
483         m_position(v3f(0,10*BS,0)),
484         m_yaw(0),
485         m_damage_visual_timer(0),
486         m_damage_texture_enabled(false)
487 {
488         ClientActiveObject::registerType(getType(), create);
489 }
490
491 Oerkki1CAO::~Oerkki1CAO()
492 {
493 }
494
495 ClientActiveObject* Oerkki1CAO::create(IGameDef *gamedef)
496 {
497         return new Oerkki1CAO(gamedef);
498 }
499
500 void Oerkki1CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
501 {
502         if(m_node != NULL)
503                 return;
504         
505         video::IVideoDriver* driver = smgr->getVideoDriver();
506         
507         scene::SMesh *mesh = new scene::SMesh();
508         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
509         video::SColor c(255,255,255,255);
510         video::S3DVertex vertices[4] =
511         {
512                 video::S3DVertex(-BS/2-BS,0,0, 0,0,0, c, 0,1),
513                 video::S3DVertex(BS/2+BS,0,0, 0,0,0, c, 1,1),
514                 video::S3DVertex(BS/2+BS,BS*2,0, 0,0,0, c, 1,0),
515                 video::S3DVertex(-BS/2-BS,BS*2,0, 0,0,0, c, 0,0),
516         };
517         u16 indices[] = {0,1,2,2,3,0};
518         buf->append(vertices, 4, indices, 6);
519         // Set material
520         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
521         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
522         //buf->getMaterial().setTexture(0, NULL);
523         buf->getMaterial().setTexture
524                         (0, driver->getTexture(getTexturePath("oerkki1.png").c_str()));
525         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
526         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
527         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
528         // Add to mesh
529         mesh->addMeshBuffer(buf);
530         buf->drop();
531         m_node = smgr->addMeshSceneNode(mesh, NULL);
532         mesh->drop();
533         // Set it to use the materials of the meshbuffers directly.
534         // This is needed for changing the texture in the future
535         m_node->setReadOnlyMaterials(true);
536         updateNodePos();
537 }
538
539 void Oerkki1CAO::removeFromScene()
540 {
541         if(m_node == NULL)
542                 return;
543
544         m_node->remove();
545         m_node = NULL;
546 }
547
548 void Oerkki1CAO::updateLight(u8 light_at_pos)
549 {
550         if(m_node == NULL)
551                 return;
552         
553         if(light_at_pos <= 2)
554         {
555                 m_node->setVisible(false);
556                 return;
557         }
558
559         m_node->setVisible(true);
560
561         u8 li = decode_light(light_at_pos);
562         video::SColor color(255,li,li,li);
563         setMeshVerticesColor(m_node->getMesh(), color);
564 }
565
566 v3s16 Oerkki1CAO::getLightPosition()
567 {
568         return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
569 }
570
571 void Oerkki1CAO::updateNodePos()
572 {
573         if(m_node == NULL)
574                 return;
575
576         //m_node->setPosition(m_position);
577         m_node->setPosition(pos_translator.vect_show);
578
579         v3f rot = m_node->getRotation();
580         rot.Y = 180.0 - m_yaw + 90.0;
581         m_node->setRotation(rot);
582 }
583
584 void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
585 {
586         pos_translator.translate(dtime);
587         updateNodePos();
588
589         LocalPlayer *player = env->getLocalPlayer();
590         assert(player);
591         
592         v3f playerpos = player->getPosition();
593         v2f playerpos_2d(playerpos.X,playerpos.Z);
594         v2f objectpos_2d(m_position.X,m_position.Z);
595
596         if(fabs(m_position.Y - playerpos.Y) < 1.5*BS &&
597                         objectpos_2d.getDistanceFrom(playerpos_2d) < 1.5*BS)
598         {
599                 if(m_attack_interval.step(dtime, 0.5))
600                 {
601                         env->damageLocalPlayer(2);
602                 }
603         }
604
605         if(m_damage_visual_timer > 0)
606         {
607                 if(!m_damage_texture_enabled)
608                 {
609                         // Enable damage texture
610                         if(m_node)
611                         {
612                                 video::IVideoDriver* driver =
613                                         m_node->getSceneManager()->getVideoDriver();
614                                 
615                                 scene::IMesh *mesh = m_node->getMesh();
616                                 if(mesh == NULL)
617                                         return;
618                                 
619                                 u16 mc = mesh->getMeshBufferCount();
620                                 for(u16 j=0; j<mc; j++)
621                                 {
622                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
623                                         buf->getMaterial().setTexture(0, driver->getTexture(
624                                                         getTexturePath("oerkki1_damaged.png").c_str()));
625                                 }
626                         }
627                         m_damage_texture_enabled = true;
628                 }
629                 m_damage_visual_timer -= dtime;
630         }
631         else
632         {
633                 if(m_damage_texture_enabled)
634                 {
635                         // Disable damage texture
636                         if(m_node)
637                         {
638                                 video::IVideoDriver* driver =
639                                         m_node->getSceneManager()->getVideoDriver();
640                                 
641                                 scene::IMesh *mesh = m_node->getMesh();
642                                 if(mesh == NULL)
643                                         return;
644                                 
645                                 u16 mc = mesh->getMeshBufferCount();
646                                 for(u16 j=0; j<mc; j++)
647                                 {
648                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
649                                         buf->getMaterial().setTexture(0, driver->getTexture(
650                                                         getTexturePath("oerkki1.png").c_str()));
651                                 }
652                         }
653                         m_damage_texture_enabled = false;
654                 }
655         }
656 }
657
658 void Oerkki1CAO::processMessage(const std::string &data)
659 {
660         //infostream<<"Oerkki1CAO: Got message"<<std::endl;
661         std::istringstream is(data, std::ios::binary);
662         // command
663         u8 cmd = readU8(is);
664         if(cmd == 0)
665         {
666                 // pos
667                 m_position = readV3F1000(is);
668                 pos_translator.update(m_position);
669                 // yaw
670                 m_yaw = readF1000(is);
671                 updateNodePos();
672         }
673         else if(cmd == 1)
674         {
675                 //u16 damage = readU8(is);
676                 m_damage_visual_timer = 1.0;
677         }
678 }
679
680 void Oerkki1CAO::initialize(const std::string &data)
681 {
682         //infostream<<"Oerkki1CAO: Got init data"<<std::endl;
683         
684         {
685                 std::istringstream is(data, std::ios::binary);
686                 // version
687                 u8 version = readU8(is);
688                 // check version
689                 if(version != 0)
690                         return;
691                 // pos
692                 m_position = readV3F1000(is);
693                 pos_translator.init(m_position);
694         }
695         
696         updateNodePos();
697 }
698
699 bool Oerkki1CAO::directReportPunch(const std::string &toolname, v3f dir)
700 {
701         m_damage_visual_timer = 1.0;
702
703         m_position += dir * BS;
704         pos_translator.sharpen();
705         pos_translator.update(m_position);
706         updateNodePos();
707         
708         return false;
709 }
710
711 /*
712         FireflyCAO
713 */
714
715 // Prototype
716 FireflyCAO proto_FireflyCAO(NULL);
717
718 FireflyCAO::FireflyCAO(IGameDef *gamedef):
719         ClientActiveObject(0, gamedef),
720         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
721         m_node(NULL),
722         m_position(v3f(0,10*BS,0)),
723         m_yaw(0)
724 {
725         ClientActiveObject::registerType(getType(), create);
726 }
727
728 FireflyCAO::~FireflyCAO()
729 {
730 }
731
732 ClientActiveObject* FireflyCAO::create(IGameDef *gamedef)
733 {
734         return new FireflyCAO(gamedef);
735 }
736
737 void FireflyCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
738 {
739         if(m_node != NULL)
740                 return;
741         
742         video::IVideoDriver* driver = smgr->getVideoDriver();
743         
744         scene::SMesh *mesh = new scene::SMesh();
745         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
746         video::SColor c(255,255,255,255);
747         video::S3DVertex vertices[4] =
748         {
749                 video::S3DVertex(0,0,0, 0,0,0, c, 0,1),
750                 video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
751                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
752                 video::S3DVertex(0,BS/2,0, 0,0,0, c, 0,0),
753         };
754         u16 indices[] = {0,1,2,2,3,0};
755         buf->append(vertices, 4, indices, 6);
756         // Set material
757         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
758         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
759         //buf->getMaterial().setTexture(0, NULL);
760         buf->getMaterial().setTexture
761                         (0, driver->getTexture(getTexturePath("firefly.png").c_str()));
762         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
763         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
764         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
765         // Add to mesh
766         mesh->addMeshBuffer(buf);
767         buf->drop();
768         m_node = smgr->addMeshSceneNode(mesh, NULL);
769         mesh->drop();
770         // Set it to use the materials of the meshbuffers directly.
771         // This is needed for changing the texture in the future
772         m_node->setReadOnlyMaterials(true);
773         updateNodePos();
774 }
775
776 void FireflyCAO::removeFromScene()
777 {
778         if(m_node == NULL)
779                 return;
780
781         m_node->remove();
782         m_node = NULL;
783 }
784
785 void FireflyCAO::updateLight(u8 light_at_pos)
786 {
787         if(m_node == NULL)
788                 return;
789
790         u8 li = 255;
791         video::SColor color(255,li,li,li);
792         setMeshVerticesColor(m_node->getMesh(), color);
793 }
794
795 v3s16 FireflyCAO::getLightPosition()
796 {
797         return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
798 }
799
800 void FireflyCAO::updateNodePos()
801 {
802         if(m_node == NULL)
803                 return;
804
805         //m_node->setPosition(m_position);
806         m_node->setPosition(pos_translator.vect_show);
807
808         v3f rot = m_node->getRotation();
809         rot.Y = 180.0 - m_yaw;
810         m_node->setRotation(rot);
811 }
812
813 void FireflyCAO::step(float dtime, ClientEnvironment *env)
814 {
815         pos_translator.translate(dtime);
816         updateNodePos();
817 }
818
819 void FireflyCAO::processMessage(const std::string &data)
820 {
821         //infostream<<"FireflyCAO: Got message"<<std::endl;
822         std::istringstream is(data, std::ios::binary);
823         // command
824         u8 cmd = readU8(is);
825         if(cmd == 0)
826         {
827                 // pos
828                 m_position = readV3F1000(is);
829                 pos_translator.update(m_position);
830                 // yaw
831                 m_yaw = readF1000(is);
832                 updateNodePos();
833         }
834 }
835
836 void FireflyCAO::initialize(const std::string &data)
837 {
838         //infostream<<"FireflyCAO: Got init data"<<std::endl;
839         
840         {
841                 std::istringstream is(data, std::ios::binary);
842                 // version
843                 u8 version = readU8(is);
844                 // check version
845                 if(version != 0)
846                         return;
847                 // pos
848                 m_position = readV3F1000(is);
849                 pos_translator.init(m_position);
850         }
851         
852         updateNodePos();
853 }
854
855 /*
856         MobV2CAO
857 */
858
859 // Prototype
860 MobV2CAO proto_MobV2CAO(NULL);
861
862 MobV2CAO::MobV2CAO(IGameDef *gamedef):
863         ClientActiveObject(0, gamedef),
864         m_selection_box(-0.4*BS,-0.4*BS,-0.4*BS, 0.4*BS,0.8*BS,0.4*BS),
865         m_node(NULL),
866         m_position(v3f(0,10*BS,0)),
867         m_yaw(0),
868         m_walking(false),
869         m_walking_unset_timer(0),
870         m_walk_timer(0),
871         m_walk_frame(0),
872         m_damage_visual_timer(0),
873         m_last_light(0),
874         m_shooting(0),
875         m_shooting_unset_timer(0),
876         m_sprite_size(BS,BS),
877         m_sprite_y(0),
878         m_bright_shooting(false),
879         m_lock_full_brightness(false),
880         m_player_hit_timer(0)
881 {
882         ClientActiveObject::registerType(getType(), create);
883
884         m_properties = new Settings;
885 }
886
887 MobV2CAO::~MobV2CAO()
888 {
889         delete m_properties;
890 }
891
892 ClientActiveObject* MobV2CAO::create(IGameDef *gamedef)
893 {
894         return new MobV2CAO(gamedef);
895 }
896
897 void MobV2CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
898 {
899         if(m_node != NULL)
900                 return;
901         
902         /*infostream<<"MobV2CAO::addToScene using texture_name="<<
903                         m_texture_name<<std::endl;*/
904         std::string texture_string = "[makealpha2:128,0,0;128,128,0:";
905         texture_string += m_texture_name;
906         
907         scene::MyBillboardSceneNode *bill = new scene::MyBillboardSceneNode(
908                         smgr->getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1));
909         bill->setMaterialTexture(0, tsrc->getTextureRaw(texture_string));
910         bill->setMaterialFlag(video::EMF_LIGHTING, false);
911         bill->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
912         bill->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
913         bill->setMaterialFlag(video::EMF_FOG_ENABLE, true);
914         bill->setColor(video::SColor(255,0,0,0));
915         bill->setVisible(false); /* Set visible when brightness is known */
916         bill->setSize(m_sprite_size);
917         if(m_sprite_type == "humanoid_1"){
918                 const float txp = 1./192;
919                 const float txs = txp*32;
920                 const float typ = 1./240;
921                 const float tys = typ*48;
922                 bill->setTCoords(0, v2f(txs*1, tys*1));
923                 bill->setTCoords(1, v2f(txs*1, tys*0));
924                 bill->setTCoords(2, v2f(txs*0, tys*0));
925                 bill->setTCoords(3, v2f(txs*0, tys*1));
926         } else if(m_sprite_type == "simple"){
927                 const float txs = 1.0;
928                 const float tys = 1.0 / m_simple_anim_frames;
929                 bill->setTCoords(0, v2f(txs*1, tys*1));
930                 bill->setTCoords(1, v2f(txs*1, tys*0));
931                 bill->setTCoords(2, v2f(txs*0, tys*0));
932                 bill->setTCoords(3, v2f(txs*0, tys*1));
933         } else {
934                 infostream<<"MobV2CAO: Unknown sprite type \""<<m_sprite_type<<"\""
935                                 <<std::endl;
936         }
937
938         m_node = bill;
939
940         updateNodePos();
941 }
942
943 void MobV2CAO::removeFromScene()
944 {
945         if(m_node == NULL)
946                 return;
947
948         m_node->drop();
949         m_node->remove();
950         m_node = NULL;
951 }
952
953 void MobV2CAO::updateLight(u8 light_at_pos)
954 {
955         if(m_lock_full_brightness)
956                 light_at_pos = 15;
957         
958         m_last_light = light_at_pos;
959
960         if(m_node == NULL)
961                 return;
962         
963         if(m_damage_visual_timer > 0)
964                 return;
965         
966         if(m_shooting && m_bright_shooting)
967                 return;
968         
969         /*if(light_at_pos <= 2){
970                 m_node->setVisible(false);
971                 return;
972         }*/
973
974         m_node->setVisible(true);
975
976         u8 li = decode_light(light_at_pos);
977         video::SColor color(255,li,li,li);
978         m_node->setColor(color);
979 }
980
981 v3s16 MobV2CAO::getLightPosition()
982 {
983         return floatToInt(m_position+v3f(0,0,0), BS);
984 }
985
986 void MobV2CAO::updateNodePos()
987 {
988         if(m_node == NULL)
989                 return;
990
991         m_node->setPosition(pos_translator.vect_show + v3f(0,m_sprite_y,0));
992 }
993
994 void MobV2CAO::step(float dtime, ClientEnvironment *env)
995 {
996         scene::MyBillboardSceneNode *bill = m_node;
997         if(!bill)
998                 return;
999
1000         pos_translator.translate(dtime);
1001         
1002         if(m_sprite_type == "humanoid_1"){
1003                 scene::ICameraSceneNode* camera = m_node->getSceneManager()->getActiveCamera();
1004                 if(!camera)
1005                         return;
1006                 v3f cam_to_mob = m_node->getAbsolutePosition() - camera->getAbsolutePosition();
1007                 cam_to_mob.normalize();
1008                 int col = 0;
1009                 if(cam_to_mob.Y > 0.75)
1010                         col = 5;
1011                 else if(cam_to_mob.Y < -0.75)
1012                         col = 4;
1013                 else{
1014                         float mob_dir = atan2(cam_to_mob.Z, cam_to_mob.X) / PI * 180.;
1015                         float dir = mob_dir - m_yaw;
1016                         dir = wrapDegrees_180(dir);
1017                         //infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
1018                         if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
1019                                 col = 2;
1020                         else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
1021                                 col = 3;
1022                         else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
1023                                 col = 0;
1024                         else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
1025                                 col = 1;
1026                         else
1027                                 col = 4;
1028                 }
1029
1030                 int row = 0;
1031                 if(m_shooting){
1032                         row = 3;
1033                 } else if(m_walking){
1034                         m_walk_timer += dtime;
1035                         if(m_walk_timer >= 0.5){
1036                                 m_walk_frame = (m_walk_frame + 1) % 2;
1037                                 m_walk_timer = 0;
1038                         }
1039                         if(m_walk_frame == 0)
1040                                 row = 1;
1041                         else
1042                                 row = 2;
1043                 }
1044
1045                 const float txp = 1./192;
1046                 const float txs = txp*32;
1047                 const float typ = 1./240;
1048                 const float tys = typ*48;
1049                 bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
1050                 bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
1051                 bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
1052                 bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
1053         } else if(m_sprite_type == "simple"){
1054                 m_walk_timer += dtime;
1055                 if(m_walk_timer >= m_simple_anim_frametime){
1056                         m_walk_frame = (m_walk_frame + 1) % m_simple_anim_frames;
1057                         m_walk_timer = 0;
1058                 }
1059                 int col = 0;
1060                 int row = m_walk_frame;
1061                 const float txs = 1.0;
1062                 const float tys = 1.0 / m_simple_anim_frames;
1063                 bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
1064                 bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
1065                 bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
1066                 bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
1067         } else {
1068                 infostream<<"MobV2CAO::step(): Unknown sprite type \""
1069                                 <<m_sprite_type<<"\""<<std::endl;
1070         }
1071
1072         updateNodePos();
1073
1074         /* Damage local player */
1075         if(m_player_hit_damage && m_player_hit_timer <= 0.0){
1076                 LocalPlayer *player = env->getLocalPlayer();
1077                 assert(player);
1078                 
1079                 v3f playerpos = player->getPosition();
1080                 v2f playerpos_2d(playerpos.X,playerpos.Z);
1081                 v2f objectpos_2d(m_position.X,m_position.Z);
1082
1083                 if(fabs(m_position.Y - playerpos.Y) < m_player_hit_distance*BS &&
1084                 objectpos_2d.getDistanceFrom(playerpos_2d) < m_player_hit_distance*BS)
1085                 {
1086                         env->damageLocalPlayer(m_player_hit_damage);
1087                         m_player_hit_timer = m_player_hit_interval;
1088                 }
1089         }
1090
1091         /* Run timers */
1092
1093         m_player_hit_timer -= dtime;
1094
1095         if(m_damage_visual_timer >= 0){
1096                 m_damage_visual_timer -= dtime;
1097                 if(m_damage_visual_timer <= 0){
1098                         infostream<<"id="<<m_id<<" damage visual ended"<<std::endl;
1099                 }
1100         }
1101
1102         m_walking_unset_timer += dtime;
1103         if(m_walking_unset_timer >= 1.0){
1104                 m_walking = false;
1105         }
1106
1107         m_shooting_unset_timer -= dtime;
1108         if(m_shooting_unset_timer <= 0.0){
1109                 if(m_bright_shooting){
1110                         u8 li = decode_light(m_last_light);
1111                         video::SColor color(255,li,li,li);
1112                         bill->setColor(color);
1113                         m_bright_shooting = false;
1114                 }
1115                 m_shooting = false;
1116         }
1117
1118 }
1119
1120 void MobV2CAO::processMessage(const std::string &data)
1121 {
1122         //infostream<<"MobV2CAO: Got message"<<std::endl;
1123         std::istringstream is(data, std::ios::binary);
1124         // command
1125         u8 cmd = readU8(is);
1126
1127         // Move
1128         if(cmd == 0)
1129         {
1130                 // pos
1131                 m_position = readV3F1000(is);
1132                 pos_translator.update(m_position);
1133                 // yaw
1134                 m_yaw = readF1000(is);
1135
1136                 m_walking = true;
1137                 m_walking_unset_timer = 0;
1138
1139                 updateNodePos();
1140         }
1141         // Damage
1142         else if(cmd == 1)
1143         {
1144                 //u16 damage = readU16(is);
1145
1146                 /*u8 li = decode_light(m_last_light);
1147                 if(li >= 100)
1148                         li = 30;
1149                 else
1150                         li = 255;*/
1151
1152                 /*video::SColor color(255,255,0,0);
1153                 m_node->setColor(color);
1154
1155                 m_damage_visual_timer = 0.2;*/
1156         }
1157         // Trigger shooting
1158         else if(cmd == 2)
1159         {
1160                 // length
1161                 m_shooting_unset_timer = readF1000(is);
1162                 // bright?
1163                 m_bright_shooting = readU8(is);
1164                 if(m_bright_shooting){
1165                         u8 li = 255;
1166                         video::SColor color(255,li,li,li);
1167                         m_node->setColor(color);
1168                 }
1169
1170                 m_shooting = true;
1171         }
1172 }
1173
1174 void MobV2CAO::initialize(const std::string &data)
1175 {
1176         //infostream<<"MobV2CAO: Got init data"<<std::endl;
1177         
1178         {
1179                 std::istringstream is(data, std::ios::binary);
1180                 // version
1181                 u8 version = readU8(is);
1182                 // check version
1183                 if(version != 0){
1184                         infostream<<__FUNCTION_NAME<<": Invalid version"<<std::endl;
1185                         return;
1186                 }
1187                 
1188                 std::ostringstream tmp_os(std::ios::binary);
1189                 decompressZlib(is, tmp_os);
1190                 std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
1191                 m_properties->parseConfigLines(tmp_is, "MobArgsEnd");
1192
1193                 infostream<<"MobV2CAO::initialize(): got properties:"<<std::endl;
1194                 m_properties->writeLines(infostream);
1195                 
1196                 m_properties->setDefault("looks", "dummy_default");
1197                 m_properties->setDefault("yaw", "0");
1198                 m_properties->setDefault("pos", "(0,0,0)");
1199                 m_properties->setDefault("player_hit_damage", "0");
1200                 m_properties->setDefault("player_hit_distance", "1.5");
1201                 m_properties->setDefault("player_hit_interval", "1.5");
1202                 
1203                 setLooks(m_properties->get("looks"));
1204                 m_yaw = m_properties->getFloat("yaw");
1205                 m_position = m_properties->getV3F("pos");
1206                 m_player_hit_damage = m_properties->getS32("player_hit_damage");
1207                 m_player_hit_distance = m_properties->getFloat("player_hit_distance");
1208                 m_player_hit_interval = m_properties->getFloat("player_hit_interval");
1209
1210                 pos_translator.init(m_position);
1211         }
1212         
1213         updateNodePos();
1214 }
1215
1216 bool MobV2CAO::directReportPunch(const std::string &toolname, v3f dir)
1217 {
1218         video::SColor color(255,255,0,0);
1219         m_node->setColor(color);
1220
1221         m_damage_visual_timer = 0.05;
1222
1223         m_position += dir * BS;
1224         pos_translator.sharpen();
1225         pos_translator.update(m_position);
1226         updateNodePos();
1227         
1228         return false;
1229 }
1230
1231 void MobV2CAO::setLooks(const std::string &looks)
1232 {
1233         v2f selection_size = v2f(0.4, 0.4) * BS;
1234         float selection_y = 0 * BS;
1235
1236         if(looks == "dungeon_master"){
1237                 m_texture_name = "dungeon_master.png";
1238                 m_sprite_type = "humanoid_1";
1239                 m_sprite_size = v2f(2, 3) * BS;
1240                 m_sprite_y = 0.85 * BS;
1241                 selection_size = v2f(0.4, 2.6) * BS;
1242                 selection_y = -0.4 * BS;
1243         }
1244         else if(looks == "fireball"){
1245                 m_texture_name = "fireball.png";
1246                 m_sprite_type = "simple";
1247                 m_sprite_size = v2f(1, 1) * BS;
1248                 m_simple_anim_frames = 3;
1249                 m_simple_anim_frametime = 0.1;
1250                 m_lock_full_brightness = true;
1251         }
1252         else{
1253                 m_texture_name = "stone.png";
1254                 m_sprite_type = "simple";
1255                 m_sprite_size = v2f(1, 1) * BS;
1256                 m_simple_anim_frames = 3;
1257                 m_simple_anim_frametime = 0.333;
1258                 selection_size = v2f(0.4, 0.4) * BS;
1259                 selection_y = 0 * BS;
1260         }
1261
1262         m_selection_box = core::aabbox3d<f32>(
1263                         -selection_size.X, selection_y, -selection_size.X,
1264                         selection_size.X, selection_y+selection_size.Y,
1265                         selection_size.X);
1266 }
1267
1268 /*
1269         LuaEntityCAO
1270 */
1271
1272 #include "luaentity_common.h"
1273
1274 // Prototype
1275 LuaEntityCAO proto_LuaEntityCAO(NULL);
1276
1277 LuaEntityCAO::LuaEntityCAO(IGameDef *gamedef):
1278         ClientActiveObject(0, gamedef),
1279         m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
1280         m_meshnode(NULL),
1281         m_spritenode(NULL),
1282         m_position(v3f(0,10*BS,0)),
1283         m_yaw(0),
1284         m_prop(new LuaEntityProperties)
1285 {
1286         ClientActiveObject::registerType(getType(), create);
1287 }
1288
1289 LuaEntityCAO::~LuaEntityCAO()
1290 {
1291         delete m_prop;
1292 }
1293
1294 ClientActiveObject* LuaEntityCAO::create(IGameDef *gamedef)
1295 {
1296         return new LuaEntityCAO(gamedef);
1297 }
1298
1299 void LuaEntityCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
1300 {
1301         if(m_meshnode != NULL || m_spritenode != NULL)
1302                 return;
1303         
1304         //video::IVideoDriver* driver = smgr->getVideoDriver();
1305
1306         if(m_prop->visual == "single_sprite"){
1307                 infostream<<"LuaEntityCAO::addToScene(): single_sprite"<<std::endl;
1308                 m_spritenode = new scene::MyBillboardSceneNode(
1309                                 smgr->getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1));
1310                 std::string texturestring = "unknown_block.png";
1311                 if(m_prop->textures.size() >= 1)
1312                         texturestring = m_prop->textures[0];
1313                 m_spritenode->setMaterialTexture(0,
1314                                 tsrc->getTextureRaw(texturestring));
1315                 m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
1316                 m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
1317                 m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
1318                 m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
1319                 m_spritenode->setColor(video::SColor(255,0,0,0));
1320                 m_spritenode->setVisible(false); /* Set visible when brightness is known */
1321                 m_spritenode->setSize(v2f(1,1)*1.0*BS);
1322                 {
1323                         const float txs = 1.0 / 1;
1324                         const float tys = 1.0 / 1;
1325                         m_spritenode->setTCoords(0, v2f(txs*1, tys*1));
1326                         m_spritenode->setTCoords(1, v2f(txs*1, tys*0));
1327                         m_spritenode->setTCoords(2, v2f(txs*0, tys*0));
1328                         m_spritenode->setTCoords(3, v2f(txs*0, tys*1));
1329                 }
1330         } else if(m_prop->visual == "cube"){
1331                 infostream<<"LuaEntityCAO::addToScene(): cube"<<std::endl;
1332                 video::SColor c(255,255,255,255);
1333                 video::S3DVertex vertices[24] =
1334                 {
1335                         // Up
1336                         video::S3DVertex(-0.5,+0.5,-0.5, 0,1,0, c, 0,1),
1337                         video::S3DVertex(-0.5,+0.5,+0.5, 0,1,0, c, 0,0),
1338                         video::S3DVertex(+0.5,+0.5,+0.5, 0,1,0, c, 1,0),
1339                         video::S3DVertex(+0.5,+0.5,-0.5, 0,1,0, c, 1,1),
1340                         // Down
1341                         video::S3DVertex(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0),
1342                         video::S3DVertex(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0),
1343                         video::S3DVertex(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1),
1344                         video::S3DVertex(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1),
1345                         // Right
1346                         video::S3DVertex(+0.5,-0.5,-0.5, 1,0,0, c, 0,1),
1347                         video::S3DVertex(+0.5,+0.5,-0.5, 1,0,0, c, 0,0),
1348                         video::S3DVertex(+0.5,+0.5,+0.5, 1,0,0, c, 1,0),
1349                         video::S3DVertex(+0.5,-0.5,+0.5, 1,0,0, c, 1,1),
1350                         // Left
1351                         video::S3DVertex(-0.5,-0.5,-0.5, -1,0,0, c, 1,1),
1352                         video::S3DVertex(-0.5,-0.5,+0.5, -1,0,0, c, 0,1),
1353                         video::S3DVertex(-0.5,+0.5,+0.5, -1,0,0, c, 0,0),
1354                         video::S3DVertex(-0.5,+0.5,-0.5, -1,0,0, c, 1,0),
1355                         // Back
1356                         video::S3DVertex(-0.5,-0.5,+0.5, 0,0,1, c, 1,1),
1357                         video::S3DVertex(+0.5,-0.5,+0.5, 0,0,1, c, 0,1),
1358                         video::S3DVertex(+0.5,+0.5,+0.5, 0,0,1, c, 0,0),
1359                         video::S3DVertex(-0.5,+0.5,+0.5, 0,0,1, c, 1,0),
1360                         // Front
1361                         video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
1362                         video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
1363                         video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
1364                         video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
1365                 };
1366                 
1367                 for(u32 i=0; i<24; ++i){
1368                         vertices[i].Pos *= BS;
1369                 }
1370
1371                 u16 indices[6] = {0,1,2,2,3,0};
1372
1373                 scene::SMesh* mesh = new scene::SMesh();
1374                 for (u32 i=0; i<6; ++i)
1375                 {
1376                         scene::IMeshBuffer* buf = new scene::SMeshBuffer();
1377                         buf->append(vertices + 4 * i, 4, indices, 6);
1378                         buf->recalculateBoundingBox();
1379                         mesh->addMeshBuffer(buf);
1380                         buf->drop();
1381                 }
1382                 mesh->recalculateBoundingBox();
1383         
1384                 m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
1385                 
1386                 m_meshnode->setMesh(mesh);
1387                 m_meshnode->setScale(v3f(1));
1388                 for (u32 i = 0; i < 6; ++i)
1389                 {
1390                         std::string texturestring = "unknown_block.png";
1391                         if(m_prop->textures.size() > i)
1392                                 texturestring = m_prop->textures[i];
1393                         AtlasPointer ap = tsrc->getTexture(texturestring);
1394
1395                         // Get the tile texture and atlas transformation
1396                         video::ITexture* atlas = ap.atlas;
1397                         v2f pos = ap.pos;
1398                         v2f size = ap.size;
1399
1400                         // Set material flags and texture
1401                         video::SMaterial& material = m_meshnode->getMaterial(i);
1402                         material.setFlag(video::EMF_LIGHTING, false);
1403                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1404                         material.setTexture(0, atlas);
1405                         material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
1406                         material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
1407                 }
1408                 // Will be shown when we know the brightness
1409                 m_meshnode->setVisible(false);
1410         } else {
1411                 infostream<<"LuaEntityCAO::addToScene(): \""<<m_prop->visual
1412                                 <<"\" not supported"<<std::endl;
1413         }
1414         updateNodePos();
1415 }
1416
1417 void LuaEntityCAO::removeFromScene()
1418 {
1419         if(m_meshnode){
1420                 m_meshnode->remove();
1421                 m_meshnode = NULL;
1422         }
1423         if(m_spritenode){
1424                 m_spritenode->remove();
1425                 m_spritenode = NULL;
1426         }
1427 }
1428
1429 void LuaEntityCAO::updateLight(u8 light_at_pos)
1430 {
1431         u8 li = decode_light(light_at_pos);
1432         video::SColor color(255,li,li,li);
1433         if(m_meshnode){
1434                 setMeshVerticesColor(m_meshnode->getMesh(), color);
1435                 m_meshnode->setVisible(true);
1436         }
1437         if(m_spritenode){
1438                 m_spritenode->setColor(color);
1439                 m_spritenode->setVisible(true);
1440         }
1441 }
1442
1443 v3s16 LuaEntityCAO::getLightPosition()
1444 {
1445         return floatToInt(m_position, BS);
1446 }
1447
1448 void LuaEntityCAO::updateNodePos()
1449 {
1450         if(m_meshnode){
1451                 m_meshnode->setPosition(pos_translator.vect_show);
1452         }
1453         if(m_spritenode){
1454                 m_spritenode->setPosition(pos_translator.vect_show);
1455         }
1456 }
1457
1458 void LuaEntityCAO::step(float dtime, ClientEnvironment *env)
1459 {
1460         pos_translator.translate(dtime);
1461         updateNodePos();
1462 }
1463
1464 void LuaEntityCAO::processMessage(const std::string &data)
1465 {
1466         infostream<<"LuaEntityCAO: Got message"<<std::endl;
1467         std::istringstream is(data, std::ios::binary);
1468         // command
1469         u8 cmd = readU8(is);
1470         if(cmd == 0)
1471         {
1472                 // do_interpolate
1473                 bool do_interpolate = readU8(is);
1474                 // pos
1475                 m_position = readV3F1000(is);
1476                 // yaw
1477                 m_yaw = readF1000(is);
1478                 // is_end_position (for interpolation)
1479                 bool is_end_position = readU8(is);
1480                 // update_interval
1481                 float update_interval = readF1000(is);
1482                 
1483                 if(do_interpolate)
1484                         pos_translator.update(m_position, is_end_position, update_interval);
1485                 else
1486                         pos_translator.init(m_position);
1487                 updateNodePos();
1488         }
1489 }
1490
1491 void LuaEntityCAO::initialize(const std::string &data)
1492 {
1493         infostream<<"LuaEntityCAO: Got init data"<<std::endl;
1494         
1495         std::istringstream is(data, std::ios::binary);
1496         // version
1497         u8 version = readU8(is);
1498         // check version
1499         if(version != 0)
1500                 return;
1501         // pos
1502         m_position = readV3F1000(is);
1503         // yaw
1504         m_yaw = readF1000(is);
1505         // properties
1506         std::istringstream prop_is(deSerializeLongString(is), std::ios::binary);
1507         m_prop->deSerialize(prop_is);
1508
1509         infostream<<"m_prop: "<<m_prop->dump()<<std::endl;
1510
1511         m_selection_box = m_prop->collisionbox;
1512         m_selection_box.MinEdge *= BS;
1513         m_selection_box.MaxEdge *= BS;
1514                 
1515         pos_translator.init(m_position);
1516         
1517         updateNodePos();
1518 }
1519
1520