]> git.lizzy.rs Git - minetest.git/blob - src/content_cao.cpp
Random Lua tweaks/fixes
[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 #include "gamedef.h"
27
28 core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
29
30 /*
31         TestCAO
32 */
33
34 // Prototype
35 TestCAO proto_TestCAO(NULL);
36
37 TestCAO::TestCAO(IGameDef *gamedef):
38         ClientActiveObject(0, gamedef),
39         m_node(NULL),
40         m_position(v3f(0,10*BS,0))
41 {
42         ClientActiveObject::registerType(getType(), create);
43 }
44
45 TestCAO::~TestCAO()
46 {
47 }
48
49 ClientActiveObject* TestCAO::create(IGameDef *gamedef)
50 {
51         return new TestCAO(gamedef);
52 }
53
54 void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
55 {
56         if(m_node != NULL)
57                 return;
58         
59         //video::IVideoDriver* driver = smgr->getVideoDriver();
60         
61         scene::SMesh *mesh = new scene::SMesh();
62         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
63         video::SColor c(255,255,255,255);
64         video::S3DVertex vertices[4] =
65         {
66                 video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
67                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
68                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
69                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
70         };
71         u16 indices[] = {0,1,2,2,3,0};
72         buf->append(vertices, 4, indices, 6);
73         // Set material
74         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
75         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
76         buf->getMaterial().setTexture(0, tsrc->getTextureRaw("rat.png"));
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(0, tsrc->getTextureRaw("stick.png"));
199         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
200         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
201         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
202         // Add to mesh
203         mesh->addMeshBuffer(buf);
204         buf->drop();
205         m_node = smgr->addMeshSceneNode(mesh, NULL);
206         mesh->drop();
207         // Set it to use the materials of the meshbuffers directly.
208         // This is needed for changing the texture in the future
209         m_node->setReadOnlyMaterials(true);
210         updateNodePos();
211
212         /*
213                 Update image of node
214         */
215
216         // Create an inventory item to see what is its image
217         std::istringstream is(m_inventorystring, std::ios_base::binary);
218         video::ITexture *texture = NULL;
219         try{
220                 InventoryItem *item = NULL;
221                 item = InventoryItem::deSerialize(is, m_gamedef);
222                 infostream<<__FUNCTION_NAME<<": m_inventorystring=\""
223                                 <<m_inventorystring<<"\" -> item="<<item
224                                 <<std::endl;
225                 if(item)
226                 {
227                         texture = item->getImage();
228                         delete item;
229                 }
230         }
231         catch(SerializationError &e)
232         {
233                 infostream<<"WARNING: "<<__FUNCTION_NAME
234                                 <<": error deSerializing inventorystring \""
235                                 <<m_inventorystring<<"\""<<std::endl;
236         }
237         
238         // Set meshbuffer texture
239         buf->getMaterial().setTexture(0, texture);
240 }
241
242 void ItemCAO::removeFromScene()
243 {
244         if(m_node == NULL)
245                 return;
246
247         m_node->remove();
248         m_node = NULL;
249 }
250
251 void ItemCAO::updateLight(u8 light_at_pos)
252 {
253         if(m_node == NULL)
254                 return;
255
256         u8 li = decode_light(light_at_pos);
257         video::SColor color(255,li,li,li);
258         setMeshVerticesColor(m_node->getMesh(), color);
259 }
260
261 v3s16 ItemCAO::getLightPosition()
262 {
263         return floatToInt(m_position, BS);
264 }
265
266 void ItemCAO::updateNodePos()
267 {
268         if(m_node == NULL)
269                 return;
270
271         m_node->setPosition(m_position);
272 }
273
274 void ItemCAO::step(float dtime, ClientEnvironment *env)
275 {
276         if(m_node)
277         {
278                 /*v3f rot = m_node->getRotation();
279                 rot.Y += dtime * 120;
280                 m_node->setRotation(rot);*/
281                 LocalPlayer *player = env->getLocalPlayer();
282                 assert(player);
283                 v3f rot = m_node->getRotation();
284                 rot.Y = 180.0 - (player->getYaw());
285                 m_node->setRotation(rot);
286         }
287 }
288
289 void ItemCAO::processMessage(const std::string &data)
290 {
291         infostream<<"ItemCAO: Got message"<<std::endl;
292         std::istringstream is(data, std::ios::binary);
293         // command
294         u8 cmd = readU8(is);
295         if(cmd == 0)
296         {
297                 // pos
298                 m_position = readV3F1000(is);
299                 updateNodePos();
300         }
301 }
302
303 void ItemCAO::initialize(const std::string &data)
304 {
305         infostream<<"ItemCAO: Got init data"<<std::endl;
306         
307         {
308                 std::istringstream is(data, std::ios::binary);
309                 // version
310                 u8 version = readU8(is);
311                 // check version
312                 if(version != 0)
313                         return;
314                 // pos
315                 m_position = readV3F1000(is);
316                 // inventorystring
317                 m_inventorystring = deSerializeString(is);
318         }
319         
320         updateNodePos();
321 }
322
323 /*
324         RatCAO
325 */
326
327 #include "inventory.h"
328
329 // Prototype
330 RatCAO proto_RatCAO(NULL);
331
332 RatCAO::RatCAO(IGameDef *gamedef):
333         ClientActiveObject(0, gamedef),
334         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
335         m_node(NULL),
336         m_position(v3f(0,10*BS,0)),
337         m_yaw(0)
338 {
339         ClientActiveObject::registerType(getType(), create);
340 }
341
342 RatCAO::~RatCAO()
343 {
344 }
345
346 ClientActiveObject* RatCAO::create(IGameDef *gamedef)
347 {
348         return new RatCAO(gamedef);
349 }
350
351 void RatCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
352 {
353         if(m_node != NULL)
354                 return;
355         
356         //video::IVideoDriver* driver = smgr->getVideoDriver();
357         
358         scene::SMesh *mesh = new scene::SMesh();
359         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
360         video::SColor c(255,255,255,255);
361         video::S3DVertex vertices[4] =
362         {
363                 video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
364                 video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
365                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
366                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
367         };
368         u16 indices[] = {0,1,2,2,3,0};
369         buf->append(vertices, 4, indices, 6);
370         // Set material
371         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
372         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
373         //buf->getMaterial().setTexture(0, NULL);
374         buf->getMaterial().setTexture(0, tsrc->getTextureRaw("rat.png"));
375         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
376         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
377         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
378         // Add to mesh
379         mesh->addMeshBuffer(buf);
380         buf->drop();
381         m_node = smgr->addMeshSceneNode(mesh, NULL);
382         mesh->drop();
383         // Set it to use the materials of the meshbuffers directly.
384         // This is needed for changing the texture in the future
385         m_node->setReadOnlyMaterials(true);
386         updateNodePos();
387 }
388
389 void RatCAO::removeFromScene()
390 {
391         if(m_node == NULL)
392                 return;
393
394         m_node->remove();
395         m_node = NULL;
396 }
397
398 void RatCAO::updateLight(u8 light_at_pos)
399 {
400         if(m_node == NULL)
401                 return;
402
403         u8 li = decode_light(light_at_pos);
404         video::SColor color(255,li,li,li);
405         setMeshVerticesColor(m_node->getMesh(), color);
406 }
407
408 v3s16 RatCAO::getLightPosition()
409 {
410         return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
411 }
412
413 void RatCAO::updateNodePos()
414 {
415         if(m_node == NULL)
416                 return;
417
418         //m_node->setPosition(m_position);
419         m_node->setPosition(pos_translator.vect_show);
420
421         v3f rot = m_node->getRotation();
422         rot.Y = 180.0 - m_yaw;
423         m_node->setRotation(rot);
424 }
425
426 void RatCAO::step(float dtime, ClientEnvironment *env)
427 {
428         pos_translator.translate(dtime);
429         updateNodePos();
430 }
431
432 void RatCAO::processMessage(const std::string &data)
433 {
434         //infostream<<"RatCAO: Got message"<<std::endl;
435         std::istringstream is(data, std::ios::binary);
436         // command
437         u8 cmd = readU8(is);
438         if(cmd == 0)
439         {
440                 // pos
441                 m_position = readV3F1000(is);
442                 pos_translator.update(m_position);
443                 // yaw
444                 m_yaw = readF1000(is);
445                 updateNodePos();
446         }
447 }
448
449 void RatCAO::initialize(const std::string &data)
450 {
451         //infostream<<"RatCAO: Got init data"<<std::endl;
452         
453         {
454                 std::istringstream is(data, std::ios::binary);
455                 // version
456                 u8 version = readU8(is);
457                 // check version
458                 if(version != 0)
459                         return;
460                 // pos
461                 m_position = readV3F1000(is);
462                 pos_translator.init(m_position);
463         }
464         
465         updateNodePos();
466 }
467
468 /*
469         Oerkki1CAO
470 */
471
472 #include "inventory.h"
473
474 // Prototype
475 Oerkki1CAO proto_Oerkki1CAO(NULL);
476
477 Oerkki1CAO::Oerkki1CAO(IGameDef *gamedef):
478         ClientActiveObject(0, gamedef),
479         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
480         m_node(NULL),
481         m_position(v3f(0,10*BS,0)),
482         m_yaw(0),
483         m_damage_visual_timer(0),
484         m_damage_texture_enabled(false)
485 {
486         ClientActiveObject::registerType(getType(), create);
487 }
488
489 Oerkki1CAO::~Oerkki1CAO()
490 {
491 }
492
493 ClientActiveObject* Oerkki1CAO::create(IGameDef *gamedef)
494 {
495         return new Oerkki1CAO(gamedef);
496 }
497
498 void Oerkki1CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
499 {
500         if(m_node != NULL)
501                 return;
502         
503         //video::IVideoDriver* driver = smgr->getVideoDriver();
504         
505         scene::SMesh *mesh = new scene::SMesh();
506         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
507         video::SColor c(255,255,255,255);
508         video::S3DVertex vertices[4] =
509         {
510                 video::S3DVertex(-BS/2-BS,0,0, 0,0,0, c, 0,1),
511                 video::S3DVertex(BS/2+BS,0,0, 0,0,0, c, 1,1),
512                 video::S3DVertex(BS/2+BS,BS*2,0, 0,0,0, c, 1,0),
513                 video::S3DVertex(-BS/2-BS,BS*2,0, 0,0,0, c, 0,0),
514         };
515         u16 indices[] = {0,1,2,2,3,0};
516         buf->append(vertices, 4, indices, 6);
517         // Set material
518         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
519         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
520         //buf->getMaterial().setTexture(0, NULL);
521         buf->getMaterial().setTexture(0, tsrc->getTextureRaw("oerkki1.png"));
522         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
523         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
524         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
525         // Add to mesh
526         mesh->addMeshBuffer(buf);
527         buf->drop();
528         m_node = smgr->addMeshSceneNode(mesh, NULL);
529         mesh->drop();
530         // Set it to use the materials of the meshbuffers directly.
531         // This is needed for changing the texture in the future
532         m_node->setReadOnlyMaterials(true);
533         updateNodePos();
534 }
535
536 void Oerkki1CAO::removeFromScene()
537 {
538         if(m_node == NULL)
539                 return;
540
541         m_node->remove();
542         m_node = NULL;
543 }
544
545 void Oerkki1CAO::updateLight(u8 light_at_pos)
546 {
547         if(m_node == NULL)
548                 return;
549         
550         if(light_at_pos <= 2)
551         {
552                 m_node->setVisible(false);
553                 return;
554         }
555
556         m_node->setVisible(true);
557
558         u8 li = decode_light(light_at_pos);
559         video::SColor color(255,li,li,li);
560         setMeshVerticesColor(m_node->getMesh(), color);
561 }
562
563 v3s16 Oerkki1CAO::getLightPosition()
564 {
565         return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
566 }
567
568 void Oerkki1CAO::updateNodePos()
569 {
570         if(m_node == NULL)
571                 return;
572
573         //m_node->setPosition(m_position);
574         m_node->setPosition(pos_translator.vect_show);
575
576         v3f rot = m_node->getRotation();
577         rot.Y = 180.0 - m_yaw + 90.0;
578         m_node->setRotation(rot);
579 }
580
581 void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
582 {
583         ITextureSource *tsrc = m_gamedef->tsrc();
584
585         pos_translator.translate(dtime);
586         updateNodePos();
587
588         LocalPlayer *player = env->getLocalPlayer();
589         assert(player);
590         
591         v3f playerpos = player->getPosition();
592         v2f playerpos_2d(playerpos.X,playerpos.Z);
593         v2f objectpos_2d(m_position.X,m_position.Z);
594
595         if(fabs(m_position.Y - playerpos.Y) < 1.5*BS &&
596                         objectpos_2d.getDistanceFrom(playerpos_2d) < 1.5*BS)
597         {
598                 if(m_attack_interval.step(dtime, 0.5))
599                 {
600                         env->damageLocalPlayer(2);
601                 }
602         }
603
604         if(m_damage_visual_timer > 0)
605         {
606                 if(!m_damage_texture_enabled)
607                 {
608                         // Enable damage texture
609                         if(m_node)
610                         {
611                                 /*video::IVideoDriver* driver =
612                                         m_node->getSceneManager()->getVideoDriver();*/
613                                 
614                                 scene::IMesh *mesh = m_node->getMesh();
615                                 if(mesh == NULL)
616                                         return;
617                                 
618                                 u16 mc = mesh->getMeshBufferCount();
619                                 for(u16 j=0; j<mc; j++)
620                                 {
621                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
622                                         buf->getMaterial().setTexture(0,
623                                                         tsrc->getTextureRaw("oerkki1_damaged.png"));
624                                 }
625                         }
626                         m_damage_texture_enabled = true;
627                 }
628                 m_damage_visual_timer -= dtime;
629         }
630         else
631         {
632                 if(m_damage_texture_enabled)
633                 {
634                         // Disable damage texture
635                         if(m_node)
636                         {
637                                 /*video::IVideoDriver* driver =
638                                         m_node->getSceneManager()->getVideoDriver();*/
639                                 
640                                 scene::IMesh *mesh = m_node->getMesh();
641                                 if(mesh == NULL)
642                                         return;
643                                 
644                                 u16 mc = mesh->getMeshBufferCount();
645                                 for(u16 j=0; j<mc; j++)
646                                 {
647                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
648                                         buf->getMaterial().setTexture(0,
649                                                         tsrc->getTextureRaw("oerkki1.png"));
650                                 }
651                         }
652                         m_damage_texture_enabled = false;
653                 }
654         }
655 }
656
657 void Oerkki1CAO::processMessage(const std::string &data)
658 {
659         //infostream<<"Oerkki1CAO: Got message"<<std::endl;
660         std::istringstream is(data, std::ios::binary);
661         // command
662         u8 cmd = readU8(is);
663         if(cmd == 0)
664         {
665                 // pos
666                 m_position = readV3F1000(is);
667                 pos_translator.update(m_position);
668                 // yaw
669                 m_yaw = readF1000(is);
670                 updateNodePos();
671         }
672         else if(cmd == 1)
673         {
674                 //u16 damage = readU8(is);
675                 m_damage_visual_timer = 1.0;
676         }
677 }
678
679 void Oerkki1CAO::initialize(const std::string &data)
680 {
681         //infostream<<"Oerkki1CAO: Got init data"<<std::endl;
682         
683         {
684                 std::istringstream is(data, std::ios::binary);
685                 // version
686                 u8 version = readU8(is);
687                 // check version
688                 if(version != 0)
689                         return;
690                 // pos
691                 m_position = readV3F1000(is);
692                 pos_translator.init(m_position);
693         }
694         
695         updateNodePos();
696 }
697
698 bool Oerkki1CAO::directReportPunch(const std::string &toolname, v3f dir)
699 {
700         m_damage_visual_timer = 1.0;
701
702         m_position += dir * BS;
703         pos_translator.sharpen();
704         pos_translator.update(m_position);
705         updateNodePos();
706         
707         return false;
708 }
709
710 /*
711         FireflyCAO
712 */
713
714 // Prototype
715 FireflyCAO proto_FireflyCAO(NULL);
716
717 FireflyCAO::FireflyCAO(IGameDef *gamedef):
718         ClientActiveObject(0, gamedef),
719         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
720         m_node(NULL),
721         m_position(v3f(0,10*BS,0)),
722         m_yaw(0)
723 {
724         ClientActiveObject::registerType(getType(), create);
725 }
726
727 FireflyCAO::~FireflyCAO()
728 {
729 }
730
731 ClientActiveObject* FireflyCAO::create(IGameDef *gamedef)
732 {
733         return new FireflyCAO(gamedef);
734 }
735
736 void FireflyCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
737 {
738         if(m_node != NULL)
739                 return;
740         
741         //video::IVideoDriver* driver = smgr->getVideoDriver();
742         
743         scene::SMesh *mesh = new scene::SMesh();
744         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
745         video::SColor c(255,255,255,255);
746         video::S3DVertex vertices[4] =
747         {
748                 video::S3DVertex(0,0,0, 0,0,0, c, 0,1),
749                 video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
750                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
751                 video::S3DVertex(0,BS/2,0, 0,0,0, c, 0,0),
752         };
753         u16 indices[] = {0,1,2,2,3,0};
754         buf->append(vertices, 4, indices, 6);
755         // Set material
756         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
757         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
758         //buf->getMaterial().setTexture(0, NULL);
759         buf->getMaterial().setTexture(0, tsrc->getTextureRaw("firefly.png"));
760         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
761         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
762         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
763         // Add to mesh
764         mesh->addMeshBuffer(buf);
765         buf->drop();
766         m_node = smgr->addMeshSceneNode(mesh, NULL);
767         mesh->drop();
768         // Set it to use the materials of the meshbuffers directly.
769         // This is needed for changing the texture in the future
770         m_node->setReadOnlyMaterials(true);
771         updateNodePos();
772 }
773
774 void FireflyCAO::removeFromScene()
775 {
776         if(m_node == NULL)
777                 return;
778
779         m_node->remove();
780         m_node = NULL;
781 }
782
783 void FireflyCAO::updateLight(u8 light_at_pos)
784 {
785         if(m_node == NULL)
786                 return;
787
788         u8 li = 255;
789         video::SColor color(255,li,li,li);
790         setMeshVerticesColor(m_node->getMesh(), color);
791 }
792
793 v3s16 FireflyCAO::getLightPosition()
794 {
795         return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
796 }
797
798 void FireflyCAO::updateNodePos()
799 {
800         if(m_node == NULL)
801                 return;
802
803         //m_node->setPosition(m_position);
804         m_node->setPosition(pos_translator.vect_show);
805
806         v3f rot = m_node->getRotation();
807         rot.Y = 180.0 - m_yaw;
808         m_node->setRotation(rot);
809 }
810
811 void FireflyCAO::step(float dtime, ClientEnvironment *env)
812 {
813         pos_translator.translate(dtime);
814         updateNodePos();
815 }
816
817 void FireflyCAO::processMessage(const std::string &data)
818 {
819         //infostream<<"FireflyCAO: Got message"<<std::endl;
820         std::istringstream is(data, std::ios::binary);
821         // command
822         u8 cmd = readU8(is);
823         if(cmd == 0)
824         {
825                 // pos
826                 m_position = readV3F1000(is);
827                 pos_translator.update(m_position);
828                 // yaw
829                 m_yaw = readF1000(is);
830                 updateNodePos();
831         }
832 }
833
834 void FireflyCAO::initialize(const std::string &data)
835 {
836         //infostream<<"FireflyCAO: Got init data"<<std::endl;
837         
838         {
839                 std::istringstream is(data, std::ios::binary);
840                 // version
841                 u8 version = readU8(is);
842                 // check version
843                 if(version != 0)
844                         return;
845                 // pos
846                 m_position = readV3F1000(is);
847                 pos_translator.init(m_position);
848         }
849         
850         updateNodePos();
851 }
852
853 /*
854         MobV2CAO
855 */
856
857 // Prototype
858 MobV2CAO proto_MobV2CAO(NULL);
859
860 MobV2CAO::MobV2CAO(IGameDef *gamedef):
861         ClientActiveObject(0, gamedef),
862         m_selection_box(-0.4*BS,-0.4*BS,-0.4*BS, 0.4*BS,0.8*BS,0.4*BS),
863         m_node(NULL),
864         m_position(v3f(0,10*BS,0)),
865         m_yaw(0),
866         m_walking(false),
867         m_walking_unset_timer(0),
868         m_walk_timer(0),
869         m_walk_frame(0),
870         m_damage_visual_timer(0),
871         m_last_light(0),
872         m_shooting(0),
873         m_shooting_unset_timer(0),
874         m_sprite_size(BS,BS),
875         m_sprite_y(0),
876         m_bright_shooting(false),
877         m_lock_full_brightness(false),
878         m_player_hit_timer(0)
879 {
880         ClientActiveObject::registerType(getType(), create);
881
882         m_properties = new Settings;
883 }
884
885 MobV2CAO::~MobV2CAO()
886 {
887         delete m_properties;
888 }
889
890 ClientActiveObject* MobV2CAO::create(IGameDef *gamedef)
891 {
892         return new MobV2CAO(gamedef);
893 }
894
895 void MobV2CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)
896 {
897         if(m_node != NULL)
898                 return;
899         
900         /*infostream<<"MobV2CAO::addToScene using texture_name="<<
901                         m_texture_name<<std::endl;*/
902         std::string texture_string = "[makealpha2:128,0,0;128,128,0:";
903         texture_string += m_texture_name;
904         
905         scene::MyBillboardSceneNode *bill = new scene::MyBillboardSceneNode(
906                         smgr->getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1));
907         bill->setMaterialTexture(0, tsrc->getTextureRaw(texture_string));
908         bill->setMaterialFlag(video::EMF_LIGHTING, false);
909         bill->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
910         bill->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
911         bill->setMaterialFlag(video::EMF_FOG_ENABLE, true);
912         bill->setColor(video::SColor(255,0,0,0));
913         bill->setVisible(false); /* Set visible when brightness is known */
914         bill->setSize(m_sprite_size);
915         if(m_sprite_type == "humanoid_1"){
916                 const float txp = 1./192;
917                 const float txs = txp*32;
918                 const float typ = 1./240;
919                 const float tys = typ*48;
920                 bill->setTCoords(0, v2f(txs*1, tys*1));
921                 bill->setTCoords(1, v2f(txs*1, tys*0));
922                 bill->setTCoords(2, v2f(txs*0, tys*0));
923                 bill->setTCoords(3, v2f(txs*0, tys*1));
924         } else if(m_sprite_type == "simple"){
925                 const float txs = 1.0;
926                 const float tys = 1.0 / m_simple_anim_frames;
927                 bill->setTCoords(0, v2f(txs*1, tys*1));
928                 bill->setTCoords(1, v2f(txs*1, tys*0));
929                 bill->setTCoords(2, v2f(txs*0, tys*0));
930                 bill->setTCoords(3, v2f(txs*0, tys*1));
931         } else {
932                 infostream<<"MobV2CAO: Unknown sprite type \""<<m_sprite_type<<"\""
933                                 <<std::endl;
934         }
935
936         m_node = bill;
937
938         updateNodePos();
939 }
940
941 void MobV2CAO::removeFromScene()
942 {
943         if(m_node == NULL)
944                 return;
945
946         m_node->drop();
947         m_node->remove();
948         m_node = NULL;
949 }
950
951 void MobV2CAO::updateLight(u8 light_at_pos)
952 {
953         if(m_lock_full_brightness)
954                 light_at_pos = 15;
955         
956         m_last_light = light_at_pos;
957
958         if(m_node == NULL)
959                 return;
960         
961         if(m_damage_visual_timer > 0)
962                 return;
963         
964         if(m_shooting && m_bright_shooting)
965                 return;
966         
967         /*if(light_at_pos <= 2){
968                 m_node->setVisible(false);
969                 return;
970         }*/
971
972         m_node->setVisible(true);
973
974         u8 li = decode_light(light_at_pos);
975         video::SColor color(255,li,li,li);
976         m_node->setColor(color);
977 }
978
979 v3s16 MobV2CAO::getLightPosition()
980 {
981         return floatToInt(m_position+v3f(0,0,0), BS);
982 }
983
984 void MobV2CAO::updateNodePos()
985 {
986         if(m_node == NULL)
987                 return;
988
989         m_node->setPosition(pos_translator.vect_show + v3f(0,m_sprite_y,0));
990 }
991
992 void MobV2CAO::step(float dtime, ClientEnvironment *env)
993 {
994         scene::MyBillboardSceneNode *bill = m_node;
995         if(!bill)
996                 return;
997
998         pos_translator.translate(dtime);
999         
1000         if(m_sprite_type == "humanoid_1"){
1001                 scene::ICameraSceneNode* camera = m_node->getSceneManager()->getActiveCamera();
1002                 if(!camera)
1003                         return;
1004                 v3f cam_to_mob = m_node->getAbsolutePosition() - camera->getAbsolutePosition();
1005                 cam_to_mob.normalize();
1006                 int col = 0;
1007                 if(cam_to_mob.Y > 0.75)
1008                         col = 5;
1009                 else if(cam_to_mob.Y < -0.75)
1010                         col = 4;
1011                 else{
1012                         float mob_dir = atan2(cam_to_mob.Z, cam_to_mob.X) / PI * 180.;
1013                         float dir = mob_dir - m_yaw;
1014                         dir = wrapDegrees_180(dir);
1015                         //infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
1016                         if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
1017                                 col = 2;
1018                         else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
1019                                 col = 3;
1020                         else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
1021                                 col = 0;
1022                         else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
1023                                 col = 1;
1024                         else
1025                                 col = 4;
1026                 }
1027
1028                 int row = 0;
1029                 if(m_shooting){
1030                         row = 3;
1031                 } else if(m_walking){
1032                         m_walk_timer += dtime;
1033                         if(m_walk_timer >= 0.5){
1034                                 m_walk_frame = (m_walk_frame + 1) % 2;
1035                                 m_walk_timer = 0;
1036                         }
1037                         if(m_walk_frame == 0)
1038                                 row = 1;
1039                         else
1040                                 row = 2;
1041                 }
1042
1043                 const float txp = 1./192;
1044                 const float txs = txp*32;
1045                 const float typ = 1./240;
1046                 const float tys = typ*48;
1047                 bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
1048                 bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
1049                 bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
1050                 bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
1051         } else if(m_sprite_type == "simple"){
1052                 m_walk_timer += dtime;
1053                 if(m_walk_timer >= m_simple_anim_frametime){
1054                         m_walk_frame = (m_walk_frame + 1) % m_simple_anim_frames;
1055                         m_walk_timer = 0;
1056                 }
1057                 int col = 0;
1058                 int row = m_walk_frame;
1059                 const float txs = 1.0;
1060                 const float tys = 1.0 / m_simple_anim_frames;
1061                 bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
1062                 bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
1063                 bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
1064                 bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
1065         } else {
1066                 infostream<<"MobV2CAO::step(): Unknown sprite type \""
1067                                 <<m_sprite_type<<"\""<<std::endl;
1068         }
1069
1070         updateNodePos();
1071
1072         /* Damage local player */
1073         if(m_player_hit_damage && m_player_hit_timer <= 0.0){
1074                 LocalPlayer *player = env->getLocalPlayer();
1075                 assert(player);
1076                 
1077                 v3f playerpos = player->getPosition();
1078                 v2f playerpos_2d(playerpos.X,playerpos.Z);
1079                 v2f objectpos_2d(m_position.X,m_position.Z);
1080
1081                 if(fabs(m_position.Y - playerpos.Y) < m_player_hit_distance*BS &&
1082                 objectpos_2d.getDistanceFrom(playerpos_2d) < m_player_hit_distance*BS)
1083                 {
1084                         env->damageLocalPlayer(m_player_hit_damage);
1085                         m_player_hit_timer = m_player_hit_interval;
1086                 }
1087         }
1088
1089         /* Run timers */
1090
1091         m_player_hit_timer -= dtime;
1092
1093         if(m_damage_visual_timer >= 0){
1094                 m_damage_visual_timer -= dtime;
1095                 if(m_damage_visual_timer <= 0){
1096                         infostream<<"id="<<m_id<<" damage visual ended"<<std::endl;
1097                 }
1098         }
1099
1100         m_walking_unset_timer += dtime;
1101         if(m_walking_unset_timer >= 1.0){
1102                 m_walking = false;
1103         }
1104
1105         m_shooting_unset_timer -= dtime;
1106         if(m_shooting_unset_timer <= 0.0){
1107                 if(m_bright_shooting){
1108                         u8 li = decode_light(m_last_light);
1109                         video::SColor color(255,li,li,li);
1110                         bill->setColor(color);
1111                         m_bright_shooting = false;
1112                 }
1113                 m_shooting = false;
1114         }
1115
1116 }
1117
1118 void MobV2CAO::processMessage(const std::string &data)
1119 {
1120         //infostream<<"MobV2CAO: Got message"<<std::endl;
1121         std::istringstream is(data, std::ios::binary);
1122         // command
1123         u8 cmd = readU8(is);
1124
1125         // Move
1126         if(cmd == 0)
1127         {
1128                 // pos
1129                 m_position = readV3F1000(is);
1130                 pos_translator.update(m_position);
1131                 // yaw
1132                 m_yaw = readF1000(is);
1133
1134                 m_walking = true;
1135                 m_walking_unset_timer = 0;
1136
1137                 updateNodePos();
1138         }
1139         // Damage
1140         else if(cmd == 1)
1141         {
1142                 //u16 damage = readU16(is);
1143
1144                 /*u8 li = decode_light(m_last_light);
1145                 if(li >= 100)
1146                         li = 30;
1147                 else
1148                         li = 255;*/
1149
1150                 /*video::SColor color(255,255,0,0);
1151                 m_node->setColor(color);
1152
1153                 m_damage_visual_timer = 0.2;*/
1154         }
1155         // Trigger shooting
1156         else if(cmd == 2)
1157         {
1158                 // length
1159                 m_shooting_unset_timer = readF1000(is);
1160                 // bright?
1161                 m_bright_shooting = readU8(is);
1162                 if(m_bright_shooting){
1163                         u8 li = 255;
1164                         video::SColor color(255,li,li,li);
1165                         m_node->setColor(color);
1166                 }
1167
1168                 m_shooting = true;
1169         }
1170 }
1171
1172 void MobV2CAO::initialize(const std::string &data)
1173 {
1174         //infostream<<"MobV2CAO: Got init data"<<std::endl;
1175         
1176         {
1177                 std::istringstream is(data, std::ios::binary);
1178                 // version
1179                 u8 version = readU8(is);
1180                 // check version
1181                 if(version != 0){
1182                         infostream<<__FUNCTION_NAME<<": Invalid version"<<std::endl;
1183                         return;
1184                 }
1185                 
1186                 std::ostringstream tmp_os(std::ios::binary);
1187                 decompressZlib(is, tmp_os);
1188                 std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
1189                 m_properties->parseConfigLines(tmp_is, "MobArgsEnd");
1190
1191                 infostream<<"MobV2CAO::initialize(): got properties:"<<std::endl;
1192                 m_properties->writeLines(infostream);
1193                 
1194                 m_properties->setDefault("looks", "dummy_default");
1195                 m_properties->setDefault("yaw", "0");
1196                 m_properties->setDefault("pos", "(0,0,0)");
1197                 m_properties->setDefault("player_hit_damage", "0");
1198                 m_properties->setDefault("player_hit_distance", "1.5");
1199                 m_properties->setDefault("player_hit_interval", "1.5");
1200                 
1201                 setLooks(m_properties->get("looks"));
1202                 m_yaw = m_properties->getFloat("yaw");
1203                 m_position = m_properties->getV3F("pos");
1204                 m_player_hit_damage = m_properties->getS32("player_hit_damage");
1205                 m_player_hit_distance = m_properties->getFloat("player_hit_distance");
1206                 m_player_hit_interval = m_properties->getFloat("player_hit_interval");
1207
1208                 pos_translator.init(m_position);
1209         }
1210         
1211         updateNodePos();
1212 }
1213
1214 bool MobV2CAO::directReportPunch(const std::string &toolname, v3f dir)
1215 {
1216         video::SColor color(255,255,0,0);
1217         m_node->setColor(color);
1218
1219         m_damage_visual_timer = 0.05;
1220
1221         m_position += dir * BS;
1222         pos_translator.sharpen();
1223         pos_translator.update(m_position);
1224         updateNodePos();
1225         
1226         return false;
1227 }
1228
1229 void MobV2CAO::setLooks(const std::string &looks)
1230 {
1231         v2f selection_size = v2f(0.4, 0.4) * BS;
1232         float selection_y = 0 * BS;
1233
1234         if(looks == "dungeon_master"){
1235                 m_texture_name = "dungeon_master.png";
1236                 m_sprite_type = "humanoid_1";
1237                 m_sprite_size = v2f(2, 3) * BS;
1238                 m_sprite_y = 0.85 * BS;
1239                 selection_size = v2f(0.4, 2.6) * BS;
1240                 selection_y = -0.4 * BS;
1241         }
1242         else if(looks == "fireball"){
1243                 m_texture_name = "fireball.png";
1244                 m_sprite_type = "simple";
1245                 m_sprite_size = v2f(1, 1) * BS;
1246                 m_simple_anim_frames = 3;
1247                 m_simple_anim_frametime = 0.1;
1248                 m_lock_full_brightness = true;
1249         }
1250         else{
1251                 m_texture_name = "stone.png";
1252                 m_sprite_type = "simple";
1253                 m_sprite_size = v2f(1, 1) * BS;
1254                 m_simple_anim_frames = 3;
1255                 m_simple_anim_frametime = 0.333;
1256                 selection_size = v2f(0.4, 0.4) * BS;
1257                 selection_y = 0 * BS;
1258         }
1259
1260         m_selection_box = core::aabbox3d<f32>(
1261                         -selection_size.X, selection_y, -selection_size.X,
1262                         selection_size.X, selection_y+selection_size.Y,
1263                         selection_size.X);
1264 }
1265
1266 /*
1267         LuaEntityCAO
1268 */
1269
1270 #include "luaentity_common.h"
1271
1272 // Prototype
1273 LuaEntityCAO proto_LuaEntityCAO(NULL);
1274
1275 LuaEntityCAO::LuaEntityCAO(IGameDef *gamedef):
1276         ClientActiveObject(0, gamedef),
1277         m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
1278         m_meshnode(NULL),
1279         m_spritenode(NULL),
1280         m_position(v3f(0,10*BS,0)),
1281         m_velocity(v3f(0,0,0)),
1282         m_acceleration(v3f(0,0,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         if(m_prop->physical){
1461                 core::aabbox3d<f32> box = m_prop->collisionbox;
1462                 box.MinEdge *= BS;
1463                 box.MaxEdge *= BS;
1464                 collisionMoveResult moveresult;
1465                 f32 pos_max_d = BS*0.25; // Distance per iteration
1466                 v3f p_pos = m_position;
1467                 v3f p_velocity = m_velocity;
1468                 IGameDef *gamedef = env->getGameDef();
1469                 moveresult = collisionMovePrecise(&env->getMap(), gamedef,
1470                                 pos_max_d, box, dtime, p_pos, p_velocity);
1471                 // Apply results
1472                 m_position = p_pos;
1473                 m_velocity = p_velocity;
1474                 
1475                 bool is_end_position = moveresult.collides;
1476                 pos_translator.update(m_position, is_end_position, dtime);
1477                 pos_translator.translate(dtime);
1478                 updateNodePos();
1479
1480                 m_velocity += dtime * m_acceleration;
1481         } else {
1482                 m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
1483                 m_velocity += dtime * m_acceleration;
1484                 pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
1485                 pos_translator.translate(dtime);
1486                 updateNodePos();
1487         }
1488 }
1489
1490 void LuaEntityCAO::processMessage(const std::string &data)
1491 {
1492         infostream<<"LuaEntityCAO: Got message"<<std::endl;
1493         std::istringstream is(data, std::ios::binary);
1494         // command
1495         u8 cmd = readU8(is);
1496         if(cmd == 0)
1497         {
1498                 // do_interpolate
1499                 bool do_interpolate = readU8(is);
1500                 // pos
1501                 m_position = readV3F1000(is);
1502                 // velocity
1503                 m_velocity = readV3F1000(is);
1504                 // acceleration
1505                 m_acceleration = readV3F1000(is);
1506                 // yaw
1507                 m_yaw = readF1000(is);
1508                 // is_end_position (for interpolation)
1509                 bool is_end_position = readU8(is);
1510                 // update_interval
1511                 float update_interval = readF1000(is);
1512                 
1513                 if(do_interpolate){
1514                         if(!m_prop->physical)
1515                                 pos_translator.update(m_position, is_end_position, update_interval);
1516                 } else {
1517                         pos_translator.init(m_position);
1518                 }
1519                 updateNodePos();
1520         }
1521 }
1522
1523 void LuaEntityCAO::initialize(const std::string &data)
1524 {
1525         infostream<<"LuaEntityCAO: Got init data"<<std::endl;
1526         
1527         std::istringstream is(data, std::ios::binary);
1528         // version
1529         u8 version = readU8(is);
1530         // check version
1531         if(version != 0)
1532                 return;
1533         // pos
1534         m_position = readV3F1000(is);
1535         // yaw
1536         m_yaw = readF1000(is);
1537         // properties
1538         std::istringstream prop_is(deSerializeLongString(is), std::ios::binary);
1539         m_prop->deSerialize(prop_is);
1540
1541         infostream<<"m_prop: "<<m_prop->dump()<<std::endl;
1542
1543         m_selection_box = m_prop->collisionbox;
1544         m_selection_box.MinEdge *= BS;
1545         m_selection_box.MaxEdge *= BS;
1546                 
1547         pos_translator.init(m_position);
1548         
1549         updateNodePos();
1550 }
1551
1552