]> git.lizzy.rs Git - dragonfireclient.git/blob - src/content_cao.cpp
Merge pull request #46 from garrosh/master
[dragonfireclient.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 "collision.h"
24 #include "settings.h"
25 #include <ICameraSceneNode.h>
26 #include <ITextSceneNode.h>
27 #include <IBillboardSceneNode.h>
28 #include "serialization.h" // For decompressZlib
29 #include "gamedef.h"
30 #include "clientobject.h"
31 #include "content_object.h"
32 #include "mesh.h"
33 #include "utility.h" // For IntervalLimiter
34 class Settings;
35
36 core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
37
38 /*
39         SmoothTranslator
40 */
41
42 struct SmoothTranslator
43 {
44         v3f vect_old;
45         v3f vect_show;
46         v3f vect_aim;
47         f32 anim_counter;
48         f32 anim_time;
49         f32 anim_time_counter;
50         bool aim_is_end;
51
52         SmoothTranslator():
53                 vect_old(0,0,0),
54                 vect_show(0,0,0),
55                 vect_aim(0,0,0),
56                 anim_counter(0),
57                 anim_time(0),
58                 anim_time_counter(0),
59                 aim_is_end(true)
60         {}
61
62         void init(v3f vect)
63         {
64                 vect_old = vect;
65                 vect_show = vect;
66                 vect_aim = vect;
67                 anim_counter = 0;
68                 anim_time = 0;
69                 anim_time_counter = 0;
70                 aim_is_end = true;
71         }
72
73         void sharpen()
74         {
75                 init(vect_show);
76         }
77
78         void update(v3f vect_new, bool is_end_position=false, float update_interval=-1)
79         {
80                 aim_is_end = is_end_position;
81                 vect_old = vect_show;
82                 vect_aim = vect_new;
83                 if(update_interval > 0){
84                         anim_time = update_interval;
85                 } else {
86                         if(anim_time < 0.001 || anim_time > 1.0)
87                                 anim_time = anim_time_counter;
88                         else
89                                 anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
90                 }
91                 anim_time_counter = 0;
92                 anim_counter = 0;
93         }
94
95         void translate(f32 dtime)
96         {
97                 anim_time_counter = anim_time_counter + dtime;
98                 anim_counter = anim_counter + dtime;
99                 v3f vect_move = vect_aim - vect_old;
100                 f32 moveratio = 1.0;
101                 if(anim_time > 0.001)
102                         moveratio = anim_time_counter / anim_time;
103                 // Move a bit less than should, to avoid oscillation
104                 moveratio = moveratio * 0.8;
105                 float move_end = 1.5;
106                 if(aim_is_end)
107                         move_end = 1.0;
108                 if(moveratio > move_end)
109                         moveratio = move_end;
110                 vect_show = vect_old + vect_move * moveratio;
111         }
112
113         bool is_moving()
114         {
115                 return ((anim_time_counter / anim_time) < 1.4);
116         }
117 };
118
119
120 /*
121         TestCAO
122 */
123
124 class TestCAO : public ClientActiveObject
125 {
126 public:
127         TestCAO(IGameDef *gamedef, ClientEnvironment *env);
128         virtual ~TestCAO();
129         
130         u8 getType() const
131         {
132                 return ACTIVEOBJECT_TYPE_TEST;
133         }
134         
135         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
136
137         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
138                         IrrlichtDevice *irr);
139         void removeFromScene();
140         void updateLight(u8 light_at_pos);
141         v3s16 getLightPosition();
142         void updateNodePos();
143
144         void step(float dtime, ClientEnvironment *env);
145
146         void processMessage(const std::string &data);
147
148 private:
149         scene::IMeshSceneNode *m_node;
150         v3f m_position;
151 };
152
153 /*
154         ItemCAO
155 */
156
157 class ItemCAO : public ClientActiveObject
158 {
159 public:
160         ItemCAO(IGameDef *gamedef, ClientEnvironment *env);
161         virtual ~ItemCAO();
162         
163         u8 getType() const
164         {
165                 return ACTIVEOBJECT_TYPE_ITEM;
166         }
167         
168         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
169
170         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
171                         IrrlichtDevice *irr);
172         void removeFromScene();
173         void updateLight(u8 light_at_pos);
174         v3s16 getLightPosition();
175         void updateNodePos();
176         void updateInfoText();
177         void updateTexture();
178
179         void step(float dtime, ClientEnvironment *env);
180
181         void processMessage(const std::string &data);
182
183         void initialize(const std::string &data);
184         
185         core::aabbox3d<f32>* getSelectionBox()
186                 {return &m_selection_box;}
187         v3f getPosition()
188                 {return m_position;}
189         
190         std::string infoText()
191                 {return m_infotext;}
192
193 private:
194         core::aabbox3d<f32> m_selection_box;
195         scene::IMeshSceneNode *m_node;
196         v3f m_position;
197         std::string m_itemstring;
198         std::string m_infotext;
199 };
200
201 /*
202         RatCAO
203 */
204
205 class RatCAO : public ClientActiveObject
206 {
207 public:
208         RatCAO(IGameDef *gamedef, ClientEnvironment *env);
209         virtual ~RatCAO();
210         
211         u8 getType() const
212         {
213                 return ACTIVEOBJECT_TYPE_RAT;
214         }
215         
216         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
217
218         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
219                         IrrlichtDevice *irr);
220         void removeFromScene();
221         void updateLight(u8 light_at_pos);
222         v3s16 getLightPosition();
223         void updateNodePos();
224
225         void step(float dtime, ClientEnvironment *env);
226
227         void processMessage(const std::string &data);
228
229         void initialize(const std::string &data);
230         
231         core::aabbox3d<f32>* getSelectionBox()
232                 {return &m_selection_box;}
233         v3f getPosition()
234                 {return pos_translator.vect_show;}
235                 //{return m_position;}
236
237 private:
238         core::aabbox3d<f32> m_selection_box;
239         scene::IMeshSceneNode *m_node;
240         v3f m_position;
241         float m_yaw;
242         SmoothTranslator pos_translator;
243 };
244
245 /*
246         Oerkki1CAO
247 */
248
249 class Oerkki1CAO : public ClientActiveObject
250 {
251 public:
252         Oerkki1CAO(IGameDef *gamedef, ClientEnvironment *env);
253         virtual ~Oerkki1CAO();
254         
255         u8 getType() const
256         {
257                 return ACTIVEOBJECT_TYPE_OERKKI1;
258         }
259         
260         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
261
262         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
263                         IrrlichtDevice *irr);
264         void removeFromScene();
265         void updateLight(u8 light_at_pos);
266         v3s16 getLightPosition();
267         void updateNodePos();
268
269         void step(float dtime, ClientEnvironment *env);
270
271         void processMessage(const std::string &data);
272
273         void initialize(const std::string &data);
274         
275         core::aabbox3d<f32>* getSelectionBox()
276                 {return &m_selection_box;}
277         v3f getPosition()
278                 {return pos_translator.vect_show;}
279                 //{return m_position;}
280
281         // If returns true, punch will not be sent to the server
282         bool directReportPunch(const std::string &toolname, v3f dir);
283
284 private:
285         IntervalLimiter m_attack_interval;
286         core::aabbox3d<f32> m_selection_box;
287         scene::IMeshSceneNode *m_node;
288         v3f m_position;
289         float m_yaw;
290         SmoothTranslator pos_translator;
291         float m_damage_visual_timer;
292         bool m_damage_texture_enabled;
293 };
294
295 /*
296         FireflyCAO
297 */
298
299 class FireflyCAO : public ClientActiveObject
300 {
301 public:
302         FireflyCAO(IGameDef *gamedef, ClientEnvironment *env);
303         virtual ~FireflyCAO();
304         
305         u8 getType() const
306         {
307                 return ACTIVEOBJECT_TYPE_FIREFLY;
308         }
309         
310         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
311
312         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
313                         IrrlichtDevice *irr);
314         void removeFromScene();
315         void updateLight(u8 light_at_pos);
316         v3s16 getLightPosition();
317         void updateNodePos();
318
319         void step(float dtime, ClientEnvironment *env);
320
321         void processMessage(const std::string &data);
322
323         void initialize(const std::string &data);
324         
325         core::aabbox3d<f32>* getSelectionBox()
326                 {return &m_selection_box;}
327         v3f getPosition()
328                 {return m_position;}
329
330 private:
331         core::aabbox3d<f32> m_selection_box;
332         scene::IMeshSceneNode *m_node;
333         v3f m_position;
334         float m_yaw;
335         SmoothTranslator pos_translator;
336 };
337
338 static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
339                 float txs, float tys, int col, int row)
340 {
341         video::SMaterial& material = bill->getMaterial(0);
342         core::matrix4& matrix = material.getTextureMatrix(0);
343         matrix.setTextureTranslate(txs*col, tys*row);
344         matrix.setTextureScale(txs, tys);
345 }
346
347 /*
348         MobV2CAO
349 */
350
351 class MobV2CAO : public ClientActiveObject
352 {
353 public:
354         MobV2CAO(IGameDef *gamedef, ClientEnvironment *env);
355         virtual ~MobV2CAO();
356         
357         u8 getType() const
358         {
359                 return ACTIVEOBJECT_TYPE_MOBV2;
360         }
361         
362         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
363
364         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
365                         IrrlichtDevice *irr);
366         void removeFromScene();
367         void updateLight(u8 light_at_pos);
368         v3s16 getLightPosition();
369         void updateNodePos();
370
371         void step(float dtime, ClientEnvironment *env);
372
373         void processMessage(const std::string &data);
374
375         void initialize(const std::string &data);
376         
377         core::aabbox3d<f32>* getSelectionBox()
378                 {return &m_selection_box;}
379         v3f getPosition()
380                 {return pos_translator.vect_show;}
381                 //{return m_position;}
382         bool doShowSelectionBox(){return false;}
383
384         // If returns true, punch will not be sent to the server
385         bool directReportPunch(const std::string &toolname, v3f dir);
386
387 private:
388         void setLooks(const std::string &looks);
389         
390         IntervalLimiter m_attack_interval;
391         core::aabbox3d<f32> m_selection_box;
392         scene::IBillboardSceneNode *m_node;
393         v3f m_position;
394         std::string m_texture_name;
395         float m_yaw;
396         SmoothTranslator pos_translator;
397         bool m_walking;
398         float m_walking_unset_timer;
399         float m_walk_timer;
400         int m_walk_frame;
401         float m_damage_visual_timer;
402         u8 m_last_light;
403         bool m_shooting;
404         float m_shooting_unset_timer;
405         v2f m_sprite_size;
406         float m_sprite_y;
407         bool m_bright_shooting;
408         std::string m_sprite_type;
409         int m_simple_anim_frames;
410         float m_simple_anim_frametime;
411         bool m_lock_full_brightness;
412         int m_player_hit_damage;
413         float m_player_hit_distance;
414         float m_player_hit_interval;
415         float m_player_hit_timer;
416
417         Settings *m_properties;
418 };
419
420 /*
421         TestCAO
422 */
423
424 // Prototype
425 TestCAO proto_TestCAO(NULL, NULL);
426
427 TestCAO::TestCAO(IGameDef *gamedef, ClientEnvironment *env):
428         ClientActiveObject(0, gamedef, env),
429         m_node(NULL),
430         m_position(v3f(0,10*BS,0))
431 {
432         ClientActiveObject::registerType(getType(), create);
433 }
434
435 TestCAO::~TestCAO()
436 {
437 }
438
439 ClientActiveObject* TestCAO::create(IGameDef *gamedef, ClientEnvironment *env)
440 {
441         return new TestCAO(gamedef, env);
442 }
443
444 void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
445                         IrrlichtDevice *irr)
446 {
447         if(m_node != NULL)
448                 return;
449         
450         //video::IVideoDriver* driver = smgr->getVideoDriver();
451         
452         scene::SMesh *mesh = new scene::SMesh();
453         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
454         video::SColor c(255,255,255,255);
455         video::S3DVertex vertices[4] =
456         {
457                 video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
458                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
459                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
460                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
461         };
462         u16 indices[] = {0,1,2,2,3,0};
463         buf->append(vertices, 4, indices, 6);
464         // Set material
465         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
466         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
467         buf->getMaterial().setTexture(0, tsrc->getTextureRaw("rat.png"));
468         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
469         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
470         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
471         // Add to mesh
472         mesh->addMeshBuffer(buf);
473         buf->drop();
474         m_node = smgr->addMeshSceneNode(mesh, NULL);
475         mesh->drop();
476         updateNodePos();
477 }
478
479 void TestCAO::removeFromScene()
480 {
481         if(m_node == NULL)
482                 return;
483
484         m_node->remove();
485         m_node = NULL;
486 }
487
488 void TestCAO::updateLight(u8 light_at_pos)
489 {
490 }
491
492 v3s16 TestCAO::getLightPosition()
493 {
494         return floatToInt(m_position, BS);
495 }
496
497 void TestCAO::updateNodePos()
498 {
499         if(m_node == NULL)
500                 return;
501
502         m_node->setPosition(m_position);
503         //m_node->setRotation(v3f(0, 45, 0));
504 }
505
506 void TestCAO::step(float dtime, ClientEnvironment *env)
507 {
508         if(m_node)
509         {
510                 v3f rot = m_node->getRotation();
511                 //infostream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
512                 rot.Y += dtime * 180;
513                 m_node->setRotation(rot);
514         }
515 }
516
517 void TestCAO::processMessage(const std::string &data)
518 {
519         infostream<<"TestCAO: Got data: "<<data<<std::endl;
520         std::istringstream is(data, std::ios::binary);
521         u16 cmd;
522         is>>cmd;
523         if(cmd == 0)
524         {
525                 v3f newpos;
526                 is>>newpos.X;
527                 is>>newpos.Y;
528                 is>>newpos.Z;
529                 m_position = newpos;
530                 updateNodePos();
531         }
532 }
533
534 /*
535         ItemCAO
536 */
537
538 #include "inventory.h"
539
540 // Prototype
541 ItemCAO proto_ItemCAO(NULL, NULL);
542
543 ItemCAO::ItemCAO(IGameDef *gamedef, ClientEnvironment *env):
544         ClientActiveObject(0, gamedef, env),
545         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
546         m_node(NULL),
547         m_position(v3f(0,10*BS,0))
548 {
549         if(!gamedef && !env)
550         {
551                 ClientActiveObject::registerType(getType(), create);
552         }
553 }
554
555 ItemCAO::~ItemCAO()
556 {
557 }
558
559 ClientActiveObject* ItemCAO::create(IGameDef *gamedef, ClientEnvironment *env)
560 {
561         return new ItemCAO(gamedef, env);
562 }
563
564 void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
565                         IrrlichtDevice *irr)
566 {
567         if(m_node != NULL)
568                 return;
569         
570         //video::IVideoDriver* driver = smgr->getVideoDriver();
571         
572         scene::SMesh *mesh = new scene::SMesh();
573         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
574         video::SColor c(255,255,255,255);
575         video::S3DVertex vertices[4] =
576         {
577                 /*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
578                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
579                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
580                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
581                 video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1),
582                 video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1),
583                 video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0),
584                 video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0),
585         };
586         u16 indices[] = {0,1,2,2,3,0};
587         buf->append(vertices, 4, indices, 6);
588         // Set material
589         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
590         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
591         // Initialize with a generated placeholder texture
592         buf->getMaterial().setTexture(0, tsrc->getTextureRaw(""));
593         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
594         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
595         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
596         // Add to mesh
597         mesh->addMeshBuffer(buf);
598         buf->drop();
599         m_node = smgr->addMeshSceneNode(mesh, NULL);
600         mesh->drop();
601         updateNodePos();
602
603         /*
604                 Update image of node
605         */
606
607         updateTexture();
608 }
609
610 void ItemCAO::removeFromScene()
611 {
612         if(m_node == NULL)
613                 return;
614
615         m_node->remove();
616         m_node = NULL;
617 }
618
619 void ItemCAO::updateLight(u8 light_at_pos)
620 {
621         if(m_node == NULL)
622                 return;
623
624         u8 li = decode_light(light_at_pos);
625         video::SColor color(255,li,li,li);
626         setMeshColor(m_node->getMesh(), color);
627 }
628
629 v3s16 ItemCAO::getLightPosition()
630 {
631         return floatToInt(m_position, BS);
632 }
633
634 void ItemCAO::updateNodePos()
635 {
636         if(m_node == NULL)
637                 return;
638
639         m_node->setPosition(m_position);
640 }
641
642 void ItemCAO::updateInfoText()
643 {
644         try{
645                 IItemDefManager *idef = m_gamedef->idef();
646                 ItemStack item;
647                 item.deSerialize(m_itemstring, idef);
648                 if(item.isKnown(idef))
649                         m_infotext = item.getDefinition(idef).description;
650                 else
651                         m_infotext = "Unknown item: '" + m_itemstring + "'";
652                 if(item.count >= 2)
653                         m_infotext += " (" + itos(item.count) + ")";
654         }
655         catch(SerializationError &e)
656         {
657                 m_infotext = "Unknown item: '" + m_itemstring + "'";
658         }
659 }
660
661 void ItemCAO::updateTexture()
662 {
663         if(m_node == NULL)
664                 return;
665
666         // Create an inventory item to see what is its image
667         std::istringstream is(m_itemstring, std::ios_base::binary);
668         video::ITexture *texture = NULL;
669         try{
670                 IItemDefManager *idef = m_gamedef->idef();
671                 ItemStack item;
672                 item.deSerialize(is, idef);
673                 texture = item.getDefinition(idef).inventory_texture;
674         }
675         catch(SerializationError &e)
676         {
677                 infostream<<"WARNING: "<<__FUNCTION_NAME
678                                 <<": error deSerializing itemstring \""
679                                 <<m_itemstring<<std::endl;
680         }
681         
682         // Set meshbuffer texture
683         m_node->getMaterial(0).setTexture(0, texture);
684 }
685
686
687 void ItemCAO::step(float dtime, ClientEnvironment *env)
688 {
689         if(m_node)
690         {
691                 /*v3f rot = m_node->getRotation();
692                 rot.Y += dtime * 120;
693                 m_node->setRotation(rot);*/
694                 LocalPlayer *player = env->getLocalPlayer();
695                 assert(player);
696                 v3f rot = m_node->getRotation();
697                 rot.Y = 180.0 - (player->getYaw());
698                 m_node->setRotation(rot);
699         }
700 }
701
702 void ItemCAO::processMessage(const std::string &data)
703 {
704         //infostream<<"ItemCAO: Got message"<<std::endl;
705         std::istringstream is(data, std::ios::binary);
706         // command
707         u8 cmd = readU8(is);
708         if(cmd == 0)
709         {
710                 // pos
711                 m_position = readV3F1000(is);
712                 updateNodePos();
713         }
714         if(cmd == 1)
715         {
716                 // itemstring
717                 m_itemstring = deSerializeString(is);
718                 updateInfoText();
719                 updateTexture();
720         }
721 }
722
723 void ItemCAO::initialize(const std::string &data)
724 {
725         infostream<<"ItemCAO: Got init data"<<std::endl;
726         
727         {
728                 std::istringstream is(data, std::ios::binary);
729                 // version
730                 u8 version = readU8(is);
731                 // check version
732                 if(version != 0)
733                         return;
734                 // pos
735                 m_position = readV3F1000(is);
736                 // itemstring
737                 m_itemstring = deSerializeString(is);
738         }
739         
740         updateNodePos();
741         updateInfoText();
742 }
743
744 /*
745         RatCAO
746 */
747
748 #include "inventory.h"
749
750 // Prototype
751 RatCAO proto_RatCAO(NULL, NULL);
752
753 RatCAO::RatCAO(IGameDef *gamedef, ClientEnvironment *env):
754         ClientActiveObject(0, gamedef, env),
755         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
756         m_node(NULL),
757         m_position(v3f(0,10*BS,0)),
758         m_yaw(0)
759 {
760         ClientActiveObject::registerType(getType(), create);
761 }
762
763 RatCAO::~RatCAO()
764 {
765 }
766
767 ClientActiveObject* RatCAO::create(IGameDef *gamedef, ClientEnvironment *env)
768 {
769         return new RatCAO(gamedef, env);
770 }
771
772 void RatCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
773                         IrrlichtDevice *irr)
774 {
775         if(m_node != NULL)
776                 return;
777         
778         //video::IVideoDriver* driver = smgr->getVideoDriver();
779         
780         scene::SMesh *mesh = new scene::SMesh();
781         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
782         video::SColor c(255,255,255,255);
783         video::S3DVertex vertices[4] =
784         {
785                 video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
786                 video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
787                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
788                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
789         };
790         u16 indices[] = {0,1,2,2,3,0};
791         buf->append(vertices, 4, indices, 6);
792         // Set material
793         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
794         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
795         //buf->getMaterial().setTexture(0, NULL);
796         buf->getMaterial().setTexture(0, tsrc->getTextureRaw("rat.png"));
797         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
798         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
799         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
800         // Add to mesh
801         mesh->addMeshBuffer(buf);
802         buf->drop();
803         m_node = smgr->addMeshSceneNode(mesh, NULL);
804         mesh->drop();
805         // Set it to use the materials of the meshbuffers directly.
806         // This is needed for changing the texture in the future
807         m_node->setReadOnlyMaterials(true);
808         updateNodePos();
809 }
810
811 void RatCAO::removeFromScene()
812 {
813         if(m_node == NULL)
814                 return;
815
816         m_node->remove();
817         m_node = NULL;
818 }
819
820 void RatCAO::updateLight(u8 light_at_pos)
821 {
822         if(m_node == NULL)
823                 return;
824
825         u8 li = decode_light(light_at_pos);
826         video::SColor color(255,li,li,li);
827         setMeshColor(m_node->getMesh(), color);
828 }
829
830 v3s16 RatCAO::getLightPosition()
831 {
832         return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
833 }
834
835 void RatCAO::updateNodePos()
836 {
837         if(m_node == NULL)
838                 return;
839
840         //m_node->setPosition(m_position);
841         m_node->setPosition(pos_translator.vect_show);
842
843         v3f rot = m_node->getRotation();
844         rot.Y = 180.0 - m_yaw;
845         m_node->setRotation(rot);
846 }
847
848 void RatCAO::step(float dtime, ClientEnvironment *env)
849 {
850         pos_translator.translate(dtime);
851         updateNodePos();
852 }
853
854 void RatCAO::processMessage(const std::string &data)
855 {
856         //infostream<<"RatCAO: Got message"<<std::endl;
857         std::istringstream is(data, std::ios::binary);
858         // command
859         u8 cmd = readU8(is);
860         if(cmd == 0)
861         {
862                 // pos
863                 m_position = readV3F1000(is);
864                 pos_translator.update(m_position);
865                 // yaw
866                 m_yaw = readF1000(is);
867                 updateNodePos();
868         }
869 }
870
871 void RatCAO::initialize(const std::string &data)
872 {
873         //infostream<<"RatCAO: Got init data"<<std::endl;
874         
875         {
876                 std::istringstream is(data, std::ios::binary);
877                 // version
878                 u8 version = readU8(is);
879                 // check version
880                 if(version != 0)
881                         return;
882                 // pos
883                 m_position = readV3F1000(is);
884                 pos_translator.init(m_position);
885         }
886         
887         updateNodePos();
888 }
889
890 /*
891         Oerkki1CAO
892 */
893
894 #include "inventory.h"
895
896 // Prototype
897 Oerkki1CAO proto_Oerkki1CAO(NULL, NULL);
898
899 Oerkki1CAO::Oerkki1CAO(IGameDef *gamedef, ClientEnvironment *env):
900         ClientActiveObject(0, gamedef, env),
901         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
902         m_node(NULL),
903         m_position(v3f(0,10*BS,0)),
904         m_yaw(0),
905         m_damage_visual_timer(0),
906         m_damage_texture_enabled(false)
907 {
908         ClientActiveObject::registerType(getType(), create);
909 }
910
911 Oerkki1CAO::~Oerkki1CAO()
912 {
913 }
914
915 ClientActiveObject* Oerkki1CAO::create(IGameDef *gamedef, ClientEnvironment *env)
916 {
917         return new Oerkki1CAO(gamedef, env);
918 }
919
920 void Oerkki1CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
921                         IrrlichtDevice *irr)
922 {
923         if(m_node != NULL)
924                 return;
925         
926         //video::IVideoDriver* driver = smgr->getVideoDriver();
927         
928         scene::SMesh *mesh = new scene::SMesh();
929         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
930         video::SColor c(255,255,255,255);
931         video::S3DVertex vertices[4] =
932         {
933                 video::S3DVertex(-BS/2-BS,0,0, 0,0,0, c, 0,1),
934                 video::S3DVertex(BS/2+BS,0,0, 0,0,0, c, 1,1),
935                 video::S3DVertex(BS/2+BS,BS*2,0, 0,0,0, c, 1,0),
936                 video::S3DVertex(-BS/2-BS,BS*2,0, 0,0,0, c, 0,0),
937         };
938         u16 indices[] = {0,1,2,2,3,0};
939         buf->append(vertices, 4, indices, 6);
940         // Set material
941         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
942         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
943         //buf->getMaterial().setTexture(0, NULL);
944         buf->getMaterial().setTexture(0, tsrc->getTextureRaw("oerkki1.png"));
945         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
946         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
947         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
948         // Add to mesh
949         mesh->addMeshBuffer(buf);
950         buf->drop();
951         m_node = smgr->addMeshSceneNode(mesh, NULL);
952         mesh->drop();
953         // Set it to use the materials of the meshbuffers directly.
954         // This is needed for changing the texture in the future
955         m_node->setReadOnlyMaterials(true);
956         updateNodePos();
957 }
958
959 void Oerkki1CAO::removeFromScene()
960 {
961         if(m_node == NULL)
962                 return;
963
964         m_node->remove();
965         m_node = NULL;
966 }
967
968 void Oerkki1CAO::updateLight(u8 light_at_pos)
969 {
970         if(m_node == NULL)
971                 return;
972         
973         if(light_at_pos <= 2)
974         {
975                 m_node->setVisible(false);
976                 return;
977         }
978
979         m_node->setVisible(true);
980
981         u8 li = decode_light(light_at_pos);
982         video::SColor color(255,li,li,li);
983         setMeshColor(m_node->getMesh(), color);
984 }
985
986 v3s16 Oerkki1CAO::getLightPosition()
987 {
988         return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
989 }
990
991 void Oerkki1CAO::updateNodePos()
992 {
993         if(m_node == NULL)
994                 return;
995
996         //m_node->setPosition(m_position);
997         m_node->setPosition(pos_translator.vect_show);
998
999         v3f rot = m_node->getRotation();
1000         rot.Y = 180.0 - m_yaw + 90.0;
1001         m_node->setRotation(rot);
1002 }
1003
1004 void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
1005 {
1006         ITextureSource *tsrc = m_gamedef->tsrc();
1007
1008         pos_translator.translate(dtime);
1009         updateNodePos();
1010
1011         LocalPlayer *player = env->getLocalPlayer();
1012         assert(player);
1013         
1014         v3f playerpos = player->getPosition();
1015         v2f playerpos_2d(playerpos.X,playerpos.Z);
1016         v2f objectpos_2d(m_position.X,m_position.Z);
1017
1018         if(fabs(m_position.Y - playerpos.Y) < 1.5*BS &&
1019                         objectpos_2d.getDistanceFrom(playerpos_2d) < 1.5*BS)
1020         {
1021                 if(m_attack_interval.step(dtime, 0.5))
1022                 {
1023                         env->damageLocalPlayer(2);
1024                 }
1025         }
1026
1027         if(m_damage_visual_timer > 0)
1028         {
1029                 if(!m_damage_texture_enabled)
1030                 {
1031                         // Enable damage texture
1032                         if(m_node)
1033                         {
1034                                 /*video::IVideoDriver* driver =
1035                                         m_node->getSceneManager()->getVideoDriver();*/
1036                                 
1037                                 scene::IMesh *mesh = m_node->getMesh();
1038                                 if(mesh == NULL)
1039                                         return;
1040                                 
1041                                 u16 mc = mesh->getMeshBufferCount();
1042                                 for(u16 j=0; j<mc; j++)
1043                                 {
1044                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
1045                                         buf->getMaterial().setTexture(0,
1046                                                         tsrc->getTextureRaw("oerkki1_damaged.png"));
1047                                 }
1048                         }
1049                         m_damage_texture_enabled = true;
1050                 }
1051                 m_damage_visual_timer -= dtime;
1052         }
1053         else
1054         {
1055                 if(m_damage_texture_enabled)
1056                 {
1057                         // Disable damage texture
1058                         if(m_node)
1059                         {
1060                                 /*video::IVideoDriver* driver =
1061                                         m_node->getSceneManager()->getVideoDriver();*/
1062                                 
1063                                 scene::IMesh *mesh = m_node->getMesh();
1064                                 if(mesh == NULL)
1065                                         return;
1066                                 
1067                                 u16 mc = mesh->getMeshBufferCount();
1068                                 for(u16 j=0; j<mc; j++)
1069                                 {
1070                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
1071                                         buf->getMaterial().setTexture(0,
1072                                                         tsrc->getTextureRaw("oerkki1.png"));
1073                                 }
1074                         }
1075                         m_damage_texture_enabled = false;
1076                 }
1077         }
1078 }
1079
1080 void Oerkki1CAO::processMessage(const std::string &data)
1081 {
1082         //infostream<<"Oerkki1CAO: Got message"<<std::endl;
1083         std::istringstream is(data, std::ios::binary);
1084         // command
1085         u8 cmd = readU8(is);
1086         if(cmd == 0)
1087         {
1088                 // pos
1089                 m_position = readV3F1000(is);
1090                 pos_translator.update(m_position);
1091                 // yaw
1092                 m_yaw = readF1000(is);
1093                 updateNodePos();
1094         }
1095         else if(cmd == 1)
1096         {
1097                 //u16 damage = readU8(is);
1098                 m_damage_visual_timer = 1.0;
1099         }
1100 }
1101
1102 void Oerkki1CAO::initialize(const std::string &data)
1103 {
1104         //infostream<<"Oerkki1CAO: Got init data"<<std::endl;
1105         
1106         {
1107                 std::istringstream is(data, std::ios::binary);
1108                 // version
1109                 u8 version = readU8(is);
1110                 // check version
1111                 if(version != 0)
1112                         return;
1113                 // pos
1114                 m_position = readV3F1000(is);
1115                 pos_translator.init(m_position);
1116         }
1117         
1118         updateNodePos();
1119 }
1120
1121 bool Oerkki1CAO::directReportPunch(const std::string &toolname, v3f dir)
1122 {
1123         m_damage_visual_timer = 1.0;
1124
1125         m_position += dir * BS;
1126         pos_translator.sharpen();
1127         pos_translator.update(m_position);
1128         updateNodePos();
1129         
1130         return false;
1131 }
1132
1133 /*
1134         FireflyCAO
1135 */
1136
1137 // Prototype
1138 FireflyCAO proto_FireflyCAO(NULL, NULL);
1139
1140 FireflyCAO::FireflyCAO(IGameDef *gamedef, ClientEnvironment *env):
1141         ClientActiveObject(0, gamedef, env),
1142         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
1143         m_node(NULL),
1144         m_position(v3f(0,10*BS,0)),
1145         m_yaw(0)
1146 {
1147         ClientActiveObject::registerType(getType(), create);
1148 }
1149
1150 FireflyCAO::~FireflyCAO()
1151 {
1152 }
1153
1154 ClientActiveObject* FireflyCAO::create(IGameDef *gamedef, ClientEnvironment *env)
1155 {
1156         return new FireflyCAO(gamedef, env);
1157 }
1158
1159 void FireflyCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
1160                         IrrlichtDevice *irr)
1161 {
1162         if(m_node != NULL)
1163                 return;
1164         
1165         //video::IVideoDriver* driver = smgr->getVideoDriver();
1166         
1167         scene::SMesh *mesh = new scene::SMesh();
1168         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
1169         video::SColor c(255,255,255,255);
1170         video::S3DVertex vertices[4] =
1171         {
1172                 video::S3DVertex(0,0,0, 0,0,0, c, 0,1),
1173                 video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
1174                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
1175                 video::S3DVertex(0,BS/2,0, 0,0,0, c, 0,0),
1176         };
1177         u16 indices[] = {0,1,2,2,3,0};
1178         buf->append(vertices, 4, indices, 6);
1179         // Set material
1180         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
1181         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
1182         //buf->getMaterial().setTexture(0, NULL);
1183         buf->getMaterial().setTexture(0, tsrc->getTextureRaw("firefly.png"));
1184         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
1185         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
1186         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
1187         // Add to mesh
1188         mesh->addMeshBuffer(buf);
1189         buf->drop();
1190         m_node = smgr->addMeshSceneNode(mesh, NULL);
1191         mesh->drop();
1192         // Set it to use the materials of the meshbuffers directly.
1193         // This is needed for changing the texture in the future
1194         m_node->setReadOnlyMaterials(true);
1195         updateNodePos();
1196 }
1197
1198 void FireflyCAO::removeFromScene()
1199 {
1200         if(m_node == NULL)
1201                 return;
1202
1203         m_node->remove();
1204         m_node = NULL;
1205 }
1206
1207 void FireflyCAO::updateLight(u8 light_at_pos)
1208 {
1209         if(m_node == NULL)
1210                 return;
1211
1212         u8 li = 255;
1213         video::SColor color(255,li,li,li);
1214         setMeshColor(m_node->getMesh(), color);
1215 }
1216
1217 v3s16 FireflyCAO::getLightPosition()
1218 {
1219         return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
1220 }
1221
1222 void FireflyCAO::updateNodePos()
1223 {
1224         if(m_node == NULL)
1225                 return;
1226
1227         //m_node->setPosition(m_position);
1228         m_node->setPosition(pos_translator.vect_show);
1229
1230         v3f rot = m_node->getRotation();
1231         rot.Y = 180.0 - m_yaw;
1232         m_node->setRotation(rot);
1233 }
1234
1235 void FireflyCAO::step(float dtime, ClientEnvironment *env)
1236 {
1237         pos_translator.translate(dtime);
1238         updateNodePos();
1239 }
1240
1241 void FireflyCAO::processMessage(const std::string &data)
1242 {
1243         //infostream<<"FireflyCAO: Got message"<<std::endl;
1244         std::istringstream is(data, std::ios::binary);
1245         // command
1246         u8 cmd = readU8(is);
1247         if(cmd == 0)
1248         {
1249                 // pos
1250                 m_position = readV3F1000(is);
1251                 pos_translator.update(m_position);
1252                 // yaw
1253                 m_yaw = readF1000(is);
1254                 updateNodePos();
1255         }
1256 }
1257
1258 void FireflyCAO::initialize(const std::string &data)
1259 {
1260         //infostream<<"FireflyCAO: Got init data"<<std::endl;
1261         
1262         {
1263                 std::istringstream is(data, std::ios::binary);
1264                 // version
1265                 u8 version = readU8(is);
1266                 // check version
1267                 if(version != 0)
1268                         return;
1269                 // pos
1270                 m_position = readV3F1000(is);
1271                 pos_translator.init(m_position);
1272         }
1273         
1274         updateNodePos();
1275 }
1276
1277 /*
1278         MobV2CAO
1279 */
1280
1281 // Prototype
1282 MobV2CAO proto_MobV2CAO(NULL, NULL);
1283
1284 MobV2CAO::MobV2CAO(IGameDef *gamedef, ClientEnvironment *env):
1285         ClientActiveObject(0, gamedef, env),
1286         m_selection_box(-0.4*BS,-0.4*BS,-0.4*BS, 0.4*BS,0.8*BS,0.4*BS),
1287         m_node(NULL),
1288         m_position(v3f(0,10*BS,0)),
1289         m_yaw(0),
1290         m_walking(false),
1291         m_walking_unset_timer(0),
1292         m_walk_timer(0),
1293         m_walk_frame(0),
1294         m_damage_visual_timer(0),
1295         m_last_light(0),
1296         m_shooting(0),
1297         m_shooting_unset_timer(0),
1298         m_sprite_size(BS,BS),
1299         m_sprite_y(0),
1300         m_bright_shooting(false),
1301         m_lock_full_brightness(false),
1302         m_player_hit_timer(0)
1303 {
1304         ClientActiveObject::registerType(getType(), create);
1305
1306         m_properties = new Settings;
1307 }
1308
1309 MobV2CAO::~MobV2CAO()
1310 {
1311         delete m_properties;
1312 }
1313
1314 ClientActiveObject* MobV2CAO::create(IGameDef *gamedef, ClientEnvironment *env)
1315 {
1316         return new MobV2CAO(gamedef, env);
1317 }
1318
1319 void MobV2CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
1320                         IrrlichtDevice *irr)
1321 {
1322         if(m_node != NULL)
1323                 return;
1324         
1325         /*infostream<<"MobV2CAO::addToScene using texture_name="<<
1326                         m_texture_name<<std::endl;*/
1327         std::string texture_string = m_texture_name +
1328                         "^[makealpha:128,0,0^[makealpha:128,128,0";
1329         
1330         scene::IBillboardSceneNode *bill = smgr->addBillboardSceneNode(
1331                         NULL, v2f(1, 1), v3f(0,0,0), -1);
1332         bill->setMaterialTexture(0, tsrc->getTextureRaw(texture_string));
1333         bill->setMaterialFlag(video::EMF_LIGHTING, false);
1334         bill->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
1335         bill->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
1336         bill->setMaterialFlag(video::EMF_FOG_ENABLE, true);
1337         bill->setColor(video::SColor(255,0,0,0));
1338         bill->setVisible(false); /* Set visible when brightness is known */
1339         bill->setSize(m_sprite_size);
1340         if(m_sprite_type == "humanoid_1"){
1341                 const float txp = 1./192;
1342                 const float txs = txp*32;
1343                 const float typ = 1./240;
1344                 const float tys = typ*48;
1345                 setBillboardTextureMatrix(bill, txs, tys, 0, 0);
1346         } else if(m_sprite_type == "simple"){
1347                 const float txs = 1.0;
1348                 const float tys = 1.0 / m_simple_anim_frames;
1349                 setBillboardTextureMatrix(bill, txs, tys, 0, 0);
1350         } else {
1351                 infostream<<"MobV2CAO: Unknown sprite type \""<<m_sprite_type<<"\""
1352                                 <<std::endl;
1353         }
1354
1355         m_node = bill;
1356
1357         updateNodePos();
1358 }
1359
1360 void MobV2CAO::removeFromScene()
1361 {
1362         if(m_node == NULL)
1363                 return;
1364
1365         m_node->remove();
1366         m_node = NULL;
1367 }
1368
1369 void MobV2CAO::updateLight(u8 light_at_pos)
1370 {
1371         if(m_lock_full_brightness)
1372                 light_at_pos = 15;
1373         
1374         m_last_light = light_at_pos;
1375
1376         if(m_node == NULL)
1377                 return;
1378         
1379         if(m_damage_visual_timer > 0)
1380                 return;
1381         
1382         if(m_shooting && m_bright_shooting)
1383                 return;
1384         
1385         /*if(light_at_pos <= 2){
1386                 m_node->setVisible(false);
1387                 return;
1388         }*/
1389
1390         m_node->setVisible(true);
1391
1392         u8 li = decode_light(light_at_pos);
1393         video::SColor color(255,li,li,li);
1394         m_node->setColor(color);
1395 }
1396
1397 v3s16 MobV2CAO::getLightPosition()
1398 {
1399         return floatToInt(m_position+v3f(0,0,0), BS);
1400 }
1401
1402 void MobV2CAO::updateNodePos()
1403 {
1404         if(m_node == NULL)
1405                 return;
1406
1407         m_node->setPosition(pos_translator.vect_show + v3f(0,m_sprite_y,0));
1408 }
1409
1410 void MobV2CAO::step(float dtime, ClientEnvironment *env)
1411 {
1412         scene::IBillboardSceneNode *bill = m_node;
1413         if(!bill)
1414                 return;
1415
1416         pos_translator.translate(dtime);
1417         
1418         if(m_sprite_type == "humanoid_1"){
1419                 scene::ICameraSceneNode* camera = m_node->getSceneManager()->getActiveCamera();
1420                 if(!camera)
1421                         return;
1422                 v3f cam_to_mob = m_node->getAbsolutePosition() - camera->getAbsolutePosition();
1423                 cam_to_mob.normalize();
1424                 int col = 0;
1425                 if(cam_to_mob.Y > 0.75)
1426                         col = 5;
1427                 else if(cam_to_mob.Y < -0.75)
1428                         col = 4;
1429                 else{
1430                         float mob_dir = atan2(cam_to_mob.Z, cam_to_mob.X) / PI * 180.;
1431                         float dir = mob_dir - m_yaw;
1432                         dir = wrapDegrees_180(dir);
1433                         //infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
1434                         if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
1435                                 col = 2;
1436                         else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
1437                                 col = 3;
1438                         else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
1439                                 col = 0;
1440                         else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
1441                                 col = 1;
1442                         else
1443                                 col = 4;
1444                 }
1445
1446                 int row = 0;
1447                 if(m_shooting){
1448                         row = 3;
1449                 } else if(m_walking){
1450                         m_walk_timer += dtime;
1451                         if(m_walk_timer >= 0.5){
1452                                 m_walk_frame = (m_walk_frame + 1) % 2;
1453                                 m_walk_timer = 0;
1454                         }
1455                         if(m_walk_frame == 0)
1456                                 row = 1;
1457                         else
1458                                 row = 2;
1459                 }
1460
1461                 const float txp = 1./192;
1462                 const float txs = txp*32;
1463                 const float typ = 1./240;
1464                 const float tys = typ*48;
1465                 setBillboardTextureMatrix(bill, txs, tys, col, row);
1466         } else if(m_sprite_type == "simple"){
1467                 m_walk_timer += dtime;
1468                 if(m_walk_timer >= m_simple_anim_frametime){
1469                         m_walk_frame = (m_walk_frame + 1) % m_simple_anim_frames;
1470                         m_walk_timer = 0;
1471                 }
1472                 int col = 0;
1473                 int row = m_walk_frame;
1474                 const float txs = 1.0;
1475                 const float tys = 1.0 / m_simple_anim_frames;
1476                 setBillboardTextureMatrix(bill, txs, tys, col, row);
1477         } else {
1478                 infostream<<"MobV2CAO::step(): Unknown sprite type \""
1479                                 <<m_sprite_type<<"\""<<std::endl;
1480         }
1481
1482         updateNodePos();
1483
1484         /* Damage local player */
1485         if(m_player_hit_damage && m_player_hit_timer <= 0.0){
1486                 LocalPlayer *player = env->getLocalPlayer();
1487                 assert(player);
1488                 
1489                 v3f playerpos = player->getPosition();
1490                 v2f playerpos_2d(playerpos.X,playerpos.Z);
1491                 v2f objectpos_2d(m_position.X,m_position.Z);
1492
1493                 if(fabs(m_position.Y - playerpos.Y) < m_player_hit_distance*BS &&
1494                 objectpos_2d.getDistanceFrom(playerpos_2d) < m_player_hit_distance*BS)
1495                 {
1496                         env->damageLocalPlayer(m_player_hit_damage);
1497                         m_player_hit_timer = m_player_hit_interval;
1498                 }
1499         }
1500
1501         /* Run timers */
1502
1503         m_player_hit_timer -= dtime;
1504
1505         if(m_damage_visual_timer >= 0){
1506                 m_damage_visual_timer -= dtime;
1507                 if(m_damage_visual_timer <= 0){
1508                         infostream<<"id="<<m_id<<" damage visual ended"<<std::endl;
1509                 }
1510         }
1511
1512         m_walking_unset_timer += dtime;
1513         if(m_walking_unset_timer >= 1.0){
1514                 m_walking = false;
1515         }
1516
1517         m_shooting_unset_timer -= dtime;
1518         if(m_shooting_unset_timer <= 0.0){
1519                 if(m_bright_shooting){
1520                         u8 li = decode_light(m_last_light);
1521                         video::SColor color(255,li,li,li);
1522                         bill->setColor(color);
1523                         m_bright_shooting = false;
1524                 }
1525                 m_shooting = false;
1526         }
1527
1528 }
1529
1530 void MobV2CAO::processMessage(const std::string &data)
1531 {
1532         //infostream<<"MobV2CAO: Got message"<<std::endl;
1533         std::istringstream is(data, std::ios::binary);
1534         // command
1535         u8 cmd = readU8(is);
1536
1537         // Move
1538         if(cmd == 0)
1539         {
1540                 // pos
1541                 m_position = readV3F1000(is);
1542                 pos_translator.update(m_position);
1543                 // yaw
1544                 m_yaw = readF1000(is);
1545
1546                 m_walking = true;
1547                 m_walking_unset_timer = 0;
1548
1549                 updateNodePos();
1550         }
1551         // Damage
1552         else if(cmd == 1)
1553         {
1554                 //u16 damage = readU16(is);
1555
1556                 /*u8 li = decode_light(m_last_light);
1557                 if(li >= 100)
1558                         li = 30;
1559                 else
1560                         li = 255;*/
1561
1562                 /*video::SColor color(255,255,0,0);
1563                 m_node->setColor(color);
1564
1565                 m_damage_visual_timer = 0.2;*/
1566         }
1567         // Trigger shooting
1568         else if(cmd == 2)
1569         {
1570                 // length
1571                 m_shooting_unset_timer = readF1000(is);
1572                 // bright?
1573                 m_bright_shooting = readU8(is);
1574                 if(m_bright_shooting){
1575                         u8 li = 255;
1576                         video::SColor color(255,li,li,li);
1577                         m_node->setColor(color);
1578                 }
1579
1580                 m_shooting = true;
1581         }
1582 }
1583
1584 void MobV2CAO::initialize(const std::string &data)
1585 {
1586         //infostream<<"MobV2CAO: Got init data"<<std::endl;
1587         
1588         {
1589                 std::istringstream is(data, std::ios::binary);
1590                 // version
1591                 u8 version = readU8(is);
1592                 // check version
1593                 if(version != 0){
1594                         infostream<<__FUNCTION_NAME<<": Invalid version"<<std::endl;
1595                         return;
1596                 }
1597                 
1598                 std::ostringstream tmp_os(std::ios::binary);
1599                 decompressZlib(is, tmp_os);
1600                 std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
1601                 m_properties->parseConfigLines(tmp_is, "MobArgsEnd");
1602
1603                 infostream<<"MobV2CAO::initialize(): got properties:"<<std::endl;
1604                 m_properties->writeLines(infostream);
1605                 
1606                 m_properties->setDefault("looks", "dummy_default");
1607                 m_properties->setDefault("yaw", "0");
1608                 m_properties->setDefault("pos", "(0,0,0)");
1609                 m_properties->setDefault("player_hit_damage", "0");
1610                 m_properties->setDefault("player_hit_distance", "1.5");
1611                 m_properties->setDefault("player_hit_interval", "1.5");
1612                 
1613                 setLooks(m_properties->get("looks"));
1614                 m_yaw = m_properties->getFloat("yaw");
1615                 m_position = m_properties->getV3F("pos");
1616                 m_player_hit_damage = m_properties->getS32("player_hit_damage");
1617                 m_player_hit_distance = m_properties->getFloat("player_hit_distance");
1618                 m_player_hit_interval = m_properties->getFloat("player_hit_interval");
1619
1620                 pos_translator.init(m_position);
1621         }
1622         
1623         updateNodePos();
1624 }
1625
1626 bool MobV2CAO::directReportPunch(const std::string &toolname, v3f dir)
1627 {
1628         video::SColor color(255,255,0,0);
1629         m_node->setColor(color);
1630
1631         m_damage_visual_timer = 0.05;
1632
1633         m_position += dir * BS;
1634         pos_translator.sharpen();
1635         pos_translator.update(m_position);
1636         updateNodePos();
1637         
1638         return false;
1639 }
1640
1641 void MobV2CAO::setLooks(const std::string &looks)
1642 {
1643         v2f selection_size = v2f(0.4, 0.4) * BS;
1644         float selection_y = 0 * BS;
1645
1646         if(looks == "dungeon_master"){
1647                 m_texture_name = "dungeon_master.png";
1648                 m_sprite_type = "humanoid_1";
1649                 m_sprite_size = v2f(2, 3) * BS;
1650                 m_sprite_y = 0.85 * BS;
1651                 selection_size = v2f(0.4, 2.6) * BS;
1652                 selection_y = -0.4 * BS;
1653         }
1654         else if(looks == "fireball"){
1655                 m_texture_name = "fireball.png";
1656                 m_sprite_type = "simple";
1657                 m_sprite_size = v2f(1, 1) * BS;
1658                 m_simple_anim_frames = 3;
1659                 m_simple_anim_frametime = 0.1;
1660                 m_lock_full_brightness = true;
1661         }
1662         else{
1663                 m_texture_name = "stone.png";
1664                 m_sprite_type = "simple";
1665                 m_sprite_size = v2f(1, 1) * BS;
1666                 m_simple_anim_frames = 3;
1667                 m_simple_anim_frametime = 0.333;
1668                 selection_size = v2f(0.4, 0.4) * BS;
1669                 selection_y = 0 * BS;
1670         }
1671
1672         m_selection_box = core::aabbox3d<f32>(
1673                         -selection_size.X, selection_y, -selection_size.X,
1674                         selection_size.X, selection_y+selection_size.Y,
1675                         selection_size.X);
1676 }
1677
1678 /*
1679         LuaEntityCAO
1680 */
1681
1682 #include "luaentity_common.h"
1683
1684 class LuaEntityCAO : public ClientActiveObject
1685 {
1686 private:
1687         core::aabbox3d<f32> m_selection_box;
1688         scene::IMeshSceneNode *m_meshnode;
1689         scene::IBillboardSceneNode *m_spritenode;
1690         v3f m_position;
1691         v3f m_velocity;
1692         v3f m_acceleration;
1693         float m_yaw;
1694         struct LuaEntityProperties *m_prop;
1695         SmoothTranslator pos_translator;
1696         // Spritesheet/animation stuff
1697         v2f m_tx_size;
1698         v2s16 m_tx_basepos;
1699         bool m_tx_select_horiz_by_yawpitch;
1700         int m_anim_frame;
1701         int m_anim_num_frames;
1702         float m_anim_framelength;
1703         float m_anim_timer;
1704
1705 public:
1706         LuaEntityCAO(IGameDef *gamedef, ClientEnvironment *env):
1707                 ClientActiveObject(0, gamedef, env),
1708                 m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
1709                 m_meshnode(NULL),
1710                 m_spritenode(NULL),
1711                 m_position(v3f(0,10*BS,0)),
1712                 m_velocity(v3f(0,0,0)),
1713                 m_acceleration(v3f(0,0,0)),
1714                 m_yaw(0),
1715                 m_prop(new LuaEntityProperties),
1716                 m_tx_size(1,1),
1717                 m_tx_basepos(0,0),
1718                 m_tx_select_horiz_by_yawpitch(false),
1719                 m_anim_frame(0),
1720                 m_anim_num_frames(1),
1721                 m_anim_framelength(0.2),
1722                 m_anim_timer(0)
1723         {
1724                 if(gamedef == NULL)
1725                         ClientActiveObject::registerType(getType(), create);
1726         }
1727
1728         void initialize(const std::string &data)
1729         {
1730                 infostream<<"LuaEntityCAO: Got init data"<<std::endl;
1731                 
1732                 std::istringstream is(data, std::ios::binary);
1733                 // version
1734                 u8 version = readU8(is);
1735                 // check version
1736                 if(version != 0)
1737                         return;
1738                 // pos
1739                 m_position = readV3F1000(is);
1740                 // yaw
1741                 m_yaw = readF1000(is);
1742                 // properties
1743                 std::istringstream prop_is(deSerializeLongString(is), std::ios::binary);
1744                 m_prop->deSerialize(prop_is);
1745
1746                 infostream<<"m_prop: "<<m_prop->dump()<<std::endl;
1747
1748                 m_selection_box = m_prop->collisionbox;
1749                 m_selection_box.MinEdge *= BS;
1750                 m_selection_box.MaxEdge *= BS;
1751                         
1752                 pos_translator.init(m_position);
1753
1754                 m_tx_size.X = 1.0 / m_prop->spritediv.X;
1755                 m_tx_size.Y = 1.0 / m_prop->spritediv.Y;
1756                 m_tx_basepos.X = m_tx_size.X * m_prop->initial_sprite_basepos.X;
1757                 m_tx_basepos.Y = m_tx_size.Y * m_prop->initial_sprite_basepos.Y;
1758                 
1759                 updateNodePos();
1760         }
1761
1762         ~LuaEntityCAO()
1763         {
1764                 delete m_prop;
1765         }
1766
1767         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
1768         {
1769                 return new LuaEntityCAO(gamedef, env);
1770         }
1771
1772         u8 getType() const
1773         {
1774                 return ACTIVEOBJECT_TYPE_LUAENTITY;
1775         }
1776         core::aabbox3d<f32>* getSelectionBox()
1777         {
1778                 return &m_selection_box;
1779         }
1780         v3f getPosition()
1781         {
1782                 return pos_translator.vect_show;
1783         }
1784                 
1785         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
1786                         IrrlichtDevice *irr)
1787         {
1788                 if(m_meshnode != NULL || m_spritenode != NULL)
1789                         return;
1790                 
1791                 //video::IVideoDriver* driver = smgr->getVideoDriver();
1792
1793                 if(m_prop->visual == "sprite"){
1794                         infostream<<"LuaEntityCAO::addToScene(): single_sprite"<<std::endl;
1795                         m_spritenode = smgr->addBillboardSceneNode(
1796                                         NULL, v2f(1, 1), v3f(0,0,0), -1);
1797                         m_spritenode->setMaterialTexture(0,
1798                                         tsrc->getTextureRaw("unknown_block.png"));
1799                         m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
1800                         m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
1801                         m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
1802                         m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
1803                         m_spritenode->setColor(video::SColor(255,0,0,0));
1804                         m_spritenode->setVisible(false); /* Set visible when brightness is known */
1805                         m_spritenode->setSize(m_prop->visual_size*BS);
1806                         {
1807                                 const float txs = 1.0 / 1;
1808                                 const float tys = 1.0 / 1;
1809                                 setBillboardTextureMatrix(m_spritenode,
1810                                                 txs, tys, 0, 0);
1811                         }
1812                 } else if(m_prop->visual == "cube"){
1813                         infostream<<"LuaEntityCAO::addToScene(): cube"<<std::endl;
1814                         scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
1815                         m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
1816                         mesh->drop();
1817                         
1818                         m_meshnode->setScale(v3f(1));
1819                         // Will be shown when we know the brightness
1820                         m_meshnode->setVisible(false);
1821                 } else {
1822                         infostream<<"LuaEntityCAO::addToScene(): \""<<m_prop->visual
1823                                         <<"\" not supported"<<std::endl;
1824                 }
1825                 updateTextures("");
1826                 updateNodePos();
1827         }
1828
1829         void removeFromScene()
1830         {
1831                 if(m_meshnode){
1832                         m_meshnode->remove();
1833                         m_meshnode = NULL;
1834                 }
1835                 if(m_spritenode){
1836                         m_spritenode->remove();
1837                         m_spritenode = NULL;
1838                 }
1839         }
1840
1841         void updateLight(u8 light_at_pos)
1842         {
1843                 u8 li = decode_light(light_at_pos);
1844                 video::SColor color(255,li,li,li);
1845                 if(m_meshnode){
1846                         setMeshColor(m_meshnode->getMesh(), color);
1847                         m_meshnode->setVisible(true);
1848                 }
1849                 if(m_spritenode){
1850                         m_spritenode->setColor(color);
1851                         m_spritenode->setVisible(true);
1852                 }
1853         }
1854
1855         v3s16 getLightPosition()
1856         {
1857                 return floatToInt(m_position, BS);
1858         }
1859
1860         void updateNodePos()
1861         {
1862                 if(m_meshnode){
1863                         m_meshnode->setPosition(pos_translator.vect_show);
1864                 }
1865                 if(m_spritenode){
1866                         m_spritenode->setPosition(pos_translator.vect_show);
1867                 }
1868         }
1869
1870         void step(float dtime, ClientEnvironment *env)
1871         {
1872                 if(m_prop->physical){
1873                         core::aabbox3d<f32> box = m_prop->collisionbox;
1874                         box.MinEdge *= BS;
1875                         box.MaxEdge *= BS;
1876                         collisionMoveResult moveresult;
1877                         f32 pos_max_d = BS*0.25; // Distance per iteration
1878                         v3f p_pos = m_position;
1879                         v3f p_velocity = m_velocity;
1880                         IGameDef *gamedef = env->getGameDef();
1881                         moveresult = collisionMovePrecise(&env->getMap(), gamedef,
1882                                         pos_max_d, box, dtime, p_pos, p_velocity);
1883                         // Apply results
1884                         m_position = p_pos;
1885                         m_velocity = p_velocity;
1886                         
1887                         bool is_end_position = moveresult.collides;
1888                         pos_translator.update(m_position, is_end_position, dtime);
1889                         pos_translator.translate(dtime);
1890                         updateNodePos();
1891
1892                         m_velocity += dtime * m_acceleration;
1893                 } else {
1894                         m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
1895                         m_velocity += dtime * m_acceleration;
1896                         pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
1897                         pos_translator.translate(dtime);
1898                         updateNodePos();
1899                 }
1900
1901                 m_anim_timer += dtime;
1902                 if(m_anim_timer >= m_anim_framelength){
1903                         m_anim_timer -= m_anim_framelength;
1904                         m_anim_frame++;
1905                         if(m_anim_frame >= m_anim_num_frames)
1906                                 m_anim_frame = 0;
1907                 }
1908
1909                 updateTexturePos();
1910         }
1911
1912         void updateTexturePos()
1913         {
1914                 if(m_spritenode){
1915                         scene::ICameraSceneNode* camera =
1916                                         m_spritenode->getSceneManager()->getActiveCamera();
1917                         if(!camera)
1918                                 return;
1919                         v3f cam_to_entity = m_spritenode->getAbsolutePosition()
1920                                         - camera->getAbsolutePosition();
1921                         cam_to_entity.normalize();
1922
1923                         int row = m_tx_basepos.Y;
1924                         int col = m_tx_basepos.X;
1925                         
1926                         if(m_tx_select_horiz_by_yawpitch)
1927                         {
1928                                 if(cam_to_entity.Y > 0.75)
1929                                         col += 5;
1930                                 else if(cam_to_entity.Y < -0.75)
1931                                         col += 4;
1932                                 else{
1933                                         float mob_dir = atan2(cam_to_entity.Z, cam_to_entity.X) / PI * 180.;
1934                                         float dir = mob_dir - m_yaw;
1935                                         dir = wrapDegrees_180(dir);
1936                                         //infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
1937                                         if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
1938                                                 col += 2;
1939                                         else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
1940                                                 col += 3;
1941                                         else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
1942                                                 col += 0;
1943                                         else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
1944                                                 col += 1;
1945                                         else
1946                                                 col += 4;
1947                                 }
1948                         }
1949                         
1950                         // Animation goes downwards
1951                         row += m_anim_frame;
1952
1953                         float txs = m_tx_size.X;
1954                         float tys = m_tx_size.Y;
1955                         setBillboardTextureMatrix(m_spritenode,
1956                                         txs, tys, col, row);
1957                 }
1958         }
1959
1960         void updateTextures(const std::string &mod)
1961         {
1962                 ITextureSource *tsrc = m_gamedef->tsrc();
1963
1964                 if(m_spritenode){
1965                         std::string texturestring = "unknown_block.png";
1966                         if(m_prop->textures.size() >= 1)
1967                                 texturestring = m_prop->textures[0];
1968                         texturestring += mod;
1969                         m_spritenode->setMaterialTexture(0,
1970                                         tsrc->getTextureRaw(texturestring));
1971                 }
1972                 if(m_meshnode){
1973                         for (u32 i = 0; i < 6; ++i)
1974                         {
1975                                 std::string texturestring = "unknown_block.png";
1976                                 if(m_prop->textures.size() > i)
1977                                         texturestring = m_prop->textures[i];
1978                                 texturestring += mod;
1979                                 AtlasPointer ap = tsrc->getTexture(texturestring);
1980
1981                                 // Get the tile texture and atlas transformation
1982                                 video::ITexture* atlas = ap.atlas;
1983                                 v2f pos = ap.pos;
1984                                 v2f size = ap.size;
1985
1986                                 // Set material flags and texture
1987                                 video::SMaterial& material = m_meshnode->getMaterial(i);
1988                                 material.setFlag(video::EMF_LIGHTING, false);
1989                                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1990                                 material.setTexture(0, atlas);
1991                                 material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
1992                                 material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
1993                         }
1994                 }
1995         }
1996
1997         void processMessage(const std::string &data)
1998         {
1999                 //infostream<<"LuaEntityCAO: Got message"<<std::endl;
2000                 std::istringstream is(data, std::ios::binary);
2001                 // command
2002                 u8 cmd = readU8(is);
2003                 if(cmd == 0) // update position
2004                 {
2005                         // do_interpolate
2006                         bool do_interpolate = readU8(is);
2007                         // pos
2008                         m_position = readV3F1000(is);
2009                         // velocity
2010                         m_velocity = readV3F1000(is);
2011                         // acceleration
2012                         m_acceleration = readV3F1000(is);
2013                         // yaw
2014                         m_yaw = readF1000(is);
2015                         // is_end_position (for interpolation)
2016                         bool is_end_position = readU8(is);
2017                         // update_interval
2018                         float update_interval = readF1000(is);
2019                         
2020                         if(do_interpolate){
2021                                 if(!m_prop->physical)
2022                                         pos_translator.update(m_position, is_end_position, update_interval);
2023                         } else {
2024                                 pos_translator.init(m_position);
2025                         }
2026                         updateNodePos();
2027                 }
2028                 else if(cmd == 1) // set texture modification
2029                 {
2030                         std::string mod = deSerializeString(is);
2031                         updateTextures(mod);
2032                 }
2033                 else if(cmd == 2) // set sprite
2034                 {
2035                         v2s16 p = readV2S16(is);
2036                         int num_frames = readU16(is);
2037                         float framelength = readF1000(is);
2038                         bool select_horiz_by_yawpitch = readU8(is);
2039                         
2040                         m_tx_basepos = p;
2041                         m_anim_num_frames = num_frames;
2042                         m_anim_framelength = framelength;
2043                         m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch;
2044
2045                         updateTexturePos();
2046                 }
2047         }
2048 };
2049
2050 // Prototype
2051 LuaEntityCAO proto_LuaEntityCAO(NULL, NULL);
2052
2053 /*
2054         PlayerCAO
2055 */
2056
2057 class PlayerCAO : public ClientActiveObject
2058 {
2059 private:
2060         core::aabbox3d<f32> m_selection_box;
2061         scene::IMeshSceneNode *m_node;
2062         scene::ITextSceneNode* m_text;
2063         std::string m_name;
2064         v3f m_position;
2065         float m_yaw;
2066         SmoothTranslator pos_translator;
2067         bool m_is_local_player;
2068         LocalPlayer *m_local_player;
2069         float m_damage_visual_timer;
2070         bool m_dead;
2071
2072 public:
2073         PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
2074                 ClientActiveObject(0, gamedef, env),
2075                 m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.0,BS/3.),
2076                 m_node(NULL),
2077                 m_text(NULL),
2078                 m_position(v3f(0,10*BS,0)),
2079                 m_yaw(0),
2080                 m_is_local_player(false),
2081                 m_local_player(NULL),
2082                 m_damage_visual_timer(0),
2083                 m_dead(false)
2084         {
2085                 if(gamedef == NULL)
2086                         ClientActiveObject::registerType(getType(), create);
2087         }
2088
2089         void initialize(const std::string &data)
2090         {
2091                 infostream<<"PlayerCAO: Got init data"<<std::endl;
2092                 
2093                 std::istringstream is(data, std::ios::binary);
2094                 // version
2095                 u8 version = readU8(is);
2096                 // check version
2097                 if(version != 0)
2098                         return;
2099                 // name
2100                 m_name = deSerializeString(is);
2101                 // pos
2102                 m_position = readV3F1000(is);
2103                 // yaw
2104                 m_yaw = readF1000(is);
2105                 // dead
2106                 m_dead = readU8(is);
2107
2108                 pos_translator.init(m_position);
2109
2110                 Player *player = m_env->getPlayer(m_name.c_str());
2111                 if(player && player->isLocal()){
2112                         m_is_local_player = true;
2113                         m_local_player = (LocalPlayer*)player;
2114                 }
2115         }
2116
2117         ~PlayerCAO()
2118         {
2119                 if(m_node)
2120                         m_node->remove();
2121         }
2122
2123         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
2124         {
2125                 return new PlayerCAO(gamedef, env);
2126         }
2127
2128         u8 getType() const
2129         {
2130                 return ACTIVEOBJECT_TYPE_PLAYER;
2131         }
2132         core::aabbox3d<f32>* getSelectionBox()
2133         {
2134                 if(m_is_local_player)
2135                         return NULL;
2136                 if(m_dead)
2137                         return NULL;
2138                 return &m_selection_box;
2139         }
2140         v3f getPosition()
2141         {
2142                 return pos_translator.vect_show;
2143         }
2144                 
2145         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
2146                         IrrlichtDevice *irr)
2147         {
2148                 if(m_node != NULL)
2149                         return;
2150                 if(m_is_local_player)
2151                         return;
2152                 
2153                 //video::IVideoDriver* driver = smgr->getVideoDriver();
2154                 gui::IGUIEnvironment* gui = irr->getGUIEnvironment();
2155                 
2156                 scene::SMesh *mesh = new scene::SMesh();
2157                 { // Front
2158                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
2159                 video::SColor c(255,255,255,255);
2160                 video::S3DVertex vertices[4] =
2161                 {
2162                         video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
2163                         video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
2164                         video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
2165                         video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
2166                 };
2167                 u16 indices[] = {0,1,2,2,3,0};
2168                 buf->append(vertices, 4, indices, 6);
2169                 // Set material
2170                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
2171                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
2172                 buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
2173                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
2174                 // Add to mesh
2175                 mesh->addMeshBuffer(buf);
2176                 buf->drop();
2177                 }
2178                 { // Back
2179                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
2180                 video::SColor c(255,255,255,255);
2181                 video::S3DVertex vertices[4] =
2182                 {
2183                         video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
2184                         video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
2185                         video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
2186                         video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
2187                 };
2188                 u16 indices[] = {0,1,2,2,3,0};
2189                 buf->append(vertices, 4, indices, 6);
2190                 // Set material
2191                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
2192                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
2193                 buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
2194                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
2195                 // Add to mesh
2196                 mesh->addMeshBuffer(buf);
2197                 buf->drop();
2198                 }
2199                 m_node = smgr->addMeshSceneNode(mesh, NULL);
2200                 mesh->drop();
2201                 // Set it to use the materials of the meshbuffers directly.
2202                 // This is needed for changing the texture in the future
2203                 m_node->setReadOnlyMaterials(true);
2204                 updateNodePos();
2205
2206                 // Add a text node for showing the name
2207                 std::wstring wname = narrow_to_wide(m_name);
2208                 m_text = smgr->addTextSceneNode(gui->getBuiltInFont(),
2209                                 wname.c_str(), video::SColor(255,255,255,255), m_node);
2210                 m_text->setPosition(v3f(0, (f32)BS*2.1, 0));
2211                 
2212                 updateTextures("");
2213                 updateVisibility();
2214                 updateNodePos();
2215         }
2216
2217         void removeFromScene()
2218         {
2219                 if(m_node == NULL)
2220                         return;
2221
2222                 m_node->remove();
2223                 m_node = NULL;
2224         }
2225
2226         void updateLight(u8 light_at_pos)
2227         {
2228                 if(m_node == NULL)
2229                         return;
2230                 
2231                 u8 li = decode_light(light_at_pos);
2232                 video::SColor color(255,li,li,li);
2233                 setMeshColor(m_node->getMesh(), color);
2234
2235                 updateVisibility();
2236         }
2237
2238         v3s16 getLightPosition()
2239         {
2240                 return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
2241         }
2242
2243         void updateVisibility()
2244         {
2245                 if(m_node == NULL)
2246                         return;
2247
2248                 m_node->setVisible(!m_dead);
2249         }
2250
2251         void updateNodePos()
2252         {
2253                 if(m_node == NULL)
2254                         return;
2255
2256                 m_node->setPosition(pos_translator.vect_show);
2257
2258                 v3f rot = m_node->getRotation();
2259                 rot.Y = -m_yaw;
2260                 m_node->setRotation(rot);
2261         }
2262
2263         void step(float dtime, ClientEnvironment *env)
2264         {
2265                 pos_translator.translate(dtime);
2266                 updateVisibility();
2267                 updateNodePos();
2268
2269                 if(m_damage_visual_timer > 0){
2270                         m_damage_visual_timer -= dtime;
2271                         if(m_damage_visual_timer <= 0){
2272                                 updateTextures("");
2273                         }
2274                 }
2275         }
2276
2277         void processMessage(const std::string &data)
2278         {
2279                 //infostream<<"PlayerCAO: Got message"<<std::endl;
2280                 std::istringstream is(data, std::ios::binary);
2281                 // command
2282                 u8 cmd = readU8(is);
2283                 if(cmd == 0) // update position
2284                 {
2285                         // pos
2286                         m_position = readV3F1000(is);
2287                         // yaw
2288                         m_yaw = readF1000(is);
2289
2290                         pos_translator.update(m_position, false);
2291
2292                         updateNodePos();
2293                 }
2294                 else if(cmd == 1) // punched
2295                 {
2296                         // damage
2297                         s16 damage = readS16(is);
2298                         m_damage_visual_timer = 0.05;
2299                         if(damage >= 2)
2300                                 m_damage_visual_timer += 0.05 * damage;
2301                         updateTextures("^[brighten");
2302                 }
2303                 else if(cmd == 2) // died or respawned
2304                 {
2305                         m_dead = readU8(is);
2306                         updateVisibility();
2307                 }
2308         }
2309
2310         void updateTextures(const std::string &mod)
2311         {
2312                 if(!m_node)
2313                         return;
2314                 ITextureSource *tsrc = m_gamedef->tsrc();
2315                 scene::IMesh *mesh = m_node->getMesh();
2316                 if(mesh){
2317                         {
2318                                 std::string tname = "player.png";
2319                                 tname += mod;
2320                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
2321                                 buf->getMaterial().setTexture(0,
2322                                                 tsrc->getTextureRaw(tname));
2323                         }
2324                         {
2325                                 std::string tname = "player_back.png";
2326                                 tname += mod;
2327                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
2328                                 buf->getMaterial().setTexture(0,
2329                                                 tsrc->getTextureRaw(tname));
2330                         }
2331                 }
2332         }
2333 };
2334
2335 // Prototype
2336 PlayerCAO proto_PlayerCAO(NULL, NULL);
2337
2338