]> git.lizzy.rs Git - minetest.git/blob - src/content_cao.cpp
Improve mobv2
[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_sprite_size(BS,BS),
878         m_sprite_y(0),
879         m_bright_shooting(false),
880         m_lock_full_brightness(false),
881         m_player_hit_timer(0)
882 {
883         ClientActiveObject::registerType(getType(), create);
884
885         m_properties = new Settings;
886 }
887
888 MobV2CAO::~MobV2CAO()
889 {
890         delete m_properties;
891 }
892
893 ClientActiveObject* MobV2CAO::create()
894 {
895         return new MobV2CAO();
896 }
897
898 void MobV2CAO::addToScene(scene::ISceneManager *smgr)
899 {
900         if(m_node != NULL)
901                 return;
902         
903         /*dstream<<"MobV2CAO::addToScene using texture_name="<<
904                         m_texture_name<<std::endl;*/
905         std::string texture_string = "[makealpha2:128,0,0;128,128,0:";
906         texture_string += m_texture_name;
907         
908         scene::MyBillboardSceneNode *bill = new scene::MyBillboardSceneNode(
909                         smgr->getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1));
910         bill->setMaterialTexture(0, g_texturesource->getTextureRaw(texture_string));
911         bill->setMaterialFlag(video::EMF_LIGHTING, false);
912         bill->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
913         bill->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
914         bill->setMaterialFlag(video::EMF_FOG_ENABLE, true);
915         bill->setColor(video::SColor(255,0,0,0));
916         bill->setVisible(false); /* Set visible when brightness is known */
917         bill->setSize(m_sprite_size);
918         if(m_sprite_type == "humanoid_1"){
919                 const float txp = 1./192;
920                 const float txs = txp*32;
921                 const float typ = 1./240;
922                 const float tys = typ*48;
923                 bill->setTCoords(0, v2f(txs*1, tys*1));
924                 bill->setTCoords(1, v2f(txs*1, tys*0));
925                 bill->setTCoords(2, v2f(txs*0, tys*0));
926                 bill->setTCoords(3, v2f(txs*0, tys*1));
927         } else if(m_sprite_type == "simple"){
928                 const float txs = 1.0;
929                 const float tys = 1.0 / m_simple_anim_frames;
930                 bill->setTCoords(0, v2f(txs*1, tys*1));
931                 bill->setTCoords(1, v2f(txs*1, tys*0));
932                 bill->setTCoords(2, v2f(txs*0, tys*0));
933                 bill->setTCoords(3, v2f(txs*0, tys*1));
934         } else {
935                 dstream<<"MobV2CAO: Unknown sprite type \""<<m_sprite_type<<"\""
936                                 <<std::endl;
937         }
938
939         m_node = bill;
940
941         updateNodePos();
942 }
943
944 void MobV2CAO::removeFromScene()
945 {
946         if(m_node == NULL)
947                 return;
948
949         m_node->drop();
950         m_node->remove();
951         m_node = NULL;
952 }
953
954 void MobV2CAO::updateLight(u8 light_at_pos)
955 {
956         if(m_lock_full_brightness)
957                 light_at_pos = 15;
958         
959         m_last_light = light_at_pos;
960
961         if(m_node == NULL)
962                 return;
963         
964         if(m_damage_visual_timer > 0)
965                 return;
966         
967         if(m_shooting && m_bright_shooting)
968                 return;
969         
970         /*if(light_at_pos <= 2){
971                 m_node->setVisible(false);
972                 return;
973         }*/
974
975         m_node->setVisible(true);
976
977         u8 li = decode_light(light_at_pos);
978         video::SColor color(255,li,li,li);
979         m_node->setColor(color);
980 }
981
982 v3s16 MobV2CAO::getLightPosition()
983 {
984         return floatToInt(m_position+v3f(0,0,0), BS);
985 }
986
987 void MobV2CAO::updateNodePos()
988 {
989         if(m_node == NULL)
990                 return;
991
992         m_node->setPosition(pos_translator.vect_show + v3f(0,m_sprite_y,0));
993 }
994
995 void MobV2CAO::step(float dtime, ClientEnvironment *env)
996 {
997         scene::MyBillboardSceneNode *bill = m_node;
998
999         pos_translator.translate(dtime);
1000         
1001         if(m_sprite_type == "humanoid_1"){
1002                 scene::ICameraSceneNode* camera = m_node->getSceneManager()->getActiveCamera();
1003                 v3f cam_to_mob = m_node->getAbsolutePosition() - camera->getAbsolutePosition();
1004                 cam_to_mob.normalize();
1005                 int col = 0;
1006                 if(cam_to_mob.Y > 0.7)
1007                         col = 5;
1008                 else if(cam_to_mob.Y < -0.7)
1009                         col = 4;
1010                 else{
1011                         float mob_dir = atan2(cam_to_mob.Z, cam_to_mob.X) / M_PI * 180.;
1012                         float dir = mob_dir - m_yaw;
1013                         dir = wrapDegrees_180(dir);
1014                         //dstream<<"id="<<m_id<<" dir="<<dir<<std::endl;
1015                         if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
1016                                 col = 2;
1017                         else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
1018                                 col = 3;
1019                         else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
1020                                 col = 0;
1021                         else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
1022                                 col = 1;
1023                         else
1024                                 col = 4;
1025                 }
1026
1027                 int row = 0;
1028                 if(m_shooting){
1029                         row = 3;
1030                 } else if(m_walking){
1031                         m_walk_timer += dtime;
1032                         if(m_walk_timer >= 0.5){
1033                                 m_walk_frame = (m_walk_frame + 1) % 2;
1034                                 m_walk_timer = 0;
1035                         }
1036                         if(m_walk_frame == 0)
1037                                 row = 1;
1038                         else
1039                                 row = 2;
1040                 }
1041
1042                 const float txp = 1./192;
1043                 const float txs = txp*32;
1044                 const float typ = 1./240;
1045                 const float tys = typ*48;
1046                 bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
1047                 bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
1048                 bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
1049                 bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
1050         } else if(m_sprite_type == "simple"){
1051                 m_walk_timer += dtime;
1052                 if(m_walk_timer >= m_simple_anim_frametime){
1053                         m_walk_frame = (m_walk_frame + 1) % m_simple_anim_frames;
1054                         m_walk_timer = 0;
1055                 }
1056                 int col = 0;
1057                 int row = m_walk_frame;
1058                 const float txs = 1.0;
1059                 const float tys = 1.0 / m_simple_anim_frames;
1060                 bill->setTCoords(0, v2f(txs*(1+col), tys*(1+row)));
1061                 bill->setTCoords(1, v2f(txs*(1+col), tys*(0+row)));
1062                 bill->setTCoords(2, v2f(txs*(0+col), tys*(0+row)));
1063                 bill->setTCoords(3, v2f(txs*(0+col), tys*(1+row)));
1064         } else {
1065                 dstream<<"MobV2CAO::step(): Unknown sprite type \""
1066                                 <<m_sprite_type<<"\""<<std::endl;
1067         }
1068
1069         updateNodePos();
1070
1071         /* Damage local player */
1072         if(m_player_hit_damage && m_player_hit_timer <= 0.0){
1073                 LocalPlayer *player = env->getLocalPlayer();
1074                 assert(player);
1075                 
1076                 v3f playerpos = player->getPosition();
1077                 v2f playerpos_2d(playerpos.X,playerpos.Z);
1078                 v2f objectpos_2d(m_position.X,m_position.Z);
1079
1080                 if(fabs(m_position.Y - playerpos.Y) < m_player_hit_distance*BS &&
1081                 objectpos_2d.getDistanceFrom(playerpos_2d) < m_player_hit_distance*BS)
1082                 {
1083                         env->damageLocalPlayer(m_player_hit_damage);
1084                         m_player_hit_timer = m_player_hit_interval;
1085                 }
1086         }
1087
1088         /* Run timers */
1089
1090         m_player_hit_timer -= dtime;
1091
1092         if(m_damage_visual_timer >= 0){
1093                 m_damage_visual_timer -= dtime;
1094                 if(m_damage_visual_timer <= 0){
1095                         dstream<<"id="<<m_id<<" damage visual ended"<<std::endl;
1096                 }
1097         }
1098
1099         m_walking_unset_timer += dtime;
1100         if(m_walking_unset_timer >= 1.0){
1101                 m_walking = false;
1102         }
1103
1104         m_shooting_unset_timer -= dtime;
1105         if(m_shooting_unset_timer <= 0.0){
1106                 if(m_bright_shooting){
1107                         u8 li = decode_light(m_last_light);
1108                         video::SColor color(255,li,li,li);
1109                         bill->setColor(color);
1110                         m_bright_shooting = false;
1111                 }
1112                 m_shooting = false;
1113         }
1114
1115 }
1116
1117 void MobV2CAO::processMessage(const std::string &data)
1118 {
1119         //dstream<<"MobV2CAO: Got message"<<std::endl;
1120         std::istringstream is(data, std::ios::binary);
1121         // command
1122         u8 cmd = readU8(is);
1123
1124         // Move
1125         if(cmd == 0)
1126         {
1127                 // pos
1128                 m_position = readV3F1000(is);
1129                 pos_translator.update(m_position);
1130                 // yaw
1131                 m_yaw = readF1000(is);
1132
1133                 m_walking = true;
1134                 m_walking_unset_timer = 0;
1135
1136                 updateNodePos();
1137         }
1138         // Damage
1139         else if(cmd == 1)
1140         {
1141                 //u16 damage = readU16(is);
1142
1143                 /*u8 li = decode_light(m_last_light);
1144                 if(li >= 100)
1145                         li = 30;
1146                 else
1147                         li = 255;*/
1148
1149                 /*video::SColor color(255,255,0,0);
1150                 m_node->setColor(color);
1151
1152                 m_damage_visual_timer = 0.2;*/
1153         }
1154         // Trigger shooting
1155         else if(cmd == 2)
1156         {
1157                 // length
1158                 m_shooting_unset_timer = readF1000(is);
1159                 // bright?
1160                 m_bright_shooting = readU8(is);
1161                 if(m_bright_shooting){
1162                         u8 li = 255;
1163                         video::SColor color(255,li,li,li);
1164                         m_node->setColor(color);
1165                 }
1166
1167                 m_shooting = true;
1168         }
1169 }
1170
1171 void MobV2CAO::initialize(const std::string &data)
1172 {
1173         //dstream<<"MobV2CAO: Got init data"<<std::endl;
1174         
1175         {
1176                 std::istringstream is(data, std::ios::binary);
1177                 // version
1178                 u8 version = readU8(is);
1179                 // check version
1180                 if(version != 0){
1181                         dstream<<__FUNCTION_NAME<<": Invalid version"<<std::endl;
1182                         return;
1183                 }
1184                 
1185                 std::ostringstream tmp_os(std::ios::binary);
1186                 decompressZlib(is, tmp_os);
1187                 std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
1188                 m_properties->parseConfigLines(tmp_is, "MobArgsEnd");
1189
1190                 dstream<<"INFO: MobV2CAO::initialize(): got properties:"<<std::endl;
1191                 m_properties->writeLines(dstream);
1192                 
1193                 m_properties->setDefault("looks", "dummy_default");
1194                 m_properties->setDefault("yaw", "0");
1195                 m_properties->setDefault("pos", "(0,0,0)");
1196                 m_properties->setDefault("player_hit_damage", "0");
1197                 m_properties->setDefault("player_hit_distance", "1.5");
1198                 m_properties->setDefault("player_hit_interval", "1.5");
1199                 
1200                 setLooks(m_properties->get("looks"));
1201                 m_yaw = m_properties->getFloat("yaw");
1202                 m_position = m_properties->getV3F("pos");
1203                 m_player_hit_damage = m_properties->getS32("player_hit_damage");
1204                 m_player_hit_distance = m_properties->getFloat("player_hit_distance");
1205                 m_player_hit_interval = m_properties->getFloat("player_hit_interval");
1206
1207                 pos_translator.init(m_position);
1208         }
1209         
1210         updateNodePos();
1211 }
1212
1213 bool MobV2CAO::directReportPunch(const std::string &toolname, v3f dir)
1214 {
1215         video::SColor color(255,255,0,0);
1216         m_node->setColor(color);
1217
1218         m_damage_visual_timer = 0.05;
1219
1220         m_position += dir * BS;
1221         pos_translator.sharpen();
1222         pos_translator.update(m_position);
1223         updateNodePos();
1224         
1225         return false;
1226 }
1227
1228 void MobV2CAO::setLooks(const std::string &looks)
1229 {
1230         v2f selection_size = v2f(0.4, 0.4) * BS;
1231         float selection_y = 0 * BS;
1232
1233         if(looks == "dungeon_master"){
1234                 m_texture_name = "dungeon_master.png";
1235                 m_sprite_type = "humanoid_1";
1236                 m_sprite_size = v2f(2, 3) * BS;
1237                 m_sprite_y = 0.85 * BS;
1238                 selection_size = v2f(0.4, 2.6) * BS;
1239                 selection_y = -0.4 * BS;
1240         }
1241         else if(looks == "fireball"){
1242                 m_texture_name = "fireball.png";
1243                 m_sprite_type = "simple";
1244                 m_sprite_size = v2f(1, 1) * BS;
1245                 m_simple_anim_frames = 3;
1246                 m_simple_anim_frametime = 0.1;
1247                 m_lock_full_brightness = true;
1248         }
1249         else{
1250                 m_texture_name = "stone.png";
1251                 m_sprite_type = "simple";
1252                 m_sprite_size = v2f(1, 1) * BS;
1253                 m_simple_anim_frames = 3;
1254                 m_simple_anim_frametime = 0.333;
1255                 selection_size = v2f(0.4, 0.4) * BS;
1256                 selection_y = 0 * BS;
1257         }
1258
1259         m_selection_box = core::aabbox3d<f32>(
1260                         -selection_size.X, selection_y, -selection_size.X,
1261                         selection_size.X, selection_y+selection_size.Y,
1262                         selection_size.X);
1263 }
1264