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