Entity damage system WIP; Remove C++ mobs
[oweals/minetest.git] / src / content_cao.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "content_cao.h"
21 #include "tile.h"
22 #include "environment.h"
23 #include "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         Other stuff
121 */
122
123 static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
124                 float txs, float tys, int col, int row)
125 {
126         video::SMaterial& material = bill->getMaterial(0);
127         core::matrix4& matrix = material.getTextureMatrix(0);
128         matrix.setTextureTranslate(txs*col, tys*row);
129         matrix.setTextureScale(txs, tys);
130 }
131
132 /*
133         TestCAO
134 */
135
136 class TestCAO : public ClientActiveObject
137 {
138 public:
139         TestCAO(IGameDef *gamedef, ClientEnvironment *env);
140         virtual ~TestCAO();
141         
142         u8 getType() const
143         {
144                 return ACTIVEOBJECT_TYPE_TEST;
145         }
146         
147         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
148
149         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
150                         IrrlichtDevice *irr);
151         void removeFromScene();
152         void updateLight(u8 light_at_pos);
153         v3s16 getLightPosition();
154         void updateNodePos();
155
156         void step(float dtime, ClientEnvironment *env);
157
158         void processMessage(const std::string &data);
159
160 private:
161         scene::IMeshSceneNode *m_node;
162         v3f m_position;
163 };
164
165 /*
166         ItemCAO
167 */
168
169 class ItemCAO : public ClientActiveObject
170 {
171 public:
172         ItemCAO(IGameDef *gamedef, ClientEnvironment *env);
173         virtual ~ItemCAO();
174         
175         u8 getType() const
176         {
177                 return ACTIVEOBJECT_TYPE_ITEM;
178         }
179         
180         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
181
182         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
183                         IrrlichtDevice *irr);
184         void removeFromScene();
185         void updateLight(u8 light_at_pos);
186         v3s16 getLightPosition();
187         void updateNodePos();
188         void updateInfoText();
189         void updateTexture();
190
191         void step(float dtime, ClientEnvironment *env);
192
193         void processMessage(const std::string &data);
194
195         void initialize(const std::string &data);
196         
197         core::aabbox3d<f32>* getSelectionBox()
198                 {return &m_selection_box;}
199         v3f getPosition()
200                 {return m_position;}
201         
202         std::string infoText()
203                 {return m_infotext;}
204
205 private:
206         core::aabbox3d<f32> m_selection_box;
207         scene::IMeshSceneNode *m_node;
208         v3f m_position;
209         std::string m_itemstring;
210         std::string m_infotext;
211 };
212
213 /*
214         LuaEntityCAO
215 */
216
217 #include "luaentity_common.h"
218
219 class LuaEntityCAO : public ClientActiveObject
220 {
221 private:
222         core::aabbox3d<f32> m_selection_box;
223         scene::IMeshSceneNode *m_meshnode;
224         scene::IBillboardSceneNode *m_spritenode;
225         v3f m_position;
226         v3f m_velocity;
227         v3f m_acceleration;
228         float m_yaw;
229         s16 m_hp;
230         struct LuaEntityProperties *m_prop;
231         SmoothTranslator pos_translator;
232         // Spritesheet/animation stuff
233         v2f m_tx_size;
234         v2s16 m_tx_basepos;
235         bool m_tx_select_horiz_by_yawpitch;
236         int m_anim_frame;
237         int m_anim_num_frames;
238         float m_anim_framelength;
239         float m_anim_timer;
240
241 public:
242         LuaEntityCAO(IGameDef *gamedef, ClientEnvironment *env):
243                 ClientActiveObject(0, gamedef, env),
244                 m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
245                 m_meshnode(NULL),
246                 m_spritenode(NULL),
247                 m_position(v3f(0,10*BS,0)),
248                 m_velocity(v3f(0,0,0)),
249                 m_acceleration(v3f(0,0,0)),
250                 m_yaw(0),
251                 m_hp(1),
252                 m_prop(new LuaEntityProperties),
253                 m_tx_size(1,1),
254                 m_tx_basepos(0,0),
255                 m_tx_select_horiz_by_yawpitch(false),
256                 m_anim_frame(0),
257                 m_anim_num_frames(1),
258                 m_anim_framelength(0.2),
259                 m_anim_timer(0)
260         {
261                 if(gamedef == NULL)
262                         ClientActiveObject::registerType(getType(), create);
263         }
264
265         void initialize(const std::string &data)
266         {
267                 infostream<<"LuaEntityCAO: Got init data"<<std::endl;
268                 
269                 std::istringstream is(data, std::ios::binary);
270                 // version
271                 u8 version = readU8(is);
272                 // check version
273                 if(version != 1)
274                         return;
275                 // pos
276                 m_position = readV3F1000(is);
277                 // yaw
278                 m_yaw = readF1000(is);
279                 // hp
280                 m_hp = readS16(is);
281                 // properties
282                 std::istringstream prop_is(deSerializeLongString(is), std::ios::binary);
283                 m_prop->deSerialize(prop_is);
284
285                 infostream<<"m_prop: "<<m_prop->dump()<<std::endl;
286
287                 m_selection_box = m_prop->collisionbox;
288                 m_selection_box.MinEdge *= BS;
289                 m_selection_box.MaxEdge *= BS;
290                         
291                 pos_translator.init(m_position);
292
293                 m_tx_size.X = 1.0 / m_prop->spritediv.X;
294                 m_tx_size.Y = 1.0 / m_prop->spritediv.Y;
295                 m_tx_basepos.X = m_tx_size.X * m_prop->initial_sprite_basepos.X;
296                 m_tx_basepos.Y = m_tx_size.Y * m_prop->initial_sprite_basepos.Y;
297                 
298                 updateNodePos();
299         }
300
301         ~LuaEntityCAO()
302         {
303                 delete m_prop;
304         }
305
306         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
307         {
308                 return new LuaEntityCAO(gamedef, env);
309         }
310
311         u8 getType() const
312         {
313                 return ACTIVEOBJECT_TYPE_LUAENTITY;
314         }
315         core::aabbox3d<f32>* getSelectionBox()
316         {
317                 return &m_selection_box;
318         }
319         v3f getPosition()
320         {
321                 return pos_translator.vect_show;
322         }
323                 
324         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
325                         IrrlichtDevice *irr)
326         {
327                 if(m_meshnode != NULL || m_spritenode != NULL)
328                         return;
329                 
330                 //video::IVideoDriver* driver = smgr->getVideoDriver();
331
332                 if(m_prop->visual == "sprite"){
333                         infostream<<"LuaEntityCAO::addToScene(): single_sprite"<<std::endl;
334                         m_spritenode = smgr->addBillboardSceneNode(
335                                         NULL, v2f(1, 1), v3f(0,0,0), -1);
336                         m_spritenode->setMaterialTexture(0,
337                                         tsrc->getTextureRaw("unknown_block.png"));
338                         m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
339                         m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
340                         m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
341                         m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
342                         m_spritenode->setColor(video::SColor(255,0,0,0));
343                         m_spritenode->setVisible(false); /* Set visible when brightness is known */
344                         m_spritenode->setSize(m_prop->visual_size*BS);
345                         {
346                                 const float txs = 1.0 / 1;
347                                 const float tys = 1.0 / 1;
348                                 setBillboardTextureMatrix(m_spritenode,
349                                                 txs, tys, 0, 0);
350                         }
351                 } else if(m_prop->visual == "cube"){
352                         infostream<<"LuaEntityCAO::addToScene(): cube"<<std::endl;
353                         scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
354                         m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
355                         mesh->drop();
356                         
357                         m_meshnode->setScale(v3f(1));
358                         // Will be shown when we know the brightness
359                         m_meshnode->setVisible(false);
360                 } else {
361                         infostream<<"LuaEntityCAO::addToScene(): \""<<m_prop->visual
362                                         <<"\" not supported"<<std::endl;
363                 }
364                 updateTextures("");
365                 updateNodePos();
366         }
367
368         void removeFromScene()
369         {
370                 if(m_meshnode){
371                         m_meshnode->remove();
372                         m_meshnode = NULL;
373                 }
374                 if(m_spritenode){
375                         m_spritenode->remove();
376                         m_spritenode = NULL;
377                 }
378         }
379
380         void updateLight(u8 light_at_pos)
381         {
382                 u8 li = decode_light(light_at_pos);
383                 video::SColor color(255,li,li,li);
384                 if(m_meshnode){
385                         setMeshColor(m_meshnode->getMesh(), color);
386                         m_meshnode->setVisible(true);
387                 }
388                 if(m_spritenode){
389                         m_spritenode->setColor(color);
390                         m_spritenode->setVisible(true);
391                 }
392         }
393
394         v3s16 getLightPosition()
395         {
396                 return floatToInt(m_position, BS);
397         }
398
399         void updateNodePos()
400         {
401                 if(m_meshnode){
402                         m_meshnode->setPosition(pos_translator.vect_show);
403                 }
404                 if(m_spritenode){
405                         m_spritenode->setPosition(pos_translator.vect_show);
406                 }
407         }
408
409         void step(float dtime, ClientEnvironment *env)
410         {
411                 if(m_prop->physical){
412                         core::aabbox3d<f32> box = m_prop->collisionbox;
413                         box.MinEdge *= BS;
414                         box.MaxEdge *= BS;
415                         collisionMoveResult moveresult;
416                         f32 pos_max_d = BS*0.25; // Distance per iteration
417                         v3f p_pos = m_position;
418                         v3f p_velocity = m_velocity;
419                         IGameDef *gamedef = env->getGameDef();
420                         moveresult = collisionMovePrecise(&env->getMap(), gamedef,
421                                         pos_max_d, box, dtime, p_pos, p_velocity);
422                         // Apply results
423                         m_position = p_pos;
424                         m_velocity = p_velocity;
425                         
426                         bool is_end_position = moveresult.collides;
427                         pos_translator.update(m_position, is_end_position, dtime);
428                         pos_translator.translate(dtime);
429                         updateNodePos();
430
431                         m_velocity += dtime * m_acceleration;
432                 } else {
433                         m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
434                         m_velocity += dtime * m_acceleration;
435                         pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time);
436                         pos_translator.translate(dtime);
437                         updateNodePos();
438                 }
439
440                 m_anim_timer += dtime;
441                 if(m_anim_timer >= m_anim_framelength){
442                         m_anim_timer -= m_anim_framelength;
443                         m_anim_frame++;
444                         if(m_anim_frame >= m_anim_num_frames)
445                                 m_anim_frame = 0;
446                 }
447
448                 updateTexturePos();
449         }
450
451         void updateTexturePos()
452         {
453                 if(m_spritenode){
454                         scene::ICameraSceneNode* camera =
455                                         m_spritenode->getSceneManager()->getActiveCamera();
456                         if(!camera)
457                                 return;
458                         v3f cam_to_entity = m_spritenode->getAbsolutePosition()
459                                         - camera->getAbsolutePosition();
460                         cam_to_entity.normalize();
461
462                         int row = m_tx_basepos.Y;
463                         int col = m_tx_basepos.X;
464                         
465                         if(m_tx_select_horiz_by_yawpitch)
466                         {
467                                 if(cam_to_entity.Y > 0.75)
468                                         col += 5;
469                                 else if(cam_to_entity.Y < -0.75)
470                                         col += 4;
471                                 else{
472                                         float mob_dir = atan2(cam_to_entity.Z, cam_to_entity.X) / PI * 180.;
473                                         float dir = mob_dir - m_yaw;
474                                         dir = wrapDegrees_180(dir);
475                                         //infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
476                                         if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
477                                                 col += 2;
478                                         else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
479                                                 col += 3;
480                                         else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
481                                                 col += 0;
482                                         else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
483                                                 col += 1;
484                                         else
485                                                 col += 4;
486                                 }
487                         }
488                         
489                         // Animation goes downwards
490                         row += m_anim_frame;
491
492                         float txs = m_tx_size.X;
493                         float tys = m_tx_size.Y;
494                         setBillboardTextureMatrix(m_spritenode,
495                                         txs, tys, col, row);
496                 }
497         }
498
499         void updateTextures(const std::string &mod)
500         {
501                 ITextureSource *tsrc = m_gamedef->tsrc();
502
503                 if(m_spritenode){
504                         std::string texturestring = "unknown_block.png";
505                         if(m_prop->textures.size() >= 1)
506                                 texturestring = m_prop->textures[0];
507                         texturestring += mod;
508                         m_spritenode->setMaterialTexture(0,
509                                         tsrc->getTextureRaw(texturestring));
510                 }
511                 if(m_meshnode){
512                         for (u32 i = 0; i < 6; ++i)
513                         {
514                                 std::string texturestring = "unknown_block.png";
515                                 if(m_prop->textures.size() > i)
516                                         texturestring = m_prop->textures[i];
517                                 texturestring += mod;
518                                 AtlasPointer ap = tsrc->getTexture(texturestring);
519
520                                 // Get the tile texture and atlas transformation
521                                 video::ITexture* atlas = ap.atlas;
522                                 v2f pos = ap.pos;
523                                 v2f size = ap.size;
524
525                                 // Set material flags and texture
526                                 video::SMaterial& material = m_meshnode->getMaterial(i);
527                                 material.setFlag(video::EMF_LIGHTING, false);
528                                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
529                                 material.setTexture(0, atlas);
530                                 material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
531                                 material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
532                         }
533                 }
534         }
535
536         void processMessage(const std::string &data)
537         {
538                 //infostream<<"LuaEntityCAO: Got message"<<std::endl;
539                 std::istringstream is(data, std::ios::binary);
540                 // command
541                 u8 cmd = readU8(is);
542                 if(cmd == LUAENTITY_CMD_UPDATE_POSITION) // update position
543                 {
544                         // do_interpolate
545                         bool do_interpolate = readU8(is);
546                         // pos
547                         m_position = readV3F1000(is);
548                         // velocity
549                         m_velocity = readV3F1000(is);
550                         // acceleration
551                         m_acceleration = readV3F1000(is);
552                         // yaw
553                         m_yaw = readF1000(is);
554                         // is_end_position (for interpolation)
555                         bool is_end_position = readU8(is);
556                         // update_interval
557                         float update_interval = readF1000(is);
558                         
559                         if(do_interpolate){
560                                 if(!m_prop->physical)
561                                         pos_translator.update(m_position, is_end_position, update_interval);
562                         } else {
563                                 pos_translator.init(m_position);
564                         }
565                         updateNodePos();
566                 }
567                 else if(cmd == LUAENTITY_CMD_SET_TEXTURE_MOD) // set texture modification
568                 {
569                         std::string mod = deSerializeString(is);
570                         updateTextures(mod);
571                 }
572                 else if(cmd == LUAENTITY_CMD_SET_SPRITE) // set sprite
573                 {
574                         v2s16 p = readV2S16(is);
575                         int num_frames = readU16(is);
576                         float framelength = readF1000(is);
577                         bool select_horiz_by_yawpitch = readU8(is);
578                         
579                         m_tx_basepos = p;
580                         m_anim_num_frames = num_frames;
581                         m_anim_framelength = framelength;
582                         m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch;
583
584                         updateTexturePos();
585                 }
586                 else if(cmd == LUAENTITY_CMD_PUNCHED)
587                 {
588                         s16 damage = readS16(is);
589                         s16 result_hp = readS16(is);
590                         
591                         m_hp = result_hp;
592                         // TODO: Execute defined fast response
593                 }
594         }
595 };
596
597 // Prototype
598 LuaEntityCAO proto_LuaEntityCAO(NULL, NULL);
599
600 /*
601         PlayerCAO
602 */
603
604 class PlayerCAO : public ClientActiveObject
605 {
606 private:
607         core::aabbox3d<f32> m_selection_box;
608         scene::IMeshSceneNode *m_node;
609         scene::ITextSceneNode* m_text;
610         std::string m_name;
611         v3f m_position;
612         float m_yaw;
613         SmoothTranslator pos_translator;
614         bool m_is_local_player;
615         LocalPlayer *m_local_player;
616         float m_damage_visual_timer;
617         bool m_dead;
618
619 public:
620         PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
621                 ClientActiveObject(0, gamedef, env),
622                 m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.0,BS/3.),
623                 m_node(NULL),
624                 m_text(NULL),
625                 m_position(v3f(0,10*BS,0)),
626                 m_yaw(0),
627                 m_is_local_player(false),
628                 m_local_player(NULL),
629                 m_damage_visual_timer(0),
630                 m_dead(false)
631         {
632                 if(gamedef == NULL)
633                         ClientActiveObject::registerType(getType(), create);
634         }
635
636         void initialize(const std::string &data)
637         {
638                 infostream<<"PlayerCAO: Got init data"<<std::endl;
639                 
640                 std::istringstream is(data, std::ios::binary);
641                 // version
642                 u8 version = readU8(is);
643                 // check version
644                 if(version != 0)
645                         return;
646                 // name
647                 m_name = deSerializeString(is);
648                 // pos
649                 m_position = readV3F1000(is);
650                 // yaw
651                 m_yaw = readF1000(is);
652                 // dead
653                 m_dead = readU8(is);
654
655                 pos_translator.init(m_position);
656
657                 Player *player = m_env->getPlayer(m_name.c_str());
658                 if(player && player->isLocal()){
659                         m_is_local_player = true;
660                         m_local_player = (LocalPlayer*)player;
661                 }
662         }
663
664         ~PlayerCAO()
665         {
666                 if(m_node)
667                         m_node->remove();
668         }
669
670         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env)
671         {
672                 return new PlayerCAO(gamedef, env);
673         }
674
675         u8 getType() const
676         {
677                 return ACTIVEOBJECT_TYPE_PLAYER;
678         }
679         core::aabbox3d<f32>* getSelectionBox()
680         {
681                 if(m_is_local_player)
682                         return NULL;
683                 if(m_dead)
684                         return NULL;
685                 return &m_selection_box;
686         }
687         v3f getPosition()
688         {
689                 return pos_translator.vect_show;
690         }
691                 
692         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
693                         IrrlichtDevice *irr)
694         {
695                 if(m_node != NULL)
696                         return;
697                 if(m_is_local_player)
698                         return;
699                 
700                 //video::IVideoDriver* driver = smgr->getVideoDriver();
701                 gui::IGUIEnvironment* gui = irr->getGUIEnvironment();
702                 
703                 scene::SMesh *mesh = new scene::SMesh();
704                 { // Front
705                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
706                 video::SColor c(255,255,255,255);
707                 video::S3DVertex vertices[4] =
708                 {
709                         video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
710                         video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
711                         video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
712                         video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
713                 };
714                 u16 indices[] = {0,1,2,2,3,0};
715                 buf->append(vertices, 4, indices, 6);
716                 // Set material
717                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
718                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
719                 buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
720                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
721                 // Add to mesh
722                 mesh->addMeshBuffer(buf);
723                 buf->drop();
724                 }
725                 { // Back
726                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
727                 video::SColor c(255,255,255,255);
728                 video::S3DVertex vertices[4] =
729                 {
730                         video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
731                         video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
732                         video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
733                         video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
734                 };
735                 u16 indices[] = {0,1,2,2,3,0};
736                 buf->append(vertices, 4, indices, 6);
737                 // Set material
738                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
739                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
740                 buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
741                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
742                 // Add to mesh
743                 mesh->addMeshBuffer(buf);
744                 buf->drop();
745                 }
746                 m_node = smgr->addMeshSceneNode(mesh, NULL);
747                 mesh->drop();
748                 // Set it to use the materials of the meshbuffers directly.
749                 // This is needed for changing the texture in the future
750                 m_node->setReadOnlyMaterials(true);
751                 updateNodePos();
752
753                 // Add a text node for showing the name
754                 std::wstring wname = narrow_to_wide(m_name);
755                 m_text = smgr->addTextSceneNode(gui->getBuiltInFont(),
756                                 wname.c_str(), video::SColor(255,255,255,255), m_node);
757                 m_text->setPosition(v3f(0, (f32)BS*2.1, 0));
758                 
759                 updateTextures("");
760                 updateVisibility();
761                 updateNodePos();
762         }
763
764         void removeFromScene()
765         {
766                 if(m_node == NULL)
767                         return;
768
769                 m_node->remove();
770                 m_node = NULL;
771         }
772
773         void updateLight(u8 light_at_pos)
774         {
775                 if(m_node == NULL)
776                         return;
777                 
778                 u8 li = decode_light(light_at_pos);
779                 video::SColor color(255,li,li,li);
780                 setMeshColor(m_node->getMesh(), color);
781
782                 updateVisibility();
783         }
784
785         v3s16 getLightPosition()
786         {
787                 return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
788         }
789
790         void updateVisibility()
791         {
792                 if(m_node == NULL)
793                         return;
794
795                 m_node->setVisible(!m_dead);
796         }
797
798         void updateNodePos()
799         {
800                 if(m_node == NULL)
801                         return;
802
803                 m_node->setPosition(pos_translator.vect_show);
804
805                 v3f rot = m_node->getRotation();
806                 rot.Y = -m_yaw;
807                 m_node->setRotation(rot);
808         }
809
810         void step(float dtime, ClientEnvironment *env)
811         {
812                 pos_translator.translate(dtime);
813                 updateVisibility();
814                 updateNodePos();
815
816                 if(m_damage_visual_timer > 0){
817                         m_damage_visual_timer -= dtime;
818                         if(m_damage_visual_timer <= 0){
819                                 updateTextures("");
820                         }
821                 }
822         }
823
824         void processMessage(const std::string &data)
825         {
826                 //infostream<<"PlayerCAO: Got message"<<std::endl;
827                 std::istringstream is(data, std::ios::binary);
828                 // command
829                 u8 cmd = readU8(is);
830                 if(cmd == 0) // update position
831                 {
832                         // pos
833                         m_position = readV3F1000(is);
834                         // yaw
835                         m_yaw = readF1000(is);
836
837                         pos_translator.update(m_position, false);
838
839                         updateNodePos();
840                 }
841                 else if(cmd == 1) // punched
842                 {
843                         // damage
844                         s16 damage = readS16(is);
845                         m_damage_visual_timer = 0.05;
846                         if(damage >= 2)
847                                 m_damage_visual_timer += 0.05 * damage;
848                         updateTextures("^[brighten");
849                 }
850                 else if(cmd == 2) // died or respawned
851                 {
852                         m_dead = readU8(is);
853                         updateVisibility();
854                 }
855         }
856
857         void updateTextures(const std::string &mod)
858         {
859                 if(!m_node)
860                         return;
861                 ITextureSource *tsrc = m_gamedef->tsrc();
862                 scene::IMesh *mesh = m_node->getMesh();
863                 if(mesh){
864                         {
865                                 std::string tname = "player.png";
866                                 tname += mod;
867                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
868                                 buf->getMaterial().setTexture(0,
869                                                 tsrc->getTextureRaw(tname));
870                         }
871                         {
872                                 std::string tname = "player_back.png";
873                                 tname += mod;
874                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
875                                 buf->getMaterial().setTexture(0,
876                                                 tsrc->getTextureRaw(tname));
877                         }
878                 }
879         }
880 };
881
882 // Prototype
883 PlayerCAO proto_PlayerCAO(NULL, NULL);
884
885