mobv2
[oweals/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) < 3.0*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 /*
713         FireflyCAO
714 */
715
716 // Prototype
717 FireflyCAO proto_FireflyCAO;
718
719 FireflyCAO::FireflyCAO():
720         ClientActiveObject(0),
721         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
722         m_node(NULL),
723         m_position(v3f(0,10*BS,0)),
724         m_yaw(0)
725 {
726         ClientActiveObject::registerType(getType(), create);
727 }
728
729 FireflyCAO::~FireflyCAO()
730 {
731 }
732
733 ClientActiveObject* FireflyCAO::create()
734 {
735         return new FireflyCAO();
736 }
737
738 void FireflyCAO::addToScene(scene::ISceneManager *smgr)
739 {
740         if(m_node != NULL)
741                 return;
742         
743         video::IVideoDriver* driver = smgr->getVideoDriver();
744         
745         scene::SMesh *mesh = new scene::SMesh();
746         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
747         video::SColor c(255,255,255,255);
748         video::S3DVertex vertices[4] =
749         {
750                 video::S3DVertex(0,0,0, 0,0,0, c, 0,1),
751                 video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
752                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
753                 video::S3DVertex(0,BS/2,0, 0,0,0, c, 0,0),
754         };
755         u16 indices[] = {0,1,2,2,3,0};
756         buf->append(vertices, 4, indices, 6);
757         // Set material
758         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
759         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
760         //buf->getMaterial().setTexture(0, NULL);
761         buf->getMaterial().setTexture
762                         (0, driver->getTexture(getTexturePath("firefly.png").c_str()));
763         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
764         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
765         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
766         // Add to mesh
767         mesh->addMeshBuffer(buf);
768         buf->drop();
769         m_node = smgr->addMeshSceneNode(mesh, NULL);
770         mesh->drop();
771         // Set it to use the materials of the meshbuffers directly.
772         // This is needed for changing the texture in the future
773         m_node->setReadOnlyMaterials(true);
774         updateNodePos();
775 }
776
777 void FireflyCAO::removeFromScene()
778 {
779         if(m_node == NULL)
780                 return;
781
782         m_node->remove();
783         m_node = NULL;
784 }
785
786 void FireflyCAO::updateLight(u8 light_at_pos)
787 {
788         if(m_node == NULL)
789                 return;
790
791         u8 li = 255;
792         video::SColor color(255,li,li,li);
793         setMeshVerticesColor(m_node->getMesh(), color);
794 }
795
796 v3s16 FireflyCAO::getLightPosition()
797 {
798         return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
799 }
800
801 void FireflyCAO::updateNodePos()
802 {
803         if(m_node == NULL)
804                 return;
805
806         //m_node->setPosition(m_position);
807         m_node->setPosition(pos_translator.vect_show);
808
809         v3f rot = m_node->getRotation();
810         rot.Y = 180.0 - m_yaw;
811         m_node->setRotation(rot);
812 }
813
814 void FireflyCAO::step(float dtime, ClientEnvironment *env)
815 {
816         pos_translator.translate(dtime);
817         updateNodePos();
818 }
819
820 void FireflyCAO::processMessage(const std::string &data)
821 {
822         //dstream<<"FireflyCAO: Got message"<<std::endl;
823         std::istringstream is(data, std::ios::binary);
824         // command
825         u8 cmd = readU8(is);
826         if(cmd == 0)
827         {
828                 // pos
829                 m_position = readV3F1000(is);
830                 pos_translator.update(m_position);
831                 // yaw
832                 m_yaw = readF1000(is);
833                 updateNodePos();
834         }
835 }
836
837 void FireflyCAO::initialize(const std::string &data)
838 {
839         //dstream<<"FireflyCAO: Got init data"<<std::endl;
840         
841         {
842                 std::istringstream is(data, std::ios::binary);
843                 // version
844                 u8 version = readU8(is);
845                 // check version
846                 if(version != 0)
847                         return;
848                 // pos
849                 m_position = readV3F1000(is);
850                 pos_translator.init(m_position);
851         }
852         
853         updateNodePos();
854 }
855
856 /*
857         MobV2CAO
858 */
859
860 // Prototype
861 MobV2CAO proto_MobV2CAO;
862
863 MobV2CAO::MobV2CAO():
864         ClientActiveObject(0),
865         m_selection_box(-0.4*BS,-0.4*BS,-0.4*BS, 0.4*BS,0.8*BS,0.4*BS),
866         m_node(NULL),
867         m_position(v3f(0,10*BS,0)),
868         m_yaw(0),
869         m_walking(false),
870         m_walking_unset_timer(0),
871         m_walk_timer(0),
872         m_walk_frame(0),
873         m_damage_visual_timer(0),
874         m_last_light(0),
875         m_shooting(0),
876         m_shooting_unset_timer(0),
877         m_bright_shooting(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()
891 {
892         return new MobV2CAO();
893 }
894
895 void MobV2CAO::addToScene(scene::ISceneManager *smgr)
896 {
897         if(m_node != NULL)
898                 return;
899         
900         std::string texture_name = m_properties->get("texture_name");
901         //dstream<<"MobV2CAO::addToScene using texture_name="<<texture_name<<std::endl;
902         std::string texture_string = "[makealpha2:128,0,0;128,128,0:";
903         texture_string += 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, g_texturesource->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                 dstream<<"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 + m_sprite_pos);
990 }
991
992 void MobV2CAO::step(float dtime, ClientEnvironment *env)
993 {
994         scene::MyBillboardSceneNode *bill = m_node;
995
996         pos_translator.translate(dtime);
997         
998         if(m_sprite_type == "humanoid_1"){
999                 scene::ICameraSceneNode* camera = m_node->getSceneManager()->getActiveCamera();
1000                 v3f cam_to_mob = m_node->getAbsolutePosition() - camera->getAbsolutePosition();
1001                 cam_to_mob.normalize();
1002                 int col = 0;
1003                 if(cam_to_mob.Y > 0.7)
1004                         col = 5;
1005                 else if(cam_to_mob.Y < -0.7)
1006                         col = 4;
1007                 else{
1008                         float mob_dir = atan2(cam_to_mob.Z, cam_to_mob.X) / M_PI * 180.;
1009                         float dir = mob_dir - m_yaw;
1010                         dir = wrapDegrees_180(dir);
1011                         //dstream<<"id="<<m_id<<" dir="<<dir<<std::endl;
1012                         if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
1013                                 col = 2;
1014                         else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
1015                                 col = 3;
1016                         else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
1017                                 col = 0;
1018                         else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
1019                                 col = 1;
1020                         else
1021                                 col = 4;
1022                 }
1023
1024                 int row = 0;
1025                 if(m_shooting){
1026                         row = 3;
1027                 } else if(m_walking){
1028                         m_walk_timer += dtime;
1029                         if(m_walk_timer >= 0.5){
1030                                 m_walk_frame = (m_walk_frame + 1) % 2;
1031                                 m_walk_timer = 0;
1032                         }
1033                         if(m_walk_frame == 0)
1034                                 row = 1;
1035                         else
1036                                 row = 2;
1037                 }
1038
1039                 const float txp = 1./192;
1040                 const float txs = txp*32;
1041                 const float typ = 1./240;
1042                 const float tys = typ*48;
1043                 bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
1044                 bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
1045                 bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
1046                 bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
1047         } else if(m_sprite_type == "simple"){
1048                 m_walk_timer += dtime;
1049                 if(m_walk_timer >= m_simple_anim_frametime){
1050                         m_walk_frame = (m_walk_frame + 1) % m_simple_anim_frames;
1051                         m_walk_timer = 0;
1052                 }
1053                 int col = 0;
1054                 int row = m_walk_frame;
1055                 const float txs = 1.0;
1056                 const float tys = 1.0 / m_simple_anim_frames;
1057                 bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
1058                 bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
1059                 bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
1060                 bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
1061         } else {
1062                 dstream<<"MobV2CAO::step(): Unknown sprite type \""
1063                                 <<m_sprite_type<<"\""<<std::endl;
1064         }
1065
1066         updateNodePos();
1067
1068         /* Damage local player */
1069         if(m_player_hit_damage && m_player_hit_timer <= 0.0){
1070                 LocalPlayer *player = env->getLocalPlayer();
1071                 assert(player);
1072                 
1073                 v3f playerpos = player->getPosition();
1074                 v2f playerpos_2d(playerpos.X,playerpos.Z);
1075                 v2f objectpos_2d(m_position.X,m_position.Z);
1076
1077                 if(fabs(m_position.Y - playerpos.Y) < m_player_hit_distance*BS &&
1078                 objectpos_2d.getDistanceFrom(playerpos_2d) < m_player_hit_distance*BS)
1079                 {
1080                         env->damageLocalPlayer(m_player_hit_damage);
1081                         m_player_hit_timer = m_player_hit_interval;
1082                 }
1083         }
1084
1085         /* Run timers */
1086
1087         m_player_hit_timer -= dtime;
1088
1089         if(m_damage_visual_timer >= 0){
1090                 m_damage_visual_timer -= dtime;
1091                 if(m_damage_visual_timer <= 0){
1092                         dstream<<"id="<<m_id<<" damage visual ended"<<std::endl;
1093                 }
1094         }
1095
1096         m_walking_unset_timer += dtime;
1097         if(m_walking_unset_timer >= 1.0){
1098                 m_walking = false;
1099         }
1100
1101         m_shooting_unset_timer -= dtime;
1102         if(m_shooting_unset_timer <= 0.0){
1103                 if(m_bright_shooting){
1104                         u8 li = decode_light(m_last_light);
1105                         video::SColor color(255,li,li,li);
1106                         bill->setColor(color);
1107                         m_bright_shooting = false;
1108                 }
1109                 m_shooting = false;
1110         }
1111
1112 }
1113
1114 void MobV2CAO::processMessage(const std::string &data)
1115 {
1116         //dstream<<"MobV2CAO: Got message"<<std::endl;
1117         std::istringstream is(data, std::ios::binary);
1118         // command
1119         u8 cmd = readU8(is);
1120
1121         // Move
1122         if(cmd == 0)
1123         {
1124                 // pos
1125                 m_position = readV3F1000(is);
1126                 pos_translator.update(m_position);
1127                 // yaw
1128                 m_yaw = readF1000(is);
1129
1130                 m_walking = true;
1131                 m_walking_unset_timer = 0;
1132
1133                 updateNodePos();
1134         }
1135         // Damage
1136         else if(cmd == 1)
1137         {
1138                 //u16 damage = readU16(is);
1139
1140                 u8 li = decode_light(m_last_light);
1141                 if(li >= 100)
1142                         li = 30;
1143                 else
1144                         li = 255;
1145                 video::SColor color(255,li,li,li);
1146                 m_node->setColor(color);
1147
1148                 m_damage_visual_timer = 0.2;
1149         }
1150         // Trigger shooting
1151         else if(cmd == 2)
1152         {
1153                 // length
1154                 m_shooting_unset_timer = readF1000(is);
1155                 // bright?
1156                 m_bright_shooting = readU8(is);
1157                 if(m_bright_shooting){
1158                         u8 li = 255;
1159                         video::SColor color(255,li,li,li);
1160                         m_node->setColor(color);
1161                 }
1162
1163                 m_shooting = true;
1164         }
1165 }
1166
1167 void MobV2CAO::initialize(const std::string &data)
1168 {
1169         //dstream<<"MobV2CAO: Got init data"<<std::endl;
1170         
1171         {
1172                 std::istringstream is(data, std::ios::binary);
1173                 // version
1174                 u8 version = readU8(is);
1175                 // check version
1176                 if(version != 0){
1177                         dstream<<__FUNCTION_NAME<<": Invalid version"<<std::endl;
1178                         return;
1179                 }
1180                 
1181                 std::ostringstream tmp_os(std::ios::binary);
1182                 decompressZlib(is, tmp_os);
1183                 std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
1184                 m_properties->parseConfigLines(tmp_is, "MobArgsEnd");
1185
1186                 /*dstream<<"INFO: MobV2CAO::initialize(): got properties:"<<std::endl;
1187                 m_properties->writeLines(dstream);*/
1188
1189                 m_properties->setDefault("texture_name", "stone.png");
1190                 m_properties->setDefault("yaw", "0");
1191                 m_properties->setDefault("pos", "(0,0,0)");
1192                 m_properties->setDefault("sprite_size", "(1,1)");
1193                 m_properties->setDefault("sprite_pos", "(0,0,0)");
1194                 m_properties->setDefault("selection_size", "(0.4,0.4)");
1195                 m_properties->setDefault("selection_y", "-0.4");
1196                 m_properties->setDefault("sprite_type", "humanoid_1");
1197                 m_properties->setDefault("simple_anim_frames", "1");
1198                 m_properties->setDefault("simple_anim_frametime", "0.5");
1199                 m_properties->setDefault("lock_full_brightness", "false");
1200                 m_properties->setDefault("player_hit_damage", "0");
1201                 m_properties->setDefault("player_hit_distance", "1.5");
1202                 m_properties->setDefault("player_hit_interval", "1.5");
1203                 
1204                 m_yaw = m_properties->getFloat("yaw");
1205                 m_position = m_properties->getV3F("pos");
1206                 m_sprite_size = m_properties->getV2F("sprite_size") * BS;
1207                 m_sprite_pos = m_properties->getV3F("sprite_pos") * BS;
1208                 v2f selection_size = m_properties->getV2F("selection_size") * BS;
1209                 float selection_y = m_properties->getFloat("selection_y") * BS;
1210                 m_selection_box = core::aabbox3d<f32>(
1211                                 -selection_size.X, selection_y, -selection_size.X,
1212                                 selection_size.X, selection_y+selection_size.Y,
1213                                 selection_size.X);
1214                 m_sprite_type = m_properties->get("sprite_type");
1215                 m_simple_anim_frames = m_properties->getS32("simple_anim_frames");
1216                 m_simple_anim_frametime = m_properties->getFloat("simple_anim_frametime");
1217                 m_lock_full_brightness = m_properties->getBool("lock_full_brightness");
1218                 m_player_hit_damage = m_properties->getS32("player_hit_damage");
1219                 m_player_hit_distance = m_properties->getFloat("player_hit_distance");
1220                 m_player_hit_interval = m_properties->getFloat("player_hit_interval");
1221
1222                 pos_translator.init(m_position);
1223         }
1224         
1225         updateNodePos();
1226 }
1227
1228