Entity damage system WIP; Remove C++ mobs
authorPerttu Ahola <celeron55@gmail.com>
Sun, 4 Mar 2012 19:08:03 +0000 (21:08 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Sat, 10 Mar 2012 09:28:13 +0000 (11:28 +0200)
14 files changed:
data/mods/default/init.lua
src/content_abm.cpp
src/content_cao.cpp
src/content_sao.cpp
src/content_sao.h
src/itemgroup.h [new file with mode: 0644]
src/luaentity_common.cpp
src/luaentity_common.h
src/scriptapi.cpp
src/scriptapi.h
src/server.cpp
src/serverobject.h
src/serverremoteplayer.cpp
src/serverremoteplayer.h

index 9750f610f460f1e123b0f63630b14bf7a0d0a859..bcd633b3432612cc9b4b97c048d7f3acfadb876c 100644 (file)
 -- - getpos() -> {x=num, y=num, z=num}
 -- - setpos(pos); pos={x=num, y=num, z=num}
 -- - moveto(pos, continuous=false): interpolated move
--- - punch(puncher, time_from_last_punch)
+-- - punch(puncher, time_from_last_punch, tool_capabilities, direction)
 --   ^ puncher = an another ObjectRef,
 --   ^ time_from_last_punch = time since last punch action of the puncher
 -- - right_click(clicker); clicker = an another ObjectRef
@@ -1124,14 +1124,14 @@ minetest.register_node("default:tree", {
        description = "Tree",
        tile_images = {"default_tree_top.png", "default_tree_top.png", "default_tree.png"},
        is_ground_content = true,
-       groups = {snappy=2},
+       groups = {snappy=2,choppy=2},
 })
 
 minetest.register_node("default:jungletree", {
        description = "Jungle Tree",
        tile_images = {"default_jungletree_top.png", "default_jungletree_top.png", "default_jungletree.png"},
        is_ground_content = true,
-       groups = {snappy=2},
+       groups = {snappy=2,choppy=2},
 })
 
 minetest.register_node("default:junglegrass", {
@@ -1174,7 +1174,7 @@ minetest.register_node("default:cactus", {
        description = "Cactus",
        tile_images = {"default_cactus_top.png", "default_cactus_top.png", "default_cactus_side.png"},
        is_ground_content = true,
-       groups = {snappy=2},
+       groups = {snappy=2,choppy=3},
 })
 
 minetest.register_node("default:papyrus", {
@@ -1193,7 +1193,7 @@ minetest.register_node("default:bookshelf", {
        description = "Bookshelf",
        tile_images = {"default_wood.png", "default_wood.png", "default_bookshelf.png"},
        is_ground_content = true,
-       groups = {snappy=2},
+       groups = {snappy=2,choppy=3},
 })
 
 minetest.register_node("default:glass", {
@@ -1219,7 +1219,7 @@ minetest.register_node("default:fence_wood", {
                type = "fixed",
                fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7},
        },
-       groups = {snappy=2},
+       groups = {snappy=2,choppy=2},
 })
 
 minetest.register_node("default:rail", {
@@ -1255,7 +1255,7 @@ minetest.register_node("default:ladder", {
                --wall_bottom = = <default>
                --wall_side = = <default>
        },
-       groups = {snappy=2},
+       groups = {snappy=2,choppy=2},
        legacy_wallmounted = true,
 })
 
@@ -1263,7 +1263,7 @@ minetest.register_node("default:wood", {
        description = "Wood",
        tile_images = {"default_wood.png"},
        is_ground_content = true,
-       groups = {snappy=2},
+       groups = {snappy=2,choppy=2},
 })
 
 minetest.register_node("default:mese", {
@@ -1421,7 +1421,7 @@ minetest.register_node("default:chest", {
                "default_chest_side.png", "default_chest_side.png", "default_chest_front.png"},
        paramtype2 = "facedir",
        metadata_name = "chest",
-       groups = {snappy=2},
+       groups = {snappy=2,choppy=2},
        legacy_facedir_simple = true,
 })
 
@@ -1431,7 +1431,7 @@ minetest.register_node("default:chest_locked", {
                "default_chest_side.png", "default_chest_side.png", "default_chest_lock.png"},
        paramtype2 = "facedir",
        metadata_name = "locked_chest",
-       groups = {snappy=2},
+       groups = {snappy=2,choppy=2},
        legacy_facedir_simple = true,
 })
 
index 63867b78b6baff9b8e07f2e386fc66e72031b100..3a92796a49eb8692415c34f30c99272877002af4 100644 (file)
@@ -88,119 +88,6 @@ public:
        }
 };
 
-class SpawnRatsAroundTreesABM : public ActiveBlockModifier
-{
-private:
-public:
-       virtual std::set<std::string> getTriggerContents()
-       {
-               std::set<std::string> s;
-               s.insert("tree");
-               s.insert("jungletree");
-               return s;
-       }
-       virtual float getTriggerInterval()
-       { return 10.0; }
-       virtual u32 getTriggerChance()
-       { return 200; }
-       virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
-                       u32 active_object_count, u32 active_object_count_wider)
-       {
-               if(active_object_count_wider != 0)
-                       return;
-
-               INodeDefManager *ndef = env->getGameDef()->ndef();
-               ServerMap *map = &env->getServerMap();
-               
-               v3s16 p1 = p + v3s16(myrand_range(-2, 2),
-                               0, myrand_range(-2, 2));
-               MapNode n1 = map->getNodeNoEx(p1);
-               MapNode n1b = map->getNodeNoEx(p1+v3s16(0,-1,0));
-               if(n1b.getContent() == ndef->getId("dirt_with_grass") &&
-                               n1.getContent() == CONTENT_AIR)
-               {
-                       v3f pos = intToFloat(p1, BS);
-                       ServerActiveObject *obj = new RatSAO(env, pos);
-                       env->addActiveObject(obj);
-               }
-       }
-};
-
-static void getMob_dungeon_master(Settings &properties)
-{
-       properties.set("looks", "dungeon_master");
-       properties.setFloat("yaw", 1.57);
-       properties.setFloat("hp", 30);
-       properties.setBool("bright_shooting", true);
-       properties.set("shoot_type", "fireball");
-       properties.set("shoot_y", "0.7");
-       properties.set("player_hit_damage", "1");
-       properties.set("player_hit_distance", "1.0");
-       properties.set("player_hit_interval", "0.5");
-       properties.setBool("mindless_rage", myrand_range(0,100)==0);
-}
-
-class SpawnInCavesABM : public ActiveBlockModifier
-{
-private:
-public:
-       virtual std::set<std::string> getTriggerContents()
-       {
-               std::set<std::string> s;
-               s.insert("stone");
-               s.insert("mossycobble");
-               return s;
-       }
-       virtual float getTriggerInterval()
-       { return 2.0; }
-       virtual u32 getTriggerChance()
-       { return 1000; }
-       virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
-                       u32 active_object_count, u32 active_object_count_wider)
-       {
-               if(active_object_count_wider != 0)
-                       return;
-
-               INodeDefManager *ndef = env->getGameDef()->ndef();
-               ServerMap *map = &env->getServerMap();
-
-               v3s16 p1 = p + v3s16(0,1,0);
-               MapNode n1a = map->getNodeNoEx(p1+v3s16(0,0,0));
-               if(n1a.getLightBlend(env->getDayNightRatio(), ndef) <= 3){
-                       MapNode n1b = map->getNodeNoEx(p1+v3s16(0,1,0));
-                       if(n1a.getContent() == CONTENT_AIR &&
-                                       n1b.getContent() == CONTENT_AIR)
-                       {
-                               v3f pos = intToFloat(p1, BS);
-                               int i = myrand()%5;
-                               if(i == 0 || i == 1){
-                                       actionstream<<"A dungeon master spawns at "
-                                                       <<PP(p1)<<std::endl;
-                                       Settings properties;
-                                       getMob_dungeon_master(properties);
-                                       ServerActiveObject *obj = new MobV2SAO(
-                                                       env, pos, &properties);
-                                       env->addActiveObject(obj);
-                               } else if(i == 2 || i == 3){
-                                       actionstream<<"Rats spawn at "
-                                                       <<PP(p1)<<std::endl;
-                                       for(int j=0; j<3; j++){
-                                               ServerActiveObject *obj = new RatSAO(
-                                                               env, pos);
-                                               env->addActiveObject(obj);
-                                       }
-                               } else {
-                                       actionstream<<"An oerkki spawns at "
-                                                       <<PP(p1)<<std::endl;
-                                       ServerActiveObject *obj = new Oerkki1SAO(
-                                                       env, pos);
-                                       env->addActiveObject(obj);
-                               }
-                       }
-               }
-       }
-};
-
 class MakeTreesFromSaplingsABM : public ActiveBlockModifier
 {
 private:
@@ -261,8 +148,6 @@ void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef)
 {
        env->addActiveBlockModifier(new GrowGrassABM());
        env->addActiveBlockModifier(new RemoveGrassABM());
-       env->addActiveBlockModifier(new SpawnRatsAroundTreesABM());
-       env->addActiveBlockModifier(new SpawnInCavesABM());
        env->addActiveBlockModifier(new MakeTreesFromSaplingsABM());
 }
 
index 3c30a08195feeb974ebd8dc0fc215f1ee35ff570..d6289a1b92e1d0ea8e72daa95603852afa747a35 100644 (file)
@@ -116,1564 +116,99 @@ struct SmoothTranslator
        }
 };
 
-
-/*
-       TestCAO
-*/
-
-class TestCAO : public ClientActiveObject
-{
-public:
-       TestCAO(IGameDef *gamedef, ClientEnvironment *env);
-       virtual ~TestCAO();
-       
-       u8 getType() const
-       {
-               return ACTIVEOBJECT_TYPE_TEST;
-       }
-       
-       static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
-
-       void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr);
-       void removeFromScene();
-       void updateLight(u8 light_at_pos);
-       v3s16 getLightPosition();
-       void updateNodePos();
-
-       void step(float dtime, ClientEnvironment *env);
-
-       void processMessage(const std::string &data);
-
-private:
-       scene::IMeshSceneNode *m_node;
-       v3f m_position;
-};
-
-/*
-       ItemCAO
-*/
-
-class ItemCAO : public ClientActiveObject
-{
-public:
-       ItemCAO(IGameDef *gamedef, ClientEnvironment *env);
-       virtual ~ItemCAO();
-       
-       u8 getType() const
-       {
-               return ACTIVEOBJECT_TYPE_ITEM;
-       }
-       
-       static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
-
-       void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr);
-       void removeFromScene();
-       void updateLight(u8 light_at_pos);
-       v3s16 getLightPosition();
-       void updateNodePos();
-       void updateInfoText();
-       void updateTexture();
-
-       void step(float dtime, ClientEnvironment *env);
-
-       void processMessage(const std::string &data);
-
-       void initialize(const std::string &data);
-       
-       core::aabbox3d<f32>* getSelectionBox()
-               {return &m_selection_box;}
-       v3f getPosition()
-               {return m_position;}
-       
-       std::string infoText()
-               {return m_infotext;}
-
-private:
-       core::aabbox3d<f32> m_selection_box;
-       scene::IMeshSceneNode *m_node;
-       v3f m_position;
-       std::string m_itemstring;
-       std::string m_infotext;
-};
-
-/*
-       RatCAO
-*/
-
-class RatCAO : public ClientActiveObject
-{
-public:
-       RatCAO(IGameDef *gamedef, ClientEnvironment *env);
-       virtual ~RatCAO();
-       
-       u8 getType() const
-       {
-               return ACTIVEOBJECT_TYPE_RAT;
-       }
-       
-       static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
-
-       void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr);
-       void removeFromScene();
-       void updateLight(u8 light_at_pos);
-       v3s16 getLightPosition();
-       void updateNodePos();
-
-       void step(float dtime, ClientEnvironment *env);
-
-       void processMessage(const std::string &data);
-
-       void initialize(const std::string &data);
-       
-       core::aabbox3d<f32>* getSelectionBox()
-               {return &m_selection_box;}
-       v3f getPosition()
-               {return pos_translator.vect_show;}
-               //{return m_position;}
-
-private:
-       core::aabbox3d<f32> m_selection_box;
-       scene::IMeshSceneNode *m_node;
-       v3f m_position;
-       float m_yaw;
-       SmoothTranslator pos_translator;
-};
-
-/*
-       Oerkki1CAO
-*/
-
-class Oerkki1CAO : public ClientActiveObject
-{
-public:
-       Oerkki1CAO(IGameDef *gamedef, ClientEnvironment *env);
-       virtual ~Oerkki1CAO();
-       
-       u8 getType() const
-       {
-               return ACTIVEOBJECT_TYPE_OERKKI1;
-       }
-       
-       static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
-
-       void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr);
-       void removeFromScene();
-       void updateLight(u8 light_at_pos);
-       v3s16 getLightPosition();
-       void updateNodePos();
-
-       void step(float dtime, ClientEnvironment *env);
-
-       void processMessage(const std::string &data);
-
-       void initialize(const std::string &data);
-       
-       core::aabbox3d<f32>* getSelectionBox()
-               {return &m_selection_box;}
-       v3f getPosition()
-               {return pos_translator.vect_show;}
-               //{return m_position;}
-
-       // If returns true, punch will not be sent to the server
-       bool directReportPunch(const std::string &toolname, v3f dir);
-
-private:
-       IntervalLimiter m_attack_interval;
-       core::aabbox3d<f32> m_selection_box;
-       scene::IMeshSceneNode *m_node;
-       v3f m_position;
-       float m_yaw;
-       SmoothTranslator pos_translator;
-       float m_damage_visual_timer;
-       bool m_damage_texture_enabled;
-};
-
-/*
-       FireflyCAO
-*/
-
-class FireflyCAO : public ClientActiveObject
-{
-public:
-       FireflyCAO(IGameDef *gamedef, ClientEnvironment *env);
-       virtual ~FireflyCAO();
-       
-       u8 getType() const
-       {
-               return ACTIVEOBJECT_TYPE_FIREFLY;
-       }
-       
-       static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
-
-       void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr);
-       void removeFromScene();
-       void updateLight(u8 light_at_pos);
-       v3s16 getLightPosition();
-       void updateNodePos();
-
-       void step(float dtime, ClientEnvironment *env);
-
-       void processMessage(const std::string &data);
-
-       void initialize(const std::string &data);
-       
-       core::aabbox3d<f32>* getSelectionBox()
-               {return &m_selection_box;}
-       v3f getPosition()
-               {return m_position;}
-
-private:
-       core::aabbox3d<f32> m_selection_box;
-       scene::IMeshSceneNode *m_node;
-       v3f m_position;
-       float m_yaw;
-       SmoothTranslator pos_translator;
-};
-
-static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
-               float txs, float tys, int col, int row)
-{
-       video::SMaterial& material = bill->getMaterial(0);
-       core::matrix4& matrix = material.getTextureMatrix(0);
-       matrix.setTextureTranslate(txs*col, tys*row);
-       matrix.setTextureScale(txs, tys);
-}
-
-/*
-       MobV2CAO
-*/
-
-class MobV2CAO : public ClientActiveObject
-{
-public:
-       MobV2CAO(IGameDef *gamedef, ClientEnvironment *env);
-       virtual ~MobV2CAO();
-       
-       u8 getType() const
-       {
-               return ACTIVEOBJECT_TYPE_MOBV2;
-       }
-       
-       static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
-
-       void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr);
-       void removeFromScene();
-       void updateLight(u8 light_at_pos);
-       v3s16 getLightPosition();
-       void updateNodePos();
-
-       void step(float dtime, ClientEnvironment *env);
-
-       void processMessage(const std::string &data);
-
-       void initialize(const std::string &data);
-       
-       core::aabbox3d<f32>* getSelectionBox()
-               {return &m_selection_box;}
-       v3f getPosition()
-               {return pos_translator.vect_show;}
-               //{return m_position;}
-       bool doShowSelectionBox(){return false;}
-
-       // If returns true, punch will not be sent to the server
-       bool directReportPunch(const std::string &toolname, v3f dir);
-
-private:
-       void setLooks(const std::string &looks);
-       
-       IntervalLimiter m_attack_interval;
-       core::aabbox3d<f32> m_selection_box;
-       scene::IBillboardSceneNode *m_node;
-       v3f m_position;
-       std::string m_texture_name;
-       float m_yaw;
-       SmoothTranslator pos_translator;
-       bool m_walking;
-       float m_walking_unset_timer;
-       float m_walk_timer;
-       int m_walk_frame;
-       float m_damage_visual_timer;
-       u8 m_last_light;
-       bool m_shooting;
-       float m_shooting_unset_timer;
-       v2f m_sprite_size;
-       float m_sprite_y;
-       bool m_bright_shooting;
-       std::string m_sprite_type;
-       int m_simple_anim_frames;
-       float m_simple_anim_frametime;
-       bool m_lock_full_brightness;
-       int m_player_hit_damage;
-       float m_player_hit_distance;
-       float m_player_hit_interval;
-       float m_player_hit_timer;
-
-       Settings *m_properties;
-};
-
-/*
-       TestCAO
-*/
-
-// Prototype
-TestCAO proto_TestCAO(NULL, NULL);
-
-TestCAO::TestCAO(IGameDef *gamedef, ClientEnvironment *env):
-       ClientActiveObject(0, gamedef, env),
-       m_node(NULL),
-       m_position(v3f(0,10*BS,0))
-{
-       ClientActiveObject::registerType(getType(), create);
-}
-
-TestCAO::~TestCAO()
-{
-}
-
-ClientActiveObject* TestCAO::create(IGameDef *gamedef, ClientEnvironment *env)
-{
-       return new TestCAO(gamedef, env);
-}
-
-void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr)
-{
-       if(m_node != NULL)
-               return;
-       
-       //video::IVideoDriver* driver = smgr->getVideoDriver();
-       
-       scene::SMesh *mesh = new scene::SMesh();
-       scene::IMeshBuffer *buf = new scene::SMeshBuffer();
-       video::SColor c(255,255,255,255);
-       video::S3DVertex vertices[4] =
-       {
-               video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
-               video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
-               video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
-               video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
-       };
-       u16 indices[] = {0,1,2,2,3,0};
-       buf->append(vertices, 4, indices, 6);
-       // Set material
-       buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
-       buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-       buf->getMaterial().setTexture(0, tsrc->getTextureRaw("rat.png"));
-       buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
-       buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
-       buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
-       // Add to mesh
-       mesh->addMeshBuffer(buf);
-       buf->drop();
-       m_node = smgr->addMeshSceneNode(mesh, NULL);
-       mesh->drop();
-       updateNodePos();
-}
-
-void TestCAO::removeFromScene()
-{
-       if(m_node == NULL)
-               return;
-
-       m_node->remove();
-       m_node = NULL;
-}
-
-void TestCAO::updateLight(u8 light_at_pos)
-{
-}
-
-v3s16 TestCAO::getLightPosition()
-{
-       return floatToInt(m_position, BS);
-}
-
-void TestCAO::updateNodePos()
-{
-       if(m_node == NULL)
-               return;
-
-       m_node->setPosition(m_position);
-       //m_node->setRotation(v3f(0, 45, 0));
-}
-
-void TestCAO::step(float dtime, ClientEnvironment *env)
-{
-       if(m_node)
-       {
-               v3f rot = m_node->getRotation();
-               //infostream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
-               rot.Y += dtime * 180;
-               m_node->setRotation(rot);
-       }
-}
-
-void TestCAO::processMessage(const std::string &data)
-{
-       infostream<<"TestCAO: Got data: "<<data<<std::endl;
-       std::istringstream is(data, std::ios::binary);
-       u16 cmd;
-       is>>cmd;
-       if(cmd == 0)
-       {
-               v3f newpos;
-               is>>newpos.X;
-               is>>newpos.Y;
-               is>>newpos.Z;
-               m_position = newpos;
-               updateNodePos();
-       }
-}
-
-/*
-       ItemCAO
-*/
-
-#include "inventory.h"
-
-// Prototype
-ItemCAO proto_ItemCAO(NULL, NULL);
-
-ItemCAO::ItemCAO(IGameDef *gamedef, ClientEnvironment *env):
-       ClientActiveObject(0, gamedef, env),
-       m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
-       m_node(NULL),
-       m_position(v3f(0,10*BS,0))
-{
-       if(!gamedef && !env)
-       {
-               ClientActiveObject::registerType(getType(), create);
-       }
-}
-
-ItemCAO::~ItemCAO()
-{
-}
-
-ClientActiveObject* ItemCAO::create(IGameDef *gamedef, ClientEnvironment *env)
-{
-       return new ItemCAO(gamedef, env);
-}
-
-void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr)
-{
-       if(m_node != NULL)
-               return;
-       
-       //video::IVideoDriver* driver = smgr->getVideoDriver();
-       
-       scene::SMesh *mesh = new scene::SMesh();
-       scene::IMeshBuffer *buf = new scene::SMeshBuffer();
-       video::SColor c(255,255,255,255);
-       video::S3DVertex vertices[4] =
-       {
-               /*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
-               video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
-               video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
-               video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
-               video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1),
-               video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1),
-               video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0),
-               video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0),
-       };
-       u16 indices[] = {0,1,2,2,3,0};
-       buf->append(vertices, 4, indices, 6);
-       // Set material
-       buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
-       buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-       // Initialize with a generated placeholder texture
-       buf->getMaterial().setTexture(0, tsrc->getTextureRaw(""));
-       buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
-       buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
-       buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
-       // Add to mesh
-       mesh->addMeshBuffer(buf);
-       buf->drop();
-       m_node = smgr->addMeshSceneNode(mesh, NULL);
-       mesh->drop();
-       updateNodePos();
-
-       /*
-               Update image of node
-       */
-
-       updateTexture();
-}
-
-void ItemCAO::removeFromScene()
-{
-       if(m_node == NULL)
-               return;
-
-       m_node->remove();
-       m_node = NULL;
-}
-
-void ItemCAO::updateLight(u8 light_at_pos)
-{
-       if(m_node == NULL)
-               return;
-
-       u8 li = decode_light(light_at_pos);
-       video::SColor color(255,li,li,li);
-       setMeshColor(m_node->getMesh(), color);
-}
-
-v3s16 ItemCAO::getLightPosition()
-{
-       return floatToInt(m_position, BS);
-}
-
-void ItemCAO::updateNodePos()
-{
-       if(m_node == NULL)
-               return;
-
-       m_node->setPosition(m_position);
-}
-
-void ItemCAO::updateInfoText()
-{
-       try{
-               IItemDefManager *idef = m_gamedef->idef();
-               ItemStack item;
-               item.deSerialize(m_itemstring, idef);
-               if(item.isKnown(idef))
-                       m_infotext = item.getDefinition(idef).description;
-               else
-                       m_infotext = "Unknown item: '" + m_itemstring + "'";
-               if(item.count >= 2)
-                       m_infotext += " (" + itos(item.count) + ")";
-       }
-       catch(SerializationError &e)
-       {
-               m_infotext = "Unknown item: '" + m_itemstring + "'";
-       }
-}
-
-void ItemCAO::updateTexture()
-{
-       if(m_node == NULL)
-               return;
-
-       // Create an inventory item to see what is its image
-       std::istringstream is(m_itemstring, std::ios_base::binary);
-       video::ITexture *texture = NULL;
-       try{
-               IItemDefManager *idef = m_gamedef->idef();
-               ItemStack item;
-               item.deSerialize(is, idef);
-               texture = item.getDefinition(idef).inventory_texture;
-       }
-       catch(SerializationError &e)
-       {
-               infostream<<"WARNING: "<<__FUNCTION_NAME
-                               <<": error deSerializing itemstring \""
-                               <<m_itemstring<<std::endl;
-       }
-       
-       // Set meshbuffer texture
-       m_node->getMaterial(0).setTexture(0, texture);
-}
-
-
-void ItemCAO::step(float dtime, ClientEnvironment *env)
-{
-       if(m_node)
-       {
-               /*v3f rot = m_node->getRotation();
-               rot.Y += dtime * 120;
-               m_node->setRotation(rot);*/
-               LocalPlayer *player = env->getLocalPlayer();
-               assert(player);
-               v3f rot = m_node->getRotation();
-               rot.Y = 180.0 - (player->getYaw());
-               m_node->setRotation(rot);
-       }
-}
-
-void ItemCAO::processMessage(const std::string &data)
-{
-       //infostream<<"ItemCAO: Got message"<<std::endl;
-       std::istringstream is(data, std::ios::binary);
-       // command
-       u8 cmd = readU8(is);
-       if(cmd == 0)
-       {
-               // pos
-               m_position = readV3F1000(is);
-               updateNodePos();
-       }
-       if(cmd == 1)
-       {
-               // itemstring
-               m_itemstring = deSerializeString(is);
-               updateInfoText();
-               updateTexture();
-       }
-}
-
-void ItemCAO::initialize(const std::string &data)
-{
-       infostream<<"ItemCAO: Got init data"<<std::endl;
-       
-       {
-               std::istringstream is(data, std::ios::binary);
-               // version
-               u8 version = readU8(is);
-               // check version
-               if(version != 0)
-                       return;
-               // pos
-               m_position = readV3F1000(is);
-               // itemstring
-               m_itemstring = deSerializeString(is);
-       }
-       
-       updateNodePos();
-       updateInfoText();
-}
-
-/*
-       RatCAO
-*/
-
-#include "inventory.h"
-
-// Prototype
-RatCAO proto_RatCAO(NULL, NULL);
-
-RatCAO::RatCAO(IGameDef *gamedef, ClientEnvironment *env):
-       ClientActiveObject(0, gamedef, env),
-       m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
-       m_node(NULL),
-       m_position(v3f(0,10*BS,0)),
-       m_yaw(0)
-{
-       ClientActiveObject::registerType(getType(), create);
-}
-
-RatCAO::~RatCAO()
-{
-}
-
-ClientActiveObject* RatCAO::create(IGameDef *gamedef, ClientEnvironment *env)
-{
-       return new RatCAO(gamedef, env);
-}
-
-void RatCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr)
-{
-       if(m_node != NULL)
-               return;
-       
-       //video::IVideoDriver* driver = smgr->getVideoDriver();
-       
-       scene::SMesh *mesh = new scene::SMesh();
-       scene::IMeshBuffer *buf = new scene::SMeshBuffer();
-       video::SColor c(255,255,255,255);
-       video::S3DVertex vertices[4] =
-       {
-               video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
-               video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
-               video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
-               video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
-       };
-       u16 indices[] = {0,1,2,2,3,0};
-       buf->append(vertices, 4, indices, 6);
-       // Set material
-       buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
-       buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-       //buf->getMaterial().setTexture(0, NULL);
-       buf->getMaterial().setTexture(0, tsrc->getTextureRaw("rat.png"));
-       buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
-       buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
-       buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
-       // Add to mesh
-       mesh->addMeshBuffer(buf);
-       buf->drop();
-       m_node = smgr->addMeshSceneNode(mesh, NULL);
-       mesh->drop();
-       // Set it to use the materials of the meshbuffers directly.
-       // This is needed for changing the texture in the future
-       m_node->setReadOnlyMaterials(true);
-       updateNodePos();
-}
-
-void RatCAO::removeFromScene()
-{
-       if(m_node == NULL)
-               return;
-
-       m_node->remove();
-       m_node = NULL;
-}
-
-void RatCAO::updateLight(u8 light_at_pos)
-{
-       if(m_node == NULL)
-               return;
-
-       u8 li = decode_light(light_at_pos);
-       video::SColor color(255,li,li,li);
-       setMeshColor(m_node->getMesh(), color);
-}
-
-v3s16 RatCAO::getLightPosition()
-{
-       return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
-}
-
-void RatCAO::updateNodePos()
-{
-       if(m_node == NULL)
-               return;
-
-       //m_node->setPosition(m_position);
-       m_node->setPosition(pos_translator.vect_show);
-
-       v3f rot = m_node->getRotation();
-       rot.Y = 180.0 - m_yaw;
-       m_node->setRotation(rot);
-}
-
-void RatCAO::step(float dtime, ClientEnvironment *env)
-{
-       pos_translator.translate(dtime);
-       updateNodePos();
-}
-
-void RatCAO::processMessage(const std::string &data)
-{
-       //infostream<<"RatCAO: Got message"<<std::endl;
-       std::istringstream is(data, std::ios::binary);
-       // command
-       u8 cmd = readU8(is);
-       if(cmd == 0)
-       {
-               // pos
-               m_position = readV3F1000(is);
-               pos_translator.update(m_position);
-               // yaw
-               m_yaw = readF1000(is);
-               updateNodePos();
-       }
-}
-
-void RatCAO::initialize(const std::string &data)
-{
-       //infostream<<"RatCAO: Got init data"<<std::endl;
-       
-       {
-               std::istringstream is(data, std::ios::binary);
-               // version
-               u8 version = readU8(is);
-               // check version
-               if(version != 0)
-                       return;
-               // pos
-               m_position = readV3F1000(is);
-               pos_translator.init(m_position);
-       }
-       
-       updateNodePos();
-}
-
-/*
-       Oerkki1CAO
-*/
-
-#include "inventory.h"
-
-// Prototype
-Oerkki1CAO proto_Oerkki1CAO(NULL, NULL);
-
-Oerkki1CAO::Oerkki1CAO(IGameDef *gamedef, ClientEnvironment *env):
-       ClientActiveObject(0, gamedef, env),
-       m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.,BS/3.),
-       m_node(NULL),
-       m_position(v3f(0,10*BS,0)),
-       m_yaw(0),
-       m_damage_visual_timer(0),
-       m_damage_texture_enabled(false)
-{
-       ClientActiveObject::registerType(getType(), create);
-}
-
-Oerkki1CAO::~Oerkki1CAO()
-{
-}
-
-ClientActiveObject* Oerkki1CAO::create(IGameDef *gamedef, ClientEnvironment *env)
-{
-       return new Oerkki1CAO(gamedef, env);
-}
-
-void Oerkki1CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr)
-{
-       if(m_node != NULL)
-               return;
-       
-       //video::IVideoDriver* driver = smgr->getVideoDriver();
-       
-       scene::SMesh *mesh = new scene::SMesh();
-       scene::IMeshBuffer *buf = new scene::SMeshBuffer();
-       video::SColor c(255,255,255,255);
-       video::S3DVertex vertices[4] =
-       {
-               video::S3DVertex(-BS/2-BS,0,0, 0,0,0, c, 0,1),
-               video::S3DVertex(BS/2+BS,0,0, 0,0,0, c, 1,1),
-               video::S3DVertex(BS/2+BS,BS*2,0, 0,0,0, c, 1,0),
-               video::S3DVertex(-BS/2-BS,BS*2,0, 0,0,0, c, 0,0),
-       };
-       u16 indices[] = {0,1,2,2,3,0};
-       buf->append(vertices, 4, indices, 6);
-       // Set material
-       buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
-       buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-       //buf->getMaterial().setTexture(0, NULL);
-       buf->getMaterial().setTexture(0, tsrc->getTextureRaw("oerkki1.png"));
-       buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
-       buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
-       buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
-       // Add to mesh
-       mesh->addMeshBuffer(buf);
-       buf->drop();
-       m_node = smgr->addMeshSceneNode(mesh, NULL);
-       mesh->drop();
-       // Set it to use the materials of the meshbuffers directly.
-       // This is needed for changing the texture in the future
-       m_node->setReadOnlyMaterials(true);
-       updateNodePos();
-}
-
-void Oerkki1CAO::removeFromScene()
-{
-       if(m_node == NULL)
-               return;
-
-       m_node->remove();
-       m_node = NULL;
-}
-
-void Oerkki1CAO::updateLight(u8 light_at_pos)
-{
-       if(m_node == NULL)
-               return;
-       
-       if(light_at_pos <= 2)
-       {
-               m_node->setVisible(false);
-               return;
-       }
-
-       m_node->setVisible(true);
-
-       u8 li = decode_light(light_at_pos);
-       video::SColor color(255,li,li,li);
-       setMeshColor(m_node->getMesh(), color);
-}
-
-v3s16 Oerkki1CAO::getLightPosition()
-{
-       return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
-}
-
-void Oerkki1CAO::updateNodePos()
-{
-       if(m_node == NULL)
-               return;
-
-       //m_node->setPosition(m_position);
-       m_node->setPosition(pos_translator.vect_show);
-
-       v3f rot = m_node->getRotation();
-       rot.Y = 180.0 - m_yaw + 90.0;
-       m_node->setRotation(rot);
-}
-
-void Oerkki1CAO::step(float dtime, ClientEnvironment *env)
-{
-       ITextureSource *tsrc = m_gamedef->tsrc();
-
-       pos_translator.translate(dtime);
-       updateNodePos();
-
-       LocalPlayer *player = env->getLocalPlayer();
-       assert(player);
-       
-       v3f playerpos = player->getPosition();
-       v2f playerpos_2d(playerpos.X,playerpos.Z);
-       v2f objectpos_2d(m_position.X,m_position.Z);
-
-       if(fabs(m_position.Y - playerpos.Y) < 1.5*BS &&
-                       objectpos_2d.getDistanceFrom(playerpos_2d) < 1.5*BS)
-       {
-               if(m_attack_interval.step(dtime, 0.5))
-               {
-                       env->damageLocalPlayer(2);
-               }
-       }
-
-       if(m_damage_visual_timer > 0)
-       {
-               if(!m_damage_texture_enabled)
-               {
-                       // Enable damage texture
-                       if(m_node)
-                       {
-                               /*video::IVideoDriver* driver =
-                                       m_node->getSceneManager()->getVideoDriver();*/
-                               
-                               scene::IMesh *mesh = m_node->getMesh();
-                               if(mesh == NULL)
-                                       return;
-                               
-                               u16 mc = mesh->getMeshBufferCount();
-                               for(u16 j=0; j<mc; j++)
-                               {
-                                       scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
-                                       buf->getMaterial().setTexture(0,
-                                                       tsrc->getTextureRaw("oerkki1_damaged.png"));
-                               }
-                       }
-                       m_damage_texture_enabled = true;
-               }
-               m_damage_visual_timer -= dtime;
-       }
-       else
-       {
-               if(m_damage_texture_enabled)
-               {
-                       // Disable damage texture
-                       if(m_node)
-                       {
-                               /*video::IVideoDriver* driver =
-                                       m_node->getSceneManager()->getVideoDriver();*/
-                               
-                               scene::IMesh *mesh = m_node->getMesh();
-                               if(mesh == NULL)
-                                       return;
-                               
-                               u16 mc = mesh->getMeshBufferCount();
-                               for(u16 j=0; j<mc; j++)
-                               {
-                                       scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
-                                       buf->getMaterial().setTexture(0,
-                                                       tsrc->getTextureRaw("oerkki1.png"));
-                               }
-                       }
-                       m_damage_texture_enabled = false;
-               }
-       }
-}
-
-void Oerkki1CAO::processMessage(const std::string &data)
-{
-       //infostream<<"Oerkki1CAO: Got message"<<std::endl;
-       std::istringstream is(data, std::ios::binary);
-       // command
-       u8 cmd = readU8(is);
-       if(cmd == 0)
-       {
-               // pos
-               m_position = readV3F1000(is);
-               pos_translator.update(m_position);
-               // yaw
-               m_yaw = readF1000(is);
-               updateNodePos();
-       }
-       else if(cmd == 1)
-       {
-               //u16 damage = readU8(is);
-               m_damage_visual_timer = 1.0;
-       }
-}
-
-void Oerkki1CAO::initialize(const std::string &data)
-{
-       //infostream<<"Oerkki1CAO: Got init data"<<std::endl;
-       
-       {
-               std::istringstream is(data, std::ios::binary);
-               // version
-               u8 version = readU8(is);
-               // check version
-               if(version != 0)
-                       return;
-               // pos
-               m_position = readV3F1000(is);
-               pos_translator.init(m_position);
-       }
-       
-       updateNodePos();
-}
-
-bool Oerkki1CAO::directReportPunch(const std::string &toolname, v3f dir)
-{
-       m_damage_visual_timer = 1.0;
-
-       m_position += dir * BS;
-       pos_translator.sharpen();
-       pos_translator.update(m_position);
-       updateNodePos();
-       
-       return false;
-}
-
 /*
-       FireflyCAO
+       Other stuff
 */
 
-// Prototype
-FireflyCAO proto_FireflyCAO(NULL, NULL);
-
-FireflyCAO::FireflyCAO(IGameDef *gamedef, ClientEnvironment *env):
-       ClientActiveObject(0, gamedef, env),
-       m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
-       m_node(NULL),
-       m_position(v3f(0,10*BS,0)),
-       m_yaw(0)
-{
-       ClientActiveObject::registerType(getType(), create);
-}
-
-FireflyCAO::~FireflyCAO()
-{
-}
-
-ClientActiveObject* FireflyCAO::create(IGameDef *gamedef, ClientEnvironment *env)
-{
-       return new FireflyCAO(gamedef, env);
-}
-
-void FireflyCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr)
-{
-       if(m_node != NULL)
-               return;
-       
-       //video::IVideoDriver* driver = smgr->getVideoDriver();
-       
-       scene::SMesh *mesh = new scene::SMesh();
-       scene::IMeshBuffer *buf = new scene::SMeshBuffer();
-       video::SColor c(255,255,255,255);
-       video::S3DVertex vertices[4] =
-       {
-               video::S3DVertex(0,0,0, 0,0,0, c, 0,1),
-               video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
-               video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
-               video::S3DVertex(0,BS/2,0, 0,0,0, c, 0,0),
-       };
-       u16 indices[] = {0,1,2,2,3,0};
-       buf->append(vertices, 4, indices, 6);
-       // Set material
-       buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
-       buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-       //buf->getMaterial().setTexture(0, NULL);
-       buf->getMaterial().setTexture(0, tsrc->getTextureRaw("firefly.png"));
-       buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
-       buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
-       buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
-       // Add to mesh
-       mesh->addMeshBuffer(buf);
-       buf->drop();
-       m_node = smgr->addMeshSceneNode(mesh, NULL);
-       mesh->drop();
-       // Set it to use the materials of the meshbuffers directly.
-       // This is needed for changing the texture in the future
-       m_node->setReadOnlyMaterials(true);
-       updateNodePos();
-}
-
-void FireflyCAO::removeFromScene()
-{
-       if(m_node == NULL)
-               return;
-
-       m_node->remove();
-       m_node = NULL;
-}
-
-void FireflyCAO::updateLight(u8 light_at_pos)
-{
-       if(m_node == NULL)
-               return;
-
-       u8 li = 255;
-       video::SColor color(255,li,li,li);
-       setMeshColor(m_node->getMesh(), color);
-}
-
-v3s16 FireflyCAO::getLightPosition()
-{
-       return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
-}
-
-void FireflyCAO::updateNodePos()
-{
-       if(m_node == NULL)
-               return;
-
-       //m_node->setPosition(m_position);
-       m_node->setPosition(pos_translator.vect_show);
-
-       v3f rot = m_node->getRotation();
-       rot.Y = 180.0 - m_yaw;
-       m_node->setRotation(rot);
-}
-
-void FireflyCAO::step(float dtime, ClientEnvironment *env)
-{
-       pos_translator.translate(dtime);
-       updateNodePos();
-}
-
-void FireflyCAO::processMessage(const std::string &data)
-{
-       //infostream<<"FireflyCAO: Got message"<<std::endl;
-       std::istringstream is(data, std::ios::binary);
-       // command
-       u8 cmd = readU8(is);
-       if(cmd == 0)
-       {
-               // pos
-               m_position = readV3F1000(is);
-               pos_translator.update(m_position);
-               // yaw
-               m_yaw = readF1000(is);
-               updateNodePos();
-       }
-}
-
-void FireflyCAO::initialize(const std::string &data)
+static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
+               float txs, float tys, int col, int row)
 {
-       //infostream<<"FireflyCAO: Got init data"<<std::endl;
-       
-       {
-               std::istringstream is(data, std::ios::binary);
-               // version
-               u8 version = readU8(is);
-               // check version
-               if(version != 0)
-                       return;
-               // pos
-               m_position = readV3F1000(is);
-               pos_translator.init(m_position);
-       }
-       
-       updateNodePos();
+       video::SMaterial& material = bill->getMaterial(0);
+       core::matrix4& matrix = material.getTextureMatrix(0);
+       matrix.setTextureTranslate(txs*col, tys*row);
+       matrix.setTextureScale(txs, tys);
 }
 
 /*
-       MobV2CAO
+       TestCAO
 */
 
-// Prototype
-MobV2CAO proto_MobV2CAO(NULL, NULL);
-
-MobV2CAO::MobV2CAO(IGameDef *gamedef, ClientEnvironment *env):
-       ClientActiveObject(0, gamedef, env),
-       m_selection_box(-0.4*BS,-0.4*BS,-0.4*BS, 0.4*BS,0.8*BS,0.4*BS),
-       m_node(NULL),
-       m_position(v3f(0,10*BS,0)),
-       m_yaw(0),
-       m_walking(false),
-       m_walking_unset_timer(0),
-       m_walk_timer(0),
-       m_walk_frame(0),
-       m_damage_visual_timer(0),
-       m_last_light(0),
-       m_shooting(0),
-       m_shooting_unset_timer(0),
-       m_sprite_size(BS,BS),
-       m_sprite_y(0),
-       m_bright_shooting(false),
-       m_lock_full_brightness(false),
-       m_player_hit_timer(0)
-{
-       ClientActiveObject::registerType(getType(), create);
-
-       m_properties = new Settings;
-}
-
-MobV2CAO::~MobV2CAO()
-{
-       delete m_properties;
-}
-
-ClientActiveObject* MobV2CAO::create(IGameDef *gamedef, ClientEnvironment *env)
-{
-       return new MobV2CAO(gamedef, env);
-}
-
-void MobV2CAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
-                       IrrlichtDevice *irr)
+class TestCAO : public ClientActiveObject
 {
-       if(m_node != NULL)
-               return;
-       
-       /*infostream<<"MobV2CAO::addToScene using texture_name="<<
-                       m_texture_name<<std::endl;*/
-       std::string texture_string = m_texture_name +
-                       "^[makealpha:128,0,0^[makealpha:128,128,0";
+public:
+       TestCAO(IGameDef *gamedef, ClientEnvironment *env);
+       virtual ~TestCAO();
        
-       scene::IBillboardSceneNode *bill = smgr->addBillboardSceneNode(
-                       NULL, v2f(1, 1), v3f(0,0,0), -1);
-       bill->setMaterialTexture(0, tsrc->getTextureRaw(texture_string));
-       bill->setMaterialFlag(video::EMF_LIGHTING, false);
-       bill->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
-       bill->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
-       bill->setMaterialFlag(video::EMF_FOG_ENABLE, true);
-       bill->setColor(video::SColor(255,0,0,0));
-       bill->setVisible(false); /* Set visible when brightness is known */
-       bill->setSize(m_sprite_size);
-       if(m_sprite_type == "humanoid_1"){
-               const float txp = 1./192;
-               const float txs = txp*32;
-               const float typ = 1./240;
-               const float tys = typ*48;
-               setBillboardTextureMatrix(bill, txs, tys, 0, 0);
-       } else if(m_sprite_type == "simple"){
-               const float txs = 1.0;
-               const float tys = 1.0 / m_simple_anim_frames;
-               setBillboardTextureMatrix(bill, txs, tys, 0, 0);
-       } else {
-               infostream<<"MobV2CAO: Unknown sprite type \""<<m_sprite_type<<"\""
-                               <<std::endl;
+       u8 getType() const
+       {
+               return ACTIVEOBJECT_TYPE_TEST;
        }
-
-       m_node = bill;
-
-       updateNodePos();
-}
-
-void MobV2CAO::removeFromScene()
-{
-       if(m_node == NULL)
-               return;
-
-       m_node->remove();
-       m_node = NULL;
-}
-
-void MobV2CAO::updateLight(u8 light_at_pos)
-{
-       if(m_lock_full_brightness)
-               light_at_pos = 15;
-       
-       m_last_light = light_at_pos;
-
-       if(m_node == NULL)
-               return;
        
-       if(m_damage_visual_timer > 0)
-               return;
-       
-       if(m_shooting && m_bright_shooting)
-               return;
-       
-       /*if(light_at_pos <= 2){
-               m_node->setVisible(false);
-               return;
-       }*/
+       static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
 
-       m_node->setVisible(true);
+       void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
+                       IrrlichtDevice *irr);
+       void removeFromScene();
+       void updateLight(u8 light_at_pos);
+       v3s16 getLightPosition();
+       void updateNodePos();
 
-       u8 li = decode_light(light_at_pos);
-       video::SColor color(255,li,li,li);
-       m_node->setColor(color);
-}
+       void step(float dtime, ClientEnvironment *env);
 
-v3s16 MobV2CAO::getLightPosition()
-{
-       return floatToInt(m_position+v3f(0,0,0), BS);
-}
+       void processMessage(const std::string &data);
 
-void MobV2CAO::updateNodePos()
-{
-       if(m_node == NULL)
-               return;
+private:
+       scene::IMeshSceneNode *m_node;
+       v3f m_position;
+};
 
-       m_node->setPosition(pos_translator.vect_show + v3f(0,m_sprite_y,0));
-}
+/*
+       ItemCAO
+*/
 
-void MobV2CAO::step(float dtime, ClientEnvironment *env)
+class ItemCAO : public ClientActiveObject
 {
-       scene::IBillboardSceneNode *bill = m_node;
-       if(!bill)
-               return;
-
-       pos_translator.translate(dtime);
+public:
+       ItemCAO(IGameDef *gamedef, ClientEnvironment *env);
+       virtual ~ItemCAO();
        
-       if(m_sprite_type == "humanoid_1"){
-               scene::ICameraSceneNode* camera = m_node->getSceneManager()->getActiveCamera();
-               if(!camera)
-                       return;
-               v3f cam_to_mob = m_node->getAbsolutePosition() - camera->getAbsolutePosition();
-               cam_to_mob.normalize();
-               int col = 0;
-               if(cam_to_mob.Y > 0.75)
-                       col = 5;
-               else if(cam_to_mob.Y < -0.75)
-                       col = 4;
-               else{
-                       float mob_dir = atan2(cam_to_mob.Z, cam_to_mob.X) / PI * 180.;
-                       float dir = mob_dir - m_yaw;
-                       dir = wrapDegrees_180(dir);
-                       //infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
-                       if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
-                               col = 2;
-                       else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
-                               col = 3;
-                       else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
-                               col = 0;
-                       else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
-                               col = 1;
-                       else
-                               col = 4;
-               }
-
-               int row = 0;
-               if(m_shooting){
-                       row = 3;
-               } else if(m_walking){
-                       m_walk_timer += dtime;
-                       if(m_walk_timer >= 0.5){
-                               m_walk_frame = (m_walk_frame + 1) % 2;
-                               m_walk_timer = 0;
-                       }
-                       if(m_walk_frame == 0)
-                               row = 1;
-                       else
-                               row = 2;
-               }
-
-               const float txp = 1./192;
-               const float txs = txp*32;
-               const float typ = 1./240;
-               const float tys = typ*48;
-               setBillboardTextureMatrix(bill, txs, tys, col, row);
-       } else if(m_sprite_type == "simple"){
-               m_walk_timer += dtime;
-               if(m_walk_timer >= m_simple_anim_frametime){
-                       m_walk_frame = (m_walk_frame + 1) % m_simple_anim_frames;
-                       m_walk_timer = 0;
-               }
-               int col = 0;
-               int row = m_walk_frame;
-               const float txs = 1.0;
-               const float tys = 1.0 / m_simple_anim_frames;
-               setBillboardTextureMatrix(bill, txs, tys, col, row);
-       } else {
-               infostream<<"MobV2CAO::step(): Unknown sprite type \""
-                               <<m_sprite_type<<"\""<<std::endl;
-       }
-
-       updateNodePos();
-
-       /* Damage local player */
-       if(m_player_hit_damage && m_player_hit_timer <= 0.0){
-               LocalPlayer *player = env->getLocalPlayer();
-               assert(player);
-               
-               v3f playerpos = player->getPosition();
-               v2f playerpos_2d(playerpos.X,playerpos.Z);
-               v2f objectpos_2d(m_position.X,m_position.Z);
-
-               if(fabs(m_position.Y - playerpos.Y) < m_player_hit_distance*BS &&
-               objectpos_2d.getDistanceFrom(playerpos_2d) < m_player_hit_distance*BS)
-               {
-                       env->damageLocalPlayer(m_player_hit_damage);
-                       m_player_hit_timer = m_player_hit_interval;
-               }
-       }
-
-       /* Run timers */
-
-       m_player_hit_timer -= dtime;
-
-       if(m_damage_visual_timer >= 0){
-               m_damage_visual_timer -= dtime;
-               if(m_damage_visual_timer <= 0){
-                       infostream<<"id="<<m_id<<" damage visual ended"<<std::endl;
-               }
-       }
-
-       m_walking_unset_timer += dtime;
-       if(m_walking_unset_timer >= 1.0){
-               m_walking = false;
-       }
-
-       m_shooting_unset_timer -= dtime;
-       if(m_shooting_unset_timer <= 0.0){
-               if(m_bright_shooting){
-                       u8 li = decode_light(m_last_light);
-                       video::SColor color(255,li,li,li);
-                       bill->setColor(color);
-                       m_bright_shooting = false;
-               }
-               m_shooting = false;
-       }
-
-}
-
-void MobV2CAO::processMessage(const std::string &data)
-{
-       //infostream<<"MobV2CAO: Got message"<<std::endl;
-       std::istringstream is(data, std::ios::binary);
-       // command
-       u8 cmd = readU8(is);
-
-       // Move
-       if(cmd == 0)
-       {
-               // pos
-               m_position = readV3F1000(is);
-               pos_translator.update(m_position);
-               // yaw
-               m_yaw = readF1000(is);
-
-               m_walking = true;
-               m_walking_unset_timer = 0;
-
-               updateNodePos();
-       }
-       // Damage
-       else if(cmd == 1)
-       {
-               //u16 damage = readU16(is);
-
-               /*u8 li = decode_light(m_last_light);
-               if(li >= 100)
-                       li = 30;
-               else
-                       li = 255;*/
-
-               /*video::SColor color(255,255,0,0);
-               m_node->setColor(color);
-
-               m_damage_visual_timer = 0.2;*/
-       }
-       // Trigger shooting
-       else if(cmd == 2)
+       u8 getType() const
        {
-               // length
-               m_shooting_unset_timer = readF1000(is);
-               // bright?
-               m_bright_shooting = readU8(is);
-               if(m_bright_shooting){
-                       u8 li = 255;
-                       video::SColor color(255,li,li,li);
-                       m_node->setColor(color);
-               }
-
-               m_shooting = true;
+               return ACTIVEOBJECT_TYPE_ITEM;
        }
-}
-
-void MobV2CAO::initialize(const std::string &data)
-{
-       //infostream<<"MobV2CAO: Got init data"<<std::endl;
        
-       {
-               std::istringstream is(data, std::ios::binary);
-               // version
-               u8 version = readU8(is);
-               // check version
-               if(version != 0){
-                       infostream<<__FUNCTION_NAME<<": Invalid version"<<std::endl;
-                       return;
-               }
-               
-               std::ostringstream tmp_os(std::ios::binary);
-               decompressZlib(is, tmp_os);
-               std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
-               m_properties->parseConfigLines(tmp_is, "MobArgsEnd");
-
-               infostream<<"MobV2CAO::initialize(): got properties:"<<std::endl;
-               m_properties->writeLines(infostream);
-               
-               m_properties->setDefault("looks", "dummy_default");
-               m_properties->setDefault("yaw", "0");
-               m_properties->setDefault("pos", "(0,0,0)");
-               m_properties->setDefault("player_hit_damage", "0");
-               m_properties->setDefault("player_hit_distance", "1.5");
-               m_properties->setDefault("player_hit_interval", "1.5");
-               
-               setLooks(m_properties->get("looks"));
-               m_yaw = m_properties->getFloat("yaw");
-               m_position = m_properties->getV3F("pos");
-               m_player_hit_damage = m_properties->getS32("player_hit_damage");
-               m_player_hit_distance = m_properties->getFloat("player_hit_distance");
-               m_player_hit_interval = m_properties->getFloat("player_hit_interval");
+       static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
 
-               pos_translator.init(m_position);
-       }
-       
-       updateNodePos();
-}
+       void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
+                       IrrlichtDevice *irr);
+       void removeFromScene();
+       void updateLight(u8 light_at_pos);
+       v3s16 getLightPosition();
+       void updateNodePos();
+       void updateInfoText();
+       void updateTexture();
 
-bool MobV2CAO::directReportPunch(const std::string &toolname, v3f dir)
-{
-       video::SColor color(255,255,0,0);
-       m_node->setColor(color);
+       void step(float dtime, ClientEnvironment *env);
 
-       m_damage_visual_timer = 0.05;
+       void processMessage(const std::string &data);
 
-       m_position += dir * BS;
-       pos_translator.sharpen();
-       pos_translator.update(m_position);
-       updateNodePos();
+       void initialize(const std::string &data);
        
-       return false;
-}
-
-void MobV2CAO::setLooks(const std::string &looks)
-{
-       v2f selection_size = v2f(0.4, 0.4) * BS;
-       float selection_y = 0 * BS;
-
-       if(looks == "dungeon_master"){
-               m_texture_name = "dungeon_master.png";
-               m_sprite_type = "humanoid_1";
-               m_sprite_size = v2f(2, 3) * BS;
-               m_sprite_y = 0.85 * BS;
-               selection_size = v2f(0.4, 2.6) * BS;
-               selection_y = -0.4 * BS;
-       }
-       else if(looks == "fireball"){
-               m_texture_name = "fireball.png";
-               m_sprite_type = "simple";
-               m_sprite_size = v2f(1, 1) * BS;
-               m_simple_anim_frames = 3;
-               m_simple_anim_frametime = 0.1;
-               m_lock_full_brightness = true;
-       }
-       else{
-               m_texture_name = "stone.png";
-               m_sprite_type = "simple";
-               m_sprite_size = v2f(1, 1) * BS;
-               m_simple_anim_frames = 3;
-               m_simple_anim_frametime = 0.333;
-               selection_size = v2f(0.4, 0.4) * BS;
-               selection_y = 0 * BS;
-       }
+       core::aabbox3d<f32>* getSelectionBox()
+               {return &m_selection_box;}
+       v3f getPosition()
+               {return m_position;}
+       
+       std::string infoText()
+               {return m_infotext;}
 
-       m_selection_box = core::aabbox3d<f32>(
-                       -selection_size.X, selection_y, -selection_size.X,
-                       selection_size.X, selection_y+selection_size.Y,
-                       selection_size.X);
-}
+private:
+       core::aabbox3d<f32> m_selection_box;
+       scene::IMeshSceneNode *m_node;
+       v3f m_position;
+       std::string m_itemstring;
+       std::string m_infotext;
+};
 
 /*
        LuaEntityCAO
@@ -1691,6 +226,7 @@ private:
        v3f m_velocity;
        v3f m_acceleration;
        float m_yaw;
+       s16 m_hp;
        struct LuaEntityProperties *m_prop;
        SmoothTranslator pos_translator;
        // Spritesheet/animation stuff
@@ -1712,6 +248,7 @@ public:
                m_velocity(v3f(0,0,0)),
                m_acceleration(v3f(0,0,0)),
                m_yaw(0),
+               m_hp(1),
                m_prop(new LuaEntityProperties),
                m_tx_size(1,1),
                m_tx_basepos(0,0),
@@ -1733,12 +270,14 @@ public:
                // version
                u8 version = readU8(is);
                // check version
-               if(version != 0)
+               if(version != 1)
                        return;
                // pos
                m_position = readV3F1000(is);
                // yaw
                m_yaw = readF1000(is);
+               // hp
+               m_hp = readS16(is);
                // properties
                std::istringstream prop_is(deSerializeLongString(is), std::ios::binary);
                m_prop->deSerialize(prop_is);
@@ -2000,7 +539,7 @@ public:
                std::istringstream is(data, std::ios::binary);
                // command
                u8 cmd = readU8(is);
-               if(cmd == 0) // update position
+               if(cmd == LUAENTITY_CMD_UPDATE_POSITION) // update position
                {
                        // do_interpolate
                        bool do_interpolate = readU8(is);
@@ -2025,12 +564,12 @@ public:
                        }
                        updateNodePos();
                }
-               else if(cmd == 1) // set texture modification
+               else if(cmd == LUAENTITY_CMD_SET_TEXTURE_MOD) // set texture modification
                {
                        std::string mod = deSerializeString(is);
                        updateTextures(mod);
                }
-               else if(cmd == 2) // set sprite
+               else if(cmd == LUAENTITY_CMD_SET_SPRITE) // set sprite
                {
                        v2s16 p = readV2S16(is);
                        int num_frames = readU16(is);
@@ -2044,6 +583,14 @@ public:
 
                        updateTexturePos();
                }
+               else if(cmd == LUAENTITY_CMD_PUNCHED)
+               {
+                       s16 damage = readS16(is);
+                       s16 result_hp = readS16(is);
+                       
+                       m_hp = result_hp;
+                       // TODO: Execute defined fast response
+               }
        }
 };
 
index b7a6db90676e404fb92c3289146f3bbee0414f1f..5c03c90539d9db0832760d12b2db2cdc3d8613eb 100644 (file)
@@ -29,1508 +29,306 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
 
-/* Some helper functions */
-
-// Y is copied, X and Z change is limited
-void accelerate_xz(v3f &speed, v3f target_speed, f32 max_increase)
-{
-       v3f d_wanted = target_speed - speed;
-       d_wanted.Y = 0;
-       f32 dl_wanted = d_wanted.getLength();
-       f32 dl = dl_wanted;
-       if(dl > max_increase)
-               dl = max_increase;
-       
-       v3f d = d_wanted.normalize() * dl;
-
-       speed.X += d.X;
-       speed.Z += d.Z;
-       speed.Y = target_speed.Y;
-}
-
 /*
-       TestSAO
-*/
-
-// Prototype
-TestSAO proto_TestSAO(NULL, v3f(0,0,0));
-
-TestSAO::TestSAO(ServerEnvironment *env, v3f pos):
-       ServerActiveObject(env, pos),
-       m_timer1(0),
-       m_age(0)
-{
-       ServerActiveObject::registerType(getType(), create);
-}
-
-ServerActiveObject* TestSAO::create(ServerEnvironment *env, v3f pos,
-               const std::string &data)
-{
-       return new TestSAO(env, pos);
-}
-
-void TestSAO::step(float dtime, bool send_recommended)
-{
-       m_age += dtime;
-       if(m_age > 10)
-       {
-               m_removed = true;
-               return;
-       }
-
-       m_base_position.Y += dtime * BS * 2;
-       if(m_base_position.Y > 8*BS)
-               m_base_position.Y = 2*BS;
-
-       if(send_recommended == false)
-               return;
-
-       m_timer1 -= dtime;
-       if(m_timer1 < 0.0)
-       {
-               m_timer1 += 0.125;
-
-               std::string data;
-
-               data += itos(0); // 0 = position
-               data += " ";
-               data += itos(m_base_position.X);
-               data += " ";
-               data += itos(m_base_position.Y);
-               data += " ";
-               data += itos(m_base_position.Z);
-
-               ActiveObjectMessage aom(getId(), false, data);
-               m_messages_out.push_back(aom);
-       }
-}
-
-
-/*
-       ItemSAO
-*/
-
-// Prototype
-ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");
-
-ItemSAO::ItemSAO(ServerEnvironment *env, v3f pos,
-               const std::string itemstring):
-       ServerActiveObject(env, pos),
-       m_itemstring(itemstring),
-       m_itemstring_changed(false),
-       m_speed_f(0,0,0),
-       m_last_sent_position(0,0,0)
-{
-       ServerActiveObject::registerType(getType(), create);
-}
-
-ServerActiveObject* ItemSAO::create(ServerEnvironment *env, v3f pos,
-               const std::string &data)
-{
-       std::istringstream is(data, std::ios::binary);
-       char buf[1];
-       // read version
-       is.read(buf, 1);
-       u8 version = buf[0];
-       // check if version is supported
-       if(version != 0)
-               return NULL;
-       std::string itemstring = deSerializeString(is);
-       infostream<<"ItemSAO::create(): Creating item \""
-                       <<itemstring<<"\""<<std::endl;
-       return new ItemSAO(env, pos, itemstring);
-}
-
-void ItemSAO::step(float dtime, bool send_recommended)
-{
-       ScopeProfiler sp2(g_profiler, "ItemSAO::step avg", SPT_AVG);
-
-       assert(m_env);
-
-       const float interval = 0.2;
-       if(m_move_interval.step(dtime, interval)==false)
-               return;
-       dtime = interval;
-       
-       core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
-       collisionMoveResult moveresult;
-       // Apply gravity
-       m_speed_f += v3f(0, -dtime*9.81*BS, 0);
-       // Maximum movement without glitches
-       f32 pos_max_d = BS*0.25;
-       // Limit speed
-       if(m_speed_f.getLength()*dtime > pos_max_d)
-               m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
-       v3f pos_f = getBasePosition();
-       v3f pos_f_old = pos_f;
-       IGameDef *gamedef = m_env->getGameDef();
-       moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
-                       pos_max_d, box, dtime, pos_f, m_speed_f);
-       
-       if(send_recommended == false)
-               return;
-
-       if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
-       {
-               setBasePosition(pos_f);
-               m_last_sent_position = pos_f;
-
-               std::ostringstream os(std::ios::binary);
-               // command (0 = update position)
-               writeU8(os, 0);
-               // pos
-               writeV3F1000(os, m_base_position);
-               // create message and add to list
-               ActiveObjectMessage aom(getId(), false, os.str());
-               m_messages_out.push_back(aom);
-       }
-       if(m_itemstring_changed)
-       {
-               m_itemstring_changed = false;
-
-               std::ostringstream os(std::ios::binary);
-               // command (1 = update itemstring)
-               writeU8(os, 1);
-               // itemstring
-               os<<serializeString(m_itemstring);
-               // create message and add to list
-               ActiveObjectMessage aom(getId(), false, os.str());
-               m_messages_out.push_back(aom);
-       }
-}
-
-std::string ItemSAO::getClientInitializationData()
-{
-       std::ostringstream os(std::ios::binary);
-       // version
-       writeU8(os, 0);
-       // pos
-       writeV3F1000(os, m_base_position);
-       // itemstring
-       os<<serializeString(m_itemstring);
-       return os.str();
-}
-
-std::string ItemSAO::getStaticData()
-{
-       infostream<<__FUNCTION_NAME<<std::endl;
-       std::ostringstream os(std::ios::binary);
-       // version
-       writeU8(os, 0);
-       // itemstring
-       os<<serializeString(m_itemstring);
-       return os.str();
-}
-
-ItemStack ItemSAO::createItemStack()
-{
-       try{
-               IItemDefManager *idef = m_env->getGameDef()->idef();
-               ItemStack item;
-               item.deSerialize(m_itemstring, idef);
-               infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring
-                               <<"\" -> item=\""<<item.getItemString()<<"\""
-                               <<std::endl;
-               return item;
-       }
-       catch(SerializationError &e)
-       {
-               infostream<<__FUNCTION_NAME<<": serialization error: "
-                               <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
-               return ItemStack();
-       }
-}
-
-void ItemSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
-{
-       // Allow removing items in creative mode
-       if(g_settings->getBool("creative_mode") == true)
-       {
-               m_removed = true;
-               return;
-       }
-
-       ItemStack item = createItemStack();
-       Inventory *inv = puncher->getInventory();
-       if(inv != NULL)
-       {
-               std::string wieldlist = puncher->getWieldList();
-               ItemStack leftover = inv->addItem(wieldlist, item);
-               puncher->setInventoryModified();
-               if(leftover.empty())
-               {
-                       m_removed = true;
-               }
-               else
-               {
-                       m_itemstring = leftover.getItemString();
-                       m_itemstring_changed = true;
-               }
-       }
-}
-
-/*
-       RatSAO
-*/
-
-// Prototype
-RatSAO proto_RatSAO(NULL, v3f(0,0,0));
-
-RatSAO::RatSAO(ServerEnvironment *env, v3f pos):
-       ServerActiveObject(env, pos),
-       m_is_active(false),
-       m_speed_f(0,0,0)
-{
-       ServerActiveObject::registerType(getType(), create);
-
-       m_oldpos = v3f(0,0,0);
-       m_last_sent_position = v3f(0,0,0);
-       m_yaw = myrand_range(0,PI*2);
-       m_counter1 = 0;
-       m_counter2 = 0;
-       m_age = 0;
-       m_touching_ground = false;
-}
-
-ServerActiveObject* RatSAO::create(ServerEnvironment *env, v3f pos,
-               const std::string &data)
-{
-       std::istringstream is(data, std::ios::binary);
-       char buf[1];
-       // read version
-       is.read(buf, 1);
-       u8 version = buf[0];
-       // check if version is supported
-       if(version != 0)
-               return NULL;
-       return new RatSAO(env, pos);
-}
-
-void RatSAO::step(float dtime, bool send_recommended)
-{
-       ScopeProfiler sp2(g_profiler, "RatSAO::step avg", SPT_AVG);
-
-       assert(m_env);
-
-       if(m_is_active == false)
-       {
-               if(m_inactive_interval.step(dtime, 0.5)==false)
-                       return;
-       }
-
-       /*
-               The AI
-       */
-
-       /*m_age += dtime;
-       if(m_age > 60)
-       {
-               // Die
-               m_removed = true;
-               return;
-       }*/
-
-       // Apply gravity
-       m_speed_f.Y -= dtime*9.81*BS;
-
-       /*
-               Move around if some player is close
-       */
-       bool player_is_close = false;
-       // Check connected players
-       core::list<Player*> players = m_env->getPlayers(true);
-       core::list<Player*>::Iterator i;
-       for(i = players.begin();
-                       i != players.end(); i++)
-       {
-               Player *player = *i;
-               v3f playerpos = player->getPosition();
-               if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
-               {
-                       player_is_close = true;
-                       break;
-               }
-       }
-
-       m_is_active = player_is_close;
-       
-       if(player_is_close == false)
-       {
-               m_speed_f.X = 0;
-               m_speed_f.Z = 0;
-       }
-       else
-       {
-               // Move around
-               v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
-               f32 speed = 2*BS;
-               m_speed_f.X = speed * dir.X;
-               m_speed_f.Z = speed * dir.Z;
-
-               if(m_touching_ground && (m_oldpos - m_base_position).getLength()
-                               < dtime*speed/2)
-               {
-                       m_counter1 -= dtime;
-                       if(m_counter1 < 0.0)
-                       {
-                               m_counter1 += 1.0;
-                               m_speed_f.Y = 5.0*BS;
-                       }
-               }
-
-               {
-                       m_counter2 -= dtime;
-                       if(m_counter2 < 0.0)
-                       {
-                               m_counter2 += (float)(myrand()%100)/100*3.0;
-                               m_yaw += ((float)(myrand()%200)-100)/100*180;
-                               m_yaw = wrapDegrees(m_yaw);
-                       }
-               }
-       }
-       
-       m_oldpos = m_base_position;
-
-       /*
-               Move it, with collision detection
-       */
-
-       core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
-       collisionMoveResult moveresult;
-       // Maximum movement without glitches
-       f32 pos_max_d = BS*0.25;
-       // Limit speed
-       if(m_speed_f.getLength()*dtime > pos_max_d)
-               m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
-       v3f pos_f = getBasePosition();
-       v3f pos_f_old = pos_f;
-       IGameDef *gamedef = m_env->getGameDef();
-       moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
-                       pos_max_d, box, dtime, pos_f, m_speed_f);
-       m_touching_ground = moveresult.touching_ground;
-       
-       setBasePosition(pos_f);
-
-       if(send_recommended == false)
-               return;
-
-       if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
-       {
-               m_last_sent_position = pos_f;
-
-               std::ostringstream os(std::ios::binary);
-               // command (0 = update position)
-               writeU8(os, 0);
-               // pos
-               writeV3F1000(os, m_base_position);
-               // yaw
-               writeF1000(os, m_yaw);
-               // create message and add to list
-               ActiveObjectMessage aom(getId(), false, os.str());
-               m_messages_out.push_back(aom);
-       }
-}
-
-std::string RatSAO::getClientInitializationData()
-{
-       std::ostringstream os(std::ios::binary);
-       // version
-       writeU8(os, 0);
-       // pos
-       writeV3F1000(os, m_base_position);
-       return os.str();
-}
-
-std::string RatSAO::getStaticData()
-{
-       //infostream<<__FUNCTION_NAME<<std::endl;
-       std::ostringstream os(std::ios::binary);
-       // version
-       writeU8(os, 0);
-       return os.str();
-}
-
-void RatSAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
-{
-       // Allow removing rats in creative mode
-       if(g_settings->getBool("creative_mode") == true)
-       {
-               m_removed = true;
-               return;
-       }
-
-       IItemDefManager *idef = m_env->getGameDef()->idef();
-       ItemStack item("rat", 1, 0, "", idef);
-       Inventory *inv = puncher->getInventory();
-       if(inv != NULL)
-       {
-               std::string wieldlist = puncher->getWieldList();
-               ItemStack leftover = inv->addItem(wieldlist, item);
-               puncher->setInventoryModified();
-               if(leftover.empty())
-                       m_removed = true;
-       }
-}
-
-/*
-       Oerkki1SAO
-*/
-
-// Prototype
-Oerkki1SAO proto_Oerkki1SAO(NULL, v3f(0,0,0));
-
-Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, v3f pos):
-       ServerActiveObject(env, pos),
-       m_is_active(false),
-       m_speed_f(0,0,0)
-{
-       ServerActiveObject::registerType(getType(), create);
-
-       m_oldpos = v3f(0,0,0);
-       m_last_sent_position = v3f(0,0,0);
-       m_yaw = 0;
-       m_counter1 = 0;
-       m_counter2 = 0;
-       m_age = 0;
-       m_touching_ground = false;
-       m_hp = 20;
-       m_after_jump_timer = 0;
-}
-
-ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, v3f pos,
-               const std::string &data)
-{
-       std::istringstream is(data, std::ios::binary);
-       // read version
-       u8 version = readU8(is);
-       // read hp
-       u8 hp = readU8(is);
-       // check if version is supported
-       if(version != 0)
-               return NULL;
-       Oerkki1SAO *o = new Oerkki1SAO(env, pos);
-       o->m_hp = hp;
-       return o;
-}
-
-void Oerkki1SAO::step(float dtime, bool send_recommended)
-{
-       ScopeProfiler sp2(g_profiler, "Oerkki1SAO::step avg", SPT_AVG);
-
-       assert(m_env);
-
-       if(m_is_active == false)
-       {
-               if(m_inactive_interval.step(dtime, 0.5)==false)
-                       return;
-       }
-
-       /*
-               The AI
-       */
-
-       m_age += dtime;
-       if(m_age > 120)
-       {
-               // Die
-               m_removed = true;
-               return;
-       }
-
-       m_after_jump_timer -= dtime;
-
-       v3f old_speed = m_speed_f;
-
-       // Apply gravity
-       m_speed_f.Y -= dtime*9.81*BS;
-
-       /*
-               Move around if some player is close
-       */
-       bool player_is_close = false;
-       bool player_is_too_close = false;
-       v3f near_player_pos;
-       // Check connected players
-       core::list<Player*> players = m_env->getPlayers(true);
-       core::list<Player*>::Iterator i;
-       for(i = players.begin();
-                       i != players.end(); i++)
-       {
-               Player *player = *i;
-               v3f playerpos = player->getPosition();
-               f32 dist = m_base_position.getDistanceFrom(playerpos);
-               if(dist < BS*0.6)
-               {
-                       m_removed = true;
-                       return;
-                       player_is_too_close = true;
-                       near_player_pos = playerpos;
-               }
-               else if(dist < BS*15.0 && !player_is_too_close)
-               {
-                       player_is_close = true;
-                       near_player_pos = playerpos;
-               }
-       }
-
-       m_is_active = player_is_close;
-
-       v3f target_speed = m_speed_f;
-
-       if(!player_is_close)
-       {
-               target_speed = v3f(0,0,0);
-       }
-       else
-       {
-               // Move around
-
-               v3f ndir = near_player_pos - m_base_position;
-               ndir.Y = 0;
-               ndir.normalize();
-
-               f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X);
-               if(nyaw < m_yaw - 180)
-                       nyaw += 360;
-               else if(nyaw > m_yaw + 180)
-                       nyaw -= 360;
-               m_yaw = 0.95*m_yaw + 0.05*nyaw;
-               m_yaw = wrapDegrees(m_yaw);
-               
-               f32 speed = 2*BS;
-
-               if((m_touching_ground || m_after_jump_timer > 0.0)
-                               && !player_is_too_close)
-               {
-                       v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
-                       target_speed.X = speed * dir.X;
-                       target_speed.Z = speed * dir.Z;
-               }
-
-               if(m_touching_ground && (m_oldpos - m_base_position).getLength()
-                               < dtime*speed/2)
-               {
-                       m_counter1 -= dtime;
-                       if(m_counter1 < 0.0)
-                       {
-                               m_counter1 += 0.2;
-                               // Jump
-                               target_speed.Y = 5.0*BS;
-                               m_after_jump_timer = 1.0;
-                       }
-               }
-
-               {
-                       m_counter2 -= dtime;
-                       if(m_counter2 < 0.0)
-                       {
-                               m_counter2 += (float)(myrand()%100)/100*3.0;
-                               //m_yaw += ((float)(myrand()%200)-100)/100*180;
-                               m_yaw += ((float)(myrand()%200)-100)/100*90;
-                               m_yaw = wrapDegrees(m_yaw);
-                       }
-               }
-       }
-       
-       if((m_speed_f - target_speed).getLength() > BS*4 || player_is_too_close)
-               accelerate_xz(m_speed_f, target_speed, dtime*BS*8);
-       else
-               accelerate_xz(m_speed_f, target_speed, dtime*BS*4);
-       
-       m_oldpos = m_base_position;
-
-       /*
-               Move it, with collision detection
-       */
-
-       core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.);
-       collisionMoveResult moveresult;
-       // Maximum movement without glitches
-       f32 pos_max_d = BS*0.25;
-       /*// Limit speed
-       if(m_speed_f.getLength()*dtime > pos_max_d)
-               m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);*/
-       v3f pos_f = getBasePosition();
-       v3f pos_f_old = pos_f;
-       IGameDef *gamedef = m_env->getGameDef();
-       moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
-                       pos_max_d, box, dtime, pos_f, m_speed_f);
-       m_touching_ground = moveresult.touching_ground;
-       
-       // Do collision damage
-       float tolerance = BS*30;
-       float factor = BS*0.5;
-       v3f speed_diff = old_speed - m_speed_f;
-       // Increase effect in X and Z
-       speed_diff.X *= 2;
-       speed_diff.Z *= 2;
-       float vel = speed_diff.getLength();
-       if(vel > tolerance)
-       {
-               f32 damage_f = (vel - tolerance)/BS*factor;
-               u16 damage = (u16)(damage_f+0.5);
-               doDamage(damage);
-       }
-
-       setBasePosition(pos_f);
-
-       if(send_recommended == false && m_speed_f.getLength() < 3.0*BS)
-               return;
-
-       if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
-       {
-               m_last_sent_position = pos_f;
-
-               std::ostringstream os(std::ios::binary);
-               // command (0 = update position)
-               writeU8(os, 0);
-               // pos
-               writeV3F1000(os, m_base_position);
-               // yaw
-               writeF1000(os, m_yaw);
-               // create message and add to list
-               ActiveObjectMessage aom(getId(), false, os.str());
-               m_messages_out.push_back(aom);
-       }
-}
-
-std::string Oerkki1SAO::getClientInitializationData()
-{
-       std::ostringstream os(std::ios::binary);
-       // version
-       writeU8(os, 0);
-       // pos
-       writeV3F1000(os, m_base_position);
-       return os.str();
-}
-
-std::string Oerkki1SAO::getStaticData()
-{
-       //infostream<<__FUNCTION_NAME<<std::endl;
-       std::ostringstream os(std::ios::binary);
-       // version
-       writeU8(os, 0);
-       // hp
-       writeU8(os, m_hp);
-       return os.str();
-}
-
-void Oerkki1SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
-{
-       if(!puncher)
-               return;
-       
-       v3f dir = (getBasePosition() - puncher->getBasePosition()).normalize();
-       m_speed_f += dir*12*BS;
-
-       // "Material" groups of the object
-       ItemGroupList groups;
-       groups["snappy"] = 1;
-       groups["choppy"] = 1;
-       groups["fleshy"] = 3;
-
-       IItemDefManager *idef = m_env->getGameDef()->idef();
-       ItemStack punchitem = puncher->getWieldedItem();
-       ToolCapabilities tp = punchitem.getToolCapabilities(idef);
-
-       HitParams hit_params = getHitParams(groups, &tp,
-                       time_from_last_punch);
-
-       doDamage(hit_params.hp);
-       if(g_settings->getBool("creative_mode") == false)
-       {
-               punchitem.addWear(hit_params.wear, idef);
-               puncher->setWieldedItem(punchitem);
-       }
-}
-
-void Oerkki1SAO::doDamage(u16 d)
-{
-       infostream<<"oerkki damage: "<<d<<std::endl;
-       
-       if(d < m_hp)
-       {
-               m_hp -= d;
-       }
-       else
-       {
-               // Die
-               m_hp = 0;
-               m_removed = true;
-       }
-
-       {
-               std::ostringstream os(std::ios::binary);
-               // command (1 = damage)
-               writeU8(os, 1);
-               // amount
-               writeU8(os, d);
-               // create message and add to list
-               ActiveObjectMessage aom(getId(), false, os.str());
-               m_messages_out.push_back(aom);
-       }
-}
-
-/*
-       FireflySAO
-*/
-
-// Prototype
-FireflySAO proto_FireflySAO(NULL, v3f(0,0,0));
-
-FireflySAO::FireflySAO(ServerEnvironment *env, v3f pos):
-       ServerActiveObject(env, pos),
-       m_is_active(false),
-       m_speed_f(0,0,0)
-{
-       ServerActiveObject::registerType(getType(), create);
-
-       m_oldpos = v3f(0,0,0);
-       m_last_sent_position = v3f(0,0,0);
-       m_yaw = 0;
-       m_counter1 = 0;
-       m_counter2 = 0;
-       m_age = 0;
-       m_touching_ground = false;
-}
-
-ServerActiveObject* FireflySAO::create(ServerEnvironment *env, v3f pos,
-               const std::string &data)
-{
-       std::istringstream is(data, std::ios::binary);
-       char buf[1];
-       // read version
-       is.read(buf, 1);
-       u8 version = buf[0];
-       // check if version is supported
-       if(version != 0)
-               return NULL;
-       return new FireflySAO(env, pos);
-}
-
-void FireflySAO::step(float dtime, bool send_recommended)
-{
-       ScopeProfiler sp2(g_profiler, "FireflySAO::step avg", SPT_AVG);
-
-       assert(m_env);
-
-       if(m_is_active == false)
-       {
-               if(m_inactive_interval.step(dtime, 0.5)==false)
-                       return;
-       }
-
-       /*
-               The AI
-       */
-
-       // Apply (less) gravity
-       m_speed_f.Y -= dtime*3*BS;
-
-       /*
-               Move around if some player is close
-       */
-       bool player_is_close = false;
-       // Check connected players
-       core::list<Player*> players = m_env->getPlayers(true);
-       core::list<Player*>::Iterator i;
-       for(i = players.begin();
-                       i != players.end(); i++)
-       {
-               Player *player = *i;
-               v3f playerpos = player->getPosition();
-               if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
-               {
-                       player_is_close = true;
-                       break;
-               }
-       }
-
-       m_is_active = player_is_close;
-       
-       if(player_is_close == false)
-       {
-               m_speed_f.X = 0;
-               m_speed_f.Z = 0;
-       }
-       else
-       {
-               // Move around
-               v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
-               f32 speed = BS/2;
-               m_speed_f.X = speed * dir.X;
-               m_speed_f.Z = speed * dir.Z;
-
-               if(m_touching_ground && (m_oldpos - m_base_position).getLength()
-                               < dtime*speed/2)
-               {
-                       m_counter1 -= dtime;
-                       if(m_counter1 < 0.0)
-                       {
-                               m_counter1 += 1.0;
-                               m_speed_f.Y = 5.0*BS;
-                       }
-               }
+       DummyLoadSAO
+*/
 
-               {
-                       m_counter2 -= dtime;
-                       if(m_counter2 < 0.0)
-                       {
-                               m_counter2 += (float)(myrand()%100)/100*3.0;
-                               m_yaw += ((float)(myrand()%200)-100)/100*180;
-                               m_yaw = wrapDegrees(m_yaw);
-                       }
-               }
+class DummyLoadSAO : public ServerActiveObject
+{
+public:
+       DummyLoadSAO(ServerEnvironment *env, v3f pos, u8 type):
+               ServerActiveObject(env, pos)
+       {
+               ServerActiveObject::registerType(type, create);
        }
+       // Pretend to be the test object (to fool the client)
+       u8 getType() const
+       { return ACTIVEOBJECT_TYPE_TEST; }
+       // And never save to disk
+       bool isStaticAllowed() const
+       { return false; }
        
-       m_oldpos = m_base_position;
-
-       /*
-               Move it, with collision detection
-       */
-
-       core::aabbox3d<f32> box(-BS/3.,-BS*2/3.0,-BS/3., BS/3.,BS*4./3.,BS/3.);
-       collisionMoveResult moveresult;
-       // Maximum movement without glitches
-       f32 pos_max_d = BS*0.25;
-       // Limit speed
-       if(m_speed_f.getLength()*dtime > pos_max_d)
-               m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
-       v3f pos_f = getBasePosition();
-       v3f pos_f_old = pos_f;
-       IGameDef *gamedef = m_env->getGameDef();
-       moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
-                       pos_max_d, box, dtime, pos_f, m_speed_f);
-       m_touching_ground = moveresult.touching_ground;
-       
-       setBasePosition(pos_f);
-
-       if(send_recommended == false)
-               return;
-
-       if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
+       static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
+                       const std::string &data)
        {
-               m_last_sent_position = pos_f;
+               return new DummyLoadSAO(env, pos, 0);
+       }
 
-               std::ostringstream os(std::ios::binary);
-               // command (0 = update position)
-               writeU8(os, 0);
-               // pos
-               writeV3F1000(os, m_base_position);
-               // yaw
-               writeF1000(os, m_yaw);
-               // create message and add to list
-               ActiveObjectMessage aom(getId(), false, os.str());
-               m_messages_out.push_back(aom);
+       void step(float dtime, bool send_recommended)
+       {
+               m_removed = true;
+               infostream<<"DummyLoadSAO step"<<std::endl;
        }
-}
 
-std::string FireflySAO::getClientInitializationData()
-{
-       std::ostringstream os(std::ios::binary);
-       // version
-       writeU8(os, 0);
-       // pos
-       writeV3F1000(os, m_base_position);
-       return os.str();
-}
+private:
+};
 
-std::string FireflySAO::getStaticData()
-{
-       //infostream<<__FUNCTION_NAME<<std::endl;
-       std::ostringstream os(std::ios::binary);
-       // version
-       writeU8(os, 0);
-       return os.str();
-}
+// Prototype (registers item for deserialization)
+DummyLoadSAO proto1_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_RAT);
+DummyLoadSAO proto2_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_OERKKI1);
+DummyLoadSAO proto3_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_FIREFLY);
+DummyLoadSAO proto4_DummyLoadSAO(NULL, v3f(0,0,0), ACTIVEOBJECT_TYPE_MOBV2);
 
 /*
-       MobV2SAO
+       TestSAO
 */
 
-// Prototype
-MobV2SAO proto_MobV2SAO(NULL, v3f(0,0,0), NULL);
-
-MobV2SAO::MobV2SAO(ServerEnvironment *env, v3f pos,
-               Settings *init_properties):
-       ServerActiveObject(env, pos),
-       m_move_type("ground_nodes"),
-       m_speed(0,0,0),
-       m_last_sent_position(0,0,0),
-       m_oldpos(0,0,0),
-       m_yaw(0),
-       m_counter1(0),
-       m_counter2(0),
-       m_age(0),
-       m_touching_ground(false),
-       m_hp(10),
-       m_walk_around(false),
-       m_walk_around_timer(0),
-       m_next_pos_exists(false),
-       m_shoot_reload_timer(0),
-       m_shooting(false),
-       m_shooting_timer(0),
-       m_falling(false),
-       m_disturb_timer(100000),
-       m_random_disturb_timer(0),
-       m_shoot_y(0)
+class TestSAO : public ServerActiveObject
 {
-       ServerActiveObject::registerType(getType(), create);
-       
-       m_properties = new Settings();
-       if(init_properties)
-               m_properties->update(*init_properties);
-       
-       m_properties->setV3F("pos", pos);
-       
-       setPropertyDefaults();
-       readProperties();
-}
+public:
+       TestSAO(ServerEnvironment *env, v3f pos):
+               ServerActiveObject(env, pos),
+               m_timer1(0),
+               m_age(0)
+       {
+               ServerActiveObject::registerType(getType(), create);
+       }
+       u8 getType() const
+       { return ACTIVEOBJECT_TYPE_TEST; }
        
-MobV2SAO::~MobV2SAO()
-{
-       delete m_properties;
-}
-
-ServerActiveObject* MobV2SAO::create(ServerEnvironment *env, v3f pos,
-               const std::string &data)
-{
-       std::istringstream is(data, std::ios::binary);
-       Settings properties;
-       properties.parseConfigLines(is, "MobArgsEnd");
-       MobV2SAO *o = new MobV2SAO(env, pos, &properties);
-       return o;
-}
-
-std::string MobV2SAO::getStaticData()
-{
-       updateProperties();
-
-       std::ostringstream os(std::ios::binary);
-       m_properties->writeLines(os);
-       return os.str();
-}
-
-std::string MobV2SAO::getClientInitializationData()
-{
-       //infostream<<__FUNCTION_NAME<<std::endl;
+       static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
+                       const std::string &data)
+       {
+               return new TestSAO(env, pos);
+       }
 
-       updateProperties();
+       void step(float dtime, bool send_recommended)
+       {
+               m_age += dtime;
+               if(m_age > 10)
+               {
+                       m_removed = true;
+                       return;
+               }
 
-       std::ostringstream os(std::ios::binary);
+               m_base_position.Y += dtime * BS * 2;
+               if(m_base_position.Y > 8*BS)
+                       m_base_position.Y = 2*BS;
 
-       // version
-       writeU8(os, 0);
-       
-       Settings client_properties;
-       
-       /*client_properties.set("version", "0");
-       client_properties.updateValue(*m_properties, "pos");
-       client_properties.updateValue(*m_properties, "yaw");
-       client_properties.updateValue(*m_properties, "hp");*/
+               if(send_recommended == false)
+                       return;
 
-       // Just send everything for simplicity
-       client_properties.update(*m_properties);
+               m_timer1 -= dtime;
+               if(m_timer1 < 0.0)
+               {
+                       m_timer1 += 0.125;
 
-       std::ostringstream os2(std::ios::binary);
-       client_properties.writeLines(os2);
-       compressZlib(os2.str(), os);
+                       std::string data;
 
-       return os.str();
-}
+                       data += itos(0); // 0 = position
+                       data += " ";
+                       data += itos(m_base_position.X);
+                       data += " ";
+                       data += itos(m_base_position.Y);
+                       data += " ";
+                       data += itos(m_base_position.Z);
 
-bool checkFreePosition(Map *map, v3s16 p0, v3s16 size)
-{
-       for(int dx=0; dx<size.X; dx++)
-       for(int dy=0; dy<size.Y; dy++)
-       for(int dz=0; dz<size.Z; dz++){
-               v3s16 dp(dx, dy, dz);
-               v3s16 p = p0 + dp;
-               MapNode n = map->getNodeNoEx(p);
-               if(n.getContent() != CONTENT_AIR)
-                       return false;
+                       ActiveObjectMessage aom(getId(), false, data);
+                       m_messages_out.push_back(aom);
+               }
        }
-       return true;
-}
-
-bool checkWalkablePosition(Map *map, v3s16 p0)
-{
-       v3s16 p = p0 + v3s16(0,-1,0);
-       MapNode n = map->getNodeNoEx(p);
-       if(n.getContent() != CONTENT_AIR)
-               return true;
-       return false;
-}
 
-bool checkFreeAndWalkablePosition(Map *map, v3s16 p0, v3s16 size)
-{
-       if(!checkFreePosition(map, p0, size))
-               return false;
-       if(!checkWalkablePosition(map, p0))
-               return false;
-       return true;
-}
+private:
+       float m_timer1;
+       float m_age;
+};
 
-static void get_random_u32_array(u32 a[], u32 len)
-{
-       u32 i, n;
-       for(i=0; i<len; i++)
-               a[i] = i;
-       n = len;
-       while(n > 1){
-               u32 k = myrand() % n;
-               n--;
-               u32 temp = a[n];
-               a[n] = a[k];
-               a[k] = temp;
-       }
-}
+// Prototype (registers item for deserialization)
+TestSAO proto_TestSAO(NULL, v3f(0,0,0));
 
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
+/*
+       ItemSAO
+*/
 
-static void explodeSquare(Map *map, v3s16 p0, v3s16 size)
+class ItemSAO : public ServerActiveObject
 {
-       core::map<v3s16, MapBlock*> modified_blocks;
-
-       for(int dx=0; dx<size.X; dx++)
-       for(int dy=0; dy<size.Y; dy++)
-       for(int dz=0; dz<size.Z; dz++){
-               v3s16 dp(dx - size.X/2, dy - size.Y/2, dz - size.Z/2);
-               v3s16 p = p0 + dp;
-               MapNode n = map->getNodeNoEx(p);
-               if(n.getContent() == CONTENT_IGNORE)
-                       continue;
-               //map->removeNodeWithEvent(p);
-               map->removeNodeAndUpdate(p, modified_blocks);
-       }
-
-       // Send a MEET_OTHER event
-       MapEditEvent event;
-       event.type = MEET_OTHER;
-       for(core::map<v3s16, MapBlock*>::Iterator
-                 i = modified_blocks.getIterator();
-                 i.atEnd() == false; i++)
+public:
+       u8 getType() const
+       { return ACTIVEOBJECT_TYPE_ITEM; }
+       
+       float getMinimumSavedMovement()
+       { return 0.1*BS; }
+
+       static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
+                       const std::string &data)
+       {
+               std::istringstream is(data, std::ios::binary);
+               char buf[1];
+               // read version
+               is.read(buf, 1);
+               u8 version = buf[0];
+               // check if version is supported
+               if(version != 0)
+                       return NULL;
+               std::string itemstring = deSerializeString(is);
+               infostream<<"create(): Creating item \""
+                               <<itemstring<<"\""<<std::endl;
+               return new ItemSAO(env, pos, itemstring);
+       }
+
+       ItemSAO(ServerEnvironment *env, v3f pos,
+                       const std::string itemstring):
+               ServerActiveObject(env, pos),
+               m_itemstring(itemstring),
+               m_itemstring_changed(false),
+               m_speed_f(0,0,0),
+               m_last_sent_position(0,0,0)
        {
-               v3s16 p = i.getNode()->getKey();
-               event.modified_blocks.insert(p, true);
+               ServerActiveObject::registerType(getType(), create);
        }
-       map->dispatchEvent(&event);
-}
 
-void MobV2SAO::step(float dtime, bool send_recommended)
-{
-       ScopeProfiler sp2(g_profiler, "MobV2SAO::step avg", SPT_AVG);
+       void step(float dtime, bool send_recommended)
+       {
+               ScopeProfiler sp2(g_profiler, "step avg", SPT_AVG);
 
-       assert(m_env);
-       Map *map = &m_env->getMap();
+               assert(m_env);
 
-       m_age += dtime;
+               const float interval = 0.2;
+               if(m_move_interval.step(dtime, interval)==false)
+                       return;
+               dtime = interval;
+               
+               core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
+               collisionMoveResult moveresult;
+               // Apply gravity
+               m_speed_f += v3f(0, -dtime*9.81*BS, 0);
+               // Maximum movement without glitches
+               f32 pos_max_d = BS*0.25;
+               // Limit speed
+               if(m_speed_f.getLength()*dtime > pos_max_d)
+                       m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
+               v3f pos_f = getBasePosition();
+               v3f pos_f_old = pos_f;
+               IGameDef *gamedef = m_env->getGameDef();
+               moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
+                               pos_max_d, box, dtime, pos_f, m_speed_f);
+               
+               if(send_recommended == false)
+                       return;
 
-       if(m_die_age >= 0.0 && m_age >= m_die_age){
-               m_removed = true;
-               return;
+               if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
+               {
+                       setBasePosition(pos_f);
+                       m_last_sent_position = pos_f;
+
+                       std::ostringstream os(std::ios::binary);
+                       // command (0 = update position)
+                       writeU8(os, 0);
+                       // pos
+                       writeV3F1000(os, m_base_position);
+                       // create message and add to list
+                       ActiveObjectMessage aom(getId(), false, os.str());
+                       m_messages_out.push_back(aom);
+               }
+               if(m_itemstring_changed)
+               {
+                       m_itemstring_changed = false;
+
+                       std::ostringstream os(std::ios::binary);
+                       // command (1 = update itemstring)
+                       writeU8(os, 1);
+                       // itemstring
+                       os<<serializeString(m_itemstring);
+                       // create message and add to list
+                       ActiveObjectMessage aom(getId(), false, os.str());
+                       m_messages_out.push_back(aom);
+               }
        }
 
-       m_random_disturb_timer += dtime;
-       if(m_random_disturb_timer >= 5.0)
+       std::string getClientInitializationData()
        {
-               m_random_disturb_timer = 0;
-               // Check connected players
-               core::list<Player*> players = m_env->getPlayers(true);
-               core::list<Player*>::Iterator i;
-               for(i = players.begin();
-                               i != players.end(); i++)
-               {
-                       Player *player = *i;
-                       v3f playerpos = player->getPosition();
-                       f32 dist = m_base_position.getDistanceFrom(playerpos);
-                       if(dist < BS*16)
-                       {
-                               if(myrand_range(0,3) == 0){
-                                       actionstream<<"Mob id="<<m_id<<" at "
-                                                       <<PP(m_base_position/BS)
-                                                       <<" got randomly disturbed by "
-                                                       <<player->getName()<<std::endl;
-                                       m_disturbing_player = player->getName();
-                                       m_disturb_timer = 0;
-                                       break;
-                               }
-                       }
-               }
+               std::ostringstream os(std::ios::binary);
+               // version
+               writeU8(os, 0);
+               // pos
+               writeV3F1000(os, m_base_position);
+               // itemstring
+               os<<serializeString(m_itemstring);
+               return os.str();
        }
 
-       Player *disturbing_player =
-                       m_env->getPlayer(m_disturbing_player.c_str());
-       v3f disturbing_player_off = v3f(0,1,0);
-       v3f disturbing_player_norm = v3f(0,1,0);
-       float disturbing_player_distance = 1000000;
-       float disturbing_player_dir = 0;
-       if(disturbing_player){
-               disturbing_player_off =
-                               disturbing_player->getPosition() - m_base_position;
-               disturbing_player_distance = disturbing_player_off.getLength();
-               disturbing_player_norm = disturbing_player_off;
-               disturbing_player_norm.normalize();
-               disturbing_player_dir = 180./PI*atan2(disturbing_player_norm.Z,
-                               disturbing_player_norm.X);
+       std::string getStaticData()
+       {
+               infostream<<__FUNCTION_NAME<<std::endl;
+               std::ostringstream os(std::ios::binary);
+               // version
+               writeU8(os, 0);
+               // itemstring
+               os<<serializeString(m_itemstring);
+               return os.str();
        }
 
-       m_disturb_timer += dtime;
-       
-       if(!m_falling)
+       ItemStack createItemStack()
        {
-               m_shooting_timer -= dtime;
-               if(m_shooting_timer <= 0.0 && m_shooting){
-                       m_shooting = false;
-                       
-                       std::string shoot_type = m_properties->get("shoot_type");
-                       v3f shoot_pos(0,0,0);
-                       shoot_pos.Y += m_properties->getFloat("shoot_y") * BS;
-                       if(shoot_type == "fireball"){
-                               v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
-                               dir.Y = m_shoot_y;
-                               dir.normalize();
-                               v3f speed = dir * BS * 10.0;
-                               v3f pos = m_base_position + shoot_pos;
-                               infostream<<__FUNCTION_NAME<<": Mob id="<<m_id
-                                               <<" shooting fireball from "<<PP(pos)
-                                               <<" at speed "<<PP(speed)<<std::endl;
-                               Settings properties;
-                               properties.set("looks", "fireball");
-                               properties.setV3F("speed", speed);
-                               properties.setFloat("die_age", 5.0);
-                               properties.set("move_type", "constant_speed");
-                               properties.setFloat("hp", 1000);
-                               properties.set("lock_full_brightness", "true");
-                               properties.set("player_hit_damage", "9");
-                               properties.set("player_hit_distance", "2");
-                               properties.set("player_hit_interval", "1");
-                               ServerActiveObject *obj = new MobV2SAO(m_env,
-                                               pos, &properties);
-                               //m_env->addActiveObjectAsStatic(obj);
-                               m_env->addActiveObject(obj);
-                       } else {
-                               infostream<<__FUNCTION_NAME<<": Mob id="<<m_id
-                                               <<": Unknown shoot_type="<<shoot_type
-                                               <<std::endl;
-                       }
+               try{
+                       IItemDefManager *idef = m_env->getGameDef()->idef();
+                       ItemStack item;
+                       item.deSerialize(m_itemstring, idef);
+                       infostream<<__FUNCTION_NAME<<": m_itemstring=\""<<m_itemstring
+                                       <<"\" -> item=\""<<item.getItemString()<<"\""
+                                       <<std::endl;
+                       return item;
                }
-
-               m_shoot_reload_timer += dtime;
-
-               float reload_time = 15.0;
-               if(m_disturb_timer <= 15.0)
-                       reload_time = 3.0;
-
-               bool shoot_without_player = false;
-               if(m_properties->getBool("mindless_rage"))
-                       shoot_without_player = true;
-
-               if(!m_shooting && m_shoot_reload_timer >= reload_time &&
-                               !m_next_pos_exists &&
-                               (m_disturb_timer <= 60.0 || shoot_without_player))
+               catch(SerializationError &e)
                {
-                       m_shoot_y = 0;
-                       if(m_disturb_timer < 60.0 && disturbing_player &&
-                                       disturbing_player_distance < 16*BS &&
-                                       fabs(disturbing_player_norm.Y) < 0.8){
-                               m_yaw = disturbing_player_dir;
-                               sendPosition();
-                               m_shoot_y += disturbing_player_norm.Y;
-                       } else {
-                               m_shoot_y = 0.01 * myrand_range(-30,10);
-                       }
-                       m_shoot_reload_timer = 0.0;
-                       m_shooting = true;
-                       m_shooting_timer = 1.5;
-                       {
-                               std::ostringstream os(std::ios::binary);
-                               // command (2 = shooting)
-                               writeU8(os, 2);
-                               // time
-                               writeF1000(os, m_shooting_timer + 0.1);
-                               // bright?
-                               writeU8(os, true);
-                               // create message and add to list
-                               ActiveObjectMessage aom(getId(), false, os.str());
-                               m_messages_out.push_back(aom);
-                       }
+                       infostream<<__FUNCTION_NAME<<": serialization error: "
+                                       <<"m_itemstring=\""<<m_itemstring<<"\""<<std::endl;
+                       return ItemStack();
                }
        }
-       
-       if(m_move_type == "ground_nodes")
-       {
-               if(!m_shooting){
-                       m_walk_around_timer -= dtime;
-                       if(m_walk_around_timer <= 0.0){
-                               m_walk_around = !m_walk_around;
-                               if(m_walk_around)
-                                       m_walk_around_timer = 0.1*myrand_range(10,50);
-                               else
-                                       m_walk_around_timer = 0.1*myrand_range(30,70);
-                       }
-               }
-
-               /* Move */
-               if(m_next_pos_exists){
-                       v3f pos_f = m_base_position;
-                       v3f next_pos_f = intToFloat(m_next_pos_i, BS);
-
-                       v3f v = next_pos_f - pos_f;
-                       m_yaw = atan2(v.Z, v.X) / PI * 180;
-                       
-                       v3f diff = next_pos_f - pos_f;
-                       v3f dir = diff;
-                       dir.normalize();
-                       float speed = BS * 0.5;
-                       if(m_falling)
-                               speed = BS * 3.0;
-                       dir *= dtime * speed;
-                       bool arrived = false;
-                       if(dir.getLength() > diff.getLength()){
-                               dir = diff;
-                               arrived = true;
-                       }
-                       pos_f += dir;
-                       m_base_position = pos_f;
 
-                       if((pos_f - next_pos_f).getLength() < 0.1 || arrived){
-                               m_next_pos_exists = false;
-                       }
-               }
-
-               v3s16 pos_i = floatToInt(m_base_position, BS);
-               v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
-               v3s16 pos_size_off(0,0,0);
-               if(m_size.X >= 2.5){
-                       pos_size_off.X = -1;
-                       pos_size_off.Y = -1;
+       int punch(v3f dir,
+                       const ToolCapabilities *toolcap,
+                       ServerActiveObject *puncher,
+                       float time_from_last_punch)
+       {
+               // Directly delete item in creative mode
+               if(g_settings->getBool("creative_mode") == true)
+               {
+                       m_removed = true;
+                       return 0;
                }
                
-               if(!m_next_pos_exists){
-                       /* Check whether to drop down */
-                       if(checkFreePosition(map,
-                                       pos_i + pos_size_off + v3s16(0,-1,0), size_blocks)){
-                               m_next_pos_i = pos_i + v3s16(0,-1,0);
-                               m_next_pos_exists = true;
-                               m_falling = true;
-                       } else {
-                               m_falling = false;
-                       }
-               }
-
-               if(m_walk_around)
+               // Take item into inventory
+               ItemStack item = createItemStack();
+               Inventory *inv = puncher->getInventory();
+               if(inv != NULL)
                {
-                       if(!m_next_pos_exists){
-                               /* Find some position where to go next */
-                               v3s16 dps[3*3*3];
-                               int num_dps = 0;
-                               for(int dx=-1; dx<=1; dx++)
-                               for(int dy=-1; dy<=1; dy++)
-                               for(int dz=-1; dz<=1; dz++){
-                                       if(dx == 0 && dy == 0)
-                                               continue;
-                                       if(dx != 0 && dz != 0 && dy != 0)
-                                               continue;
-                                       dps[num_dps++] = v3s16(dx,dy,dz);
-                               }
-                               u32 order[3*3*3];
-                               get_random_u32_array(order, num_dps);
-                               for(int i=0; i<num_dps; i++){
-                                       v3s16 p = dps[order[i]] + pos_i;
-                                       bool is_free = checkFreeAndWalkablePosition(map,
-                                                       p + pos_size_off, size_blocks);
-                                       if(!is_free)
-                                               continue;
-                                       m_next_pos_i = p;
-                                       m_next_pos_exists = true;
-                                       break;
-                               }
+                       std::string wieldlist = puncher->getWieldList();
+                       ItemStack leftover = inv->addItem(wieldlist, item);
+                       puncher->setInventoryModified();
+                       if(leftover.empty())
+                       {
+                               m_removed = true;
+                       }
+                       else
+                       {
+                               m_itemstring = leftover.getItemString();
+                               m_itemstring_changed = true;
                        }
                }
-       }
-       else if(m_move_type == "constant_speed")
-       {
-               m_base_position += m_speed * dtime;
                
-               v3s16 pos_i = floatToInt(m_base_position, BS);
-               v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
-               v3s16 pos_size_off(0,0,0);
-               if(m_size.X >= 2.5){
-                       pos_size_off.X = -1;
-                       pos_size_off.Y = -1;
-               }
-               bool free = checkFreePosition(map, pos_i + pos_size_off, size_blocks);
-               if(!free){
-                       explodeSquare(map, pos_i, v3s16(3,3,3));
-                       m_removed = true;
-                       return;
-               }
-       }
-       else
-       {
-               errorstream<<"MobV2SAO::step(): id="<<m_id<<" unknown move_type=\""
-                               <<m_move_type<<"\""<<std::endl;
+               return 0;
        }
 
-       if(send_recommended == false)
-               return;
-
-       if(m_base_position.getDistanceFrom(m_last_sent_position) > 0.05*BS)
-       {
-               sendPosition();
-       }
-}
-
-void MobV2SAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
-{
-       if(!puncher)
-               return;
-       
-       v3f dir = (getBasePosition() - puncher->getBasePosition()).normalize();
-
-       // A quick hack; SAO description is player name for player
-       std::string playername = puncher->getDescription();
-
-       Map *map = &m_env->getMap();
-       
-       actionstream<<playername<<" punches mob id="<<m_id
-                       <<" at "<<PP(m_base_position/BS)<<std::endl;
-
-       m_disturb_timer = 0;
-       m_disturbing_player = playername;
-       m_next_pos_exists = false; // Cancel moving immediately
-       
-       m_yaw = wrapDegrees_180(180./PI*atan2(dir.Z, dir.X) + 180.);
-       v3f new_base_position = m_base_position + dir * BS;
-       {
-               v3s16 pos_i = floatToInt(new_base_position, BS);
-               v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
-               v3s16 pos_size_off(0,0,0);
-               if(m_size.X >= 2.5){
-                       pos_size_off.X = -1;
-                       pos_size_off.Y = -1;
-               }
-               bool free = checkFreePosition(map, pos_i + pos_size_off, size_blocks);
-               if(free)
-                       m_base_position = new_base_position;
-       }
-       sendPosition();
-       
-
-       // "Material" groups of the object
-       ItemGroupList groups;
-       groups["snappy"] = 1;
-       groups["choppy"] = 1;
-       groups["fleshy"] = 3;
-
-       IItemDefManager *idef = m_env->getGameDef()->idef();
-       ItemStack punchitem = puncher->getWieldedItem();
-       ToolCapabilities tp = punchitem.getToolCapabilities(idef);
-
-       HitParams hit_params = getHitParams(groups, &tp,
-                       time_from_last_punch);
-
-       doDamage(hit_params.hp);
-       if(g_settings->getBool("creative_mode") == false)
-       {
-               punchitem.addWear(hit_params.wear, idef);
-               puncher->setWieldedItem(punchitem);
-       }
-}
-
-bool MobV2SAO::isPeaceful()
-{
-       return m_properties->getBool("is_peaceful");
-}
-
-void MobV2SAO::sendPosition()
-{
-       m_last_sent_position = m_base_position;
 
-       std::ostringstream os(std::ios::binary);
-       // command (0 = update position)
-       writeU8(os, 0);
-       // pos
-       writeV3F1000(os, m_base_position);
-       // yaw
-       writeF1000(os, m_yaw);
-       // create message and add to list
-       ActiveObjectMessage aom(getId(), false, os.str());
-       m_messages_out.push_back(aom);
-}
+private:
+       std::string m_itemstring;
+       bool m_itemstring_changed;
+       v3f m_speed_f;
+       v3f m_last_sent_position;
+       IntervalLimiter m_move_interval;
+};
 
-void MobV2SAO::setPropertyDefaults()
-{
-       m_properties->setDefault("is_peaceful", "false");
-       m_properties->setDefault("move_type", "ground_nodes");
-       m_properties->setDefault("speed", "(0,0,0)");
-       m_properties->setDefault("age", "0");
-       m_properties->setDefault("yaw", "0");
-       m_properties->setDefault("pos", "(0,0,0)");
-       m_properties->setDefault("hp", "0");
-       m_properties->setDefault("die_age", "-1");
-       m_properties->setDefault("size", "(1,2)");
-       m_properties->setDefault("shoot_type", "fireball");
-       m_properties->setDefault("shoot_y", "0");
-       m_properties->setDefault("mindless_rage", "false");
-}
-void MobV2SAO::readProperties()
-{
-       m_move_type = m_properties->get("move_type");
-       m_speed = m_properties->getV3F("speed");
-       m_age = m_properties->getFloat("age");
-       m_yaw = m_properties->getFloat("yaw");
-       m_base_position = m_properties->getV3F("pos");
-       m_hp = m_properties->getS32("hp");
-       m_die_age = m_properties->getFloat("die_age");
-       m_size = m_properties->getV2F("size");
-}
-void MobV2SAO::updateProperties()
-{
-       m_properties->set("move_type", m_move_type);
-       m_properties->setV3F("speed", m_speed);
-       m_properties->setFloat("age", m_age);
-       m_properties->setFloat("yaw", m_yaw);
-       m_properties->setV3F("pos", m_base_position);
-       m_properties->setS32("hp", m_hp);
-       m_properties->setFloat("die_age", m_die_age);
-       m_properties->setV2F("size", m_size);
-
-       m_properties->setS32("version", 0);
-}
+// Prototype (registers item for deserialization)
+ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), "");
 
-void MobV2SAO::doDamage(u16 d)
+ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
+               const std::string itemstring)
 {
-       if(d > 0)
-               actionstream<<"MobV2 ("<<m_hp<<"hp) takes "<<d<<"hp of damage"<<std::endl;
-       
-       if(d < m_hp)
-       {
-               m_hp -= d;
-       }
-       else
-       {
-               actionstream<<"A "<<(isPeaceful()?"peaceful":"non-peaceful")
-                               <<" mob id="<<m_id<<" dies at "<<PP(m_base_position)<<std::endl;
-               // Die
-               m_hp = 0;
-               m_removed = true;
-       }
-
-       {
-               std::ostringstream os(std::ios::binary);
-               // command (1 = damage)
-               writeU8(os, 1);
-               // amount
-               writeU16(os, d);
-               // create message and add to list
-               ActiveObjectMessage aom(getId(), false, os.str());
-               m_messages_out.push_back(aom);
-       }
+       return new ItemSAO(env, pos, itemstring);
 }
 
-
 /*
        LuaEntitySAO
 */
@@ -1538,7 +336,7 @@ void MobV2SAO::doDamage(u16 d)
 #include "scriptapi.h"
 #include "luaentity_common.h"
 
-// Prototype
+// Prototype (registers item for deserialization)
 LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");
 
 LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
@@ -1548,6 +346,7 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
        m_init_state(state),
        m_registered(false),
        m_prop(new LuaEntityProperties),
+       m_hp(-1),
        m_velocity(0,0,0),
        m_acceleration(0,0,0),
        m_yaw(0),
@@ -1562,6 +361,10 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
                ServerActiveObject::registerType(getType(), create);
                return;
        }
+       
+       // Initialize something to armor groups
+       m_armor_groups["fleshy"] = 3;
+       m_armor_groups["snappy"] = 2;
 }
 
 LuaEntitySAO::~LuaEntitySAO()
@@ -1594,17 +397,34 @@ ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
        std::istringstream is(data, std::ios::binary);
        // read version
        u8 version = readU8(is);
+       std::string name;
+       std::string state;
+       s16 hp = 1;
+       v3f velocity;
+       float yaw = 0;
        // check if version is supported
-       if(version != 0)
+       if(version == 0){
+               name = deSerializeString(is);
+               state = deSerializeLongString(is);
+       }
+       else if(version == 1){
+               name = deSerializeString(is);
+               state = deSerializeLongString(is);
+               hp = readS16(is);
+               velocity = readV3F1000(is);
+               yaw = readF1000(is);
+       }
+       else{
                return NULL;
-       // read name
-       std::string name = deSerializeString(is);
-       // read state
-       std::string state = deSerializeLongString(is);
+       }
        // create object
        infostream<<"LuaEntitySAO::create(name=\""<<name<<"\" state=\""
                        <<state<<"\")"<<std::endl;
-       return new LuaEntitySAO(env, pos, name, state);
+       LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state);
+       sao->m_hp = hp;
+       sao->m_velocity = velocity;
+       sao->m_yaw = yaw;
+       return sao;
 }
 
 void LuaEntitySAO::step(float dtime, bool send_recommended)
@@ -1661,11 +481,13 @@ std::string LuaEntitySAO::getClientInitializationData()
 {
        std::ostringstream os(std::ios::binary);
        // version
-       writeU8(os, 0);
+       writeU8(os, 1);
        // pos
        writeV3F1000(os, m_base_position);
        // yaw
        writeF1000(os, m_yaw);
+       // hp
+       writeS16(os, m_hp);
        // properties
        std::ostringstream prop_os(std::ios::binary);
        m_prop->serialize(prop_os);
@@ -1679,7 +501,7 @@ std::string LuaEntitySAO::getStaticData()
        infostream<<__FUNCTION_NAME<<std::endl;
        std::ostringstream os(std::ios::binary);
        // version
-       writeU8(os, 0);
+       writeU8(os, 1);
        // name
        os<<serializeString(m_init_name);
        // state
@@ -1690,18 +512,52 @@ std::string LuaEntitySAO::getStaticData()
        } else {
                os<<serializeLongString(m_init_state);
        }
+       // hp
+       writeS16(os, m_hp);
+       // velocity
+       writeV3F1000(os, m_velocity);
+       // yaw
+       writeF1000(os, m_yaw);
        return os.str();
 }
 
-void LuaEntitySAO::punch(ServerActiveObject *puncher, float time_from_last_punch)
+int LuaEntitySAO::punch(v3f dir,
+               const ToolCapabilities *toolcap,
+               ServerActiveObject *puncher,
+               float time_from_last_punch)
 {
        if(!m_registered){
                // Delete unknown LuaEntities when punched
                m_removed = true;
-               return;
+               return 0;
        }
        lua_State *L = m_env->getLua();
-       scriptapi_luaentity_punch(L, m_id, puncher, time_from_last_punch);
+       scriptapi_luaentity_punch(L, m_id, puncher,
+                       time_from_last_punch, toolcap, dir);
+
+       HitParams hitparams = getHitParams(m_armor_groups, toolcap,
+                       time_from_last_punch);
+       
+       actionstream<<getDescription()<<" punched by "
+                       <<puncher->getDescription()<<", damage "<<hitparams.hp
+                       <<" HP"<<std::endl;
+       
+       setHP(getHP() - hitparams.hp);
+       
+       {
+               std::ostringstream os(std::ios::binary);
+               // command 
+               writeU8(os, LUAENTITY_CMD_PUNCHED);
+               // damage
+               writeS16(os, hitparams.hp);
+               // result_hp
+               writeS16(os, getHP());
+               // create message and add to list
+               ActiveObjectMessage aom(getId(), true, os.str());
+               m_messages_out.push_back(aom);
+       }
+
+       return hitparams.wear;
 }
 
 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
@@ -1712,6 +568,17 @@ void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
        scriptapi_luaentity_rightclick(L, m_id, clicker);
 }
 
+void LuaEntitySAO::setHP(s16 hp)
+{
+       if(hp < 0) hp = 0;
+       m_hp = hp;
+}
+
+s16 LuaEntitySAO::getHP()
+{
+       return m_hp;
+}
+
 void LuaEntitySAO::setPos(v3f pos)
 {
        m_base_position = pos;
@@ -1730,6 +597,17 @@ float LuaEntitySAO::getMinimumSavedMovement()
        return 0.1 * BS;
 }
 
+std::string LuaEntitySAO::getDescription()
+{
+       std::ostringstream os(std::ios::binary);
+       os<<"LuaEntitySAO at (";
+       os<<(m_base_position.X/BS)<<",";
+       os<<(m_base_position.Y/BS)<<",";
+       os<<(m_base_position.Z/BS);
+       os<<")";
+       return std::string("LuaEntitySAO");
+}
+
 void LuaEntitySAO::setVelocity(v3f velocity)
 {
        m_velocity = velocity;
@@ -1763,8 +641,8 @@ float LuaEntitySAO::getYaw()
 void LuaEntitySAO::setTextureMod(const std::string &mod)
 {
        std::ostringstream os(std::ios::binary);
-       // command (1 = set texture modification)
-       writeU8(os, 1);
+       // command 
+       writeU8(os, LUAENTITY_CMD_SET_TEXTURE_MOD);
        // parameters
        os<<serializeString(mod);
        // create message and add to list
@@ -1776,8 +654,8 @@ void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
                bool select_horiz_by_yawpitch)
 {
        std::ostringstream os(std::ios::binary);
-       // command (2 = set sprite)
-       writeU8(os, 2);
+       // command
+       writeU8(os, LUAENTITY_CMD_SET_SPRITE);
        // parameters
        writeV2S16(os, p);
        writeU16(os, num_frames);
@@ -1806,8 +684,8 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
        float update_interval = m_env->getSendRecommendedInterval();
 
        std::ostringstream os(std::ios::binary);
-       // command (0 = update position)
-       writeU8(os, 0);
+       // command
+       writeU8(os, LUAENTITY_CMD_UPDATE_POSITION);
 
        // do_interpolate
        writeU8(os, do_interpolate);
index f0c9cea9052c3a2a5fe2f582ec0c7f8bd1dcea0a..507631d2a37b2ee87a8846b1fb424c830f727389 100644 (file)
@@ -22,173 +22,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "serverobject.h"
 #include "content_object.h"
+#include "itemgroup.h"
 
-class TestSAO : public ServerActiveObject
-{
-public:
-       TestSAO(ServerEnvironment *env, v3f pos);
-       u8 getType() const
-               {return ACTIVEOBJECT_TYPE_TEST;}
-       static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
-                       const std::string &data);
-       void step(float dtime, bool send_recommended);
-private:
-       float m_timer1;
-       float m_age;
-};
-
-class ItemSAO : public ServerActiveObject
-{
-public:
-       ItemSAO(ServerEnvironment *env, v3f pos, const std::string itemstring);
-       u8 getType() const
-               {return ACTIVEOBJECT_TYPE_ITEM;}
-       static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
-                       const std::string &data);
-       void step(float dtime, bool send_recommended);
-       std::string getClientInitializationData();
-       std::string getStaticData();
-       ItemStack createItemStack();
-       void punch(ServerActiveObject *puncher, float time_from_last_punch);
-       float getMinimumSavedMovement(){ return 0.1*BS; }
-private:
-       std::string m_itemstring;
-       bool m_itemstring_changed;
-       v3f m_speed_f;
-       v3f m_last_sent_position;
-       IntervalLimiter m_move_interval;
-};
+ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
+               const std::string itemstring);
 
-class RatSAO : public ServerActiveObject
-{
-public:
-       RatSAO(ServerEnvironment *env, v3f pos);
-       u8 getType() const
-               {return ACTIVEOBJECT_TYPE_RAT;}
-       static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
-                       const std::string &data);
-       void step(float dtime, bool send_recommended);
-       std::string getClientInitializationData();
-       std::string getStaticData();
-       void punch(ServerActiveObject *puncher, float time_from_last_punch);
-private:
-       bool m_is_active;
-       IntervalLimiter m_inactive_interval;
-       v3f m_speed_f;
-       v3f m_oldpos;
-       v3f m_last_sent_position;
-       float m_yaw;
-       float m_counter1;
-       float m_counter2;
-       float m_age;
-       bool m_touching_ground;
-};
-
-class Oerkki1SAO : public ServerActiveObject
-{
-public:
-       Oerkki1SAO(ServerEnvironment *env, v3f pos);
-       u8 getType() const
-               {return ACTIVEOBJECT_TYPE_OERKKI1;}
-       static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
-                       const std::string &data);
-       void step(float dtime, bool send_recommended);
-       std::string getClientInitializationData();
-       std::string getStaticData();
-       void punch(ServerActiveObject *puncher, float time_from_last_punch);
-       bool isPeaceful(){return false;}
-private:
-       void doDamage(u16 d);
-
-       bool m_is_active;
-       IntervalLimiter m_inactive_interval;
-       v3f m_speed_f;
-       v3f m_oldpos;
-       v3f m_last_sent_position;
-       float m_yaw;
-       float m_counter1;
-       float m_counter2;
-       float m_age;
-       bool m_touching_ground;
-       u8 m_hp;
-       float m_after_jump_timer;
-};
-
-class FireflySAO : public ServerActiveObject
-{
-public:
-       FireflySAO(ServerEnvironment *env, v3f pos);
-       u8 getType() const
-               {return ACTIVEOBJECT_TYPE_FIREFLY;}
-       static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
-                       const std::string &data);
-       void step(float dtime, bool send_recommended);
-       std::string getClientInitializationData();
-       std::string getStaticData();
-private:
-       bool m_is_active;
-       IntervalLimiter m_inactive_interval;
-       v3f m_speed_f;
-       v3f m_oldpos;
-       v3f m_last_sent_position;
-       float m_yaw;
-       float m_counter1;
-       float m_counter2;
-       float m_age;
-       bool m_touching_ground;
-};
-
-class Settings;
-
-class MobV2SAO : public ServerActiveObject
-{
-public:
-       MobV2SAO(ServerEnvironment *env, v3f pos,
-                       Settings *init_properties);
-       virtual ~MobV2SAO();
-       u8 getType() const
-               {return ACTIVEOBJECT_TYPE_MOBV2;}
-       static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
-                       const std::string &data);
-       std::string getStaticData();
-       std::string getClientInitializationData();
-       void step(float dtime, bool send_recommended);
-       void punch(ServerActiveObject *puncher, float time_from_last_punch);
-       bool isPeaceful();
-private:
-       void sendPosition();
-       void setPropertyDefaults();
-       void readProperties();
-       void updateProperties();
-       void doDamage(u16 d);
-       
-       std::string m_move_type;
-       v3f m_speed;
-       v3f m_last_sent_position;
-       v3f m_oldpos;
-       float m_yaw;
-       float m_counter1;
-       float m_counter2;
-       float m_age;
-       bool m_touching_ground;
-       int m_hp;
-       bool m_walk_around;
-       float m_walk_around_timer;
-       bool m_next_pos_exists;
-       v3s16 m_next_pos_i;
-       float m_shoot_reload_timer;
-       bool m_shooting;
-       float m_shooting_timer;
-       float m_die_age;
-       v2f m_size;
-       bool m_falling;
-       float m_disturb_timer;
-       std::string m_disturbing_player;
-       float m_random_disturb_timer;
-       float m_shoot_y;
+/*
+       LuaEntitySAO
        
-       Settings *m_properties;
-};
+       This is the only SAO that needs to have a bunch of it's internals exposed.
+*/
 
 struct LuaEntityProperties;
 
@@ -206,11 +49,17 @@ public:
        void step(float dtime, bool send_recommended);
        std::string getClientInitializationData();
        std::string getStaticData();
-       void punch(ServerActiveObject *puncher, float time_from_last_punch);
+       int punch(v3f dir,
+                       const ToolCapabilities *toolcap=NULL,
+                       ServerActiveObject *puncher=NULL,
+                       float time_from_last_punch=1000000);
        void rightClick(ServerActiveObject *clicker);
        void setPos(v3f pos);
        void moveTo(v3f pos, bool continuous);
        float getMinimumSavedMovement();
+       std::string getDescription();
+       void setHP(s16 hp);
+       s16 getHP();
        /* LuaEntitySAO-specific */
        void setVelocity(v3f velocity);
        v3f getVelocity();
@@ -230,9 +79,12 @@ private:
        bool m_registered;
        struct LuaEntityProperties *m_prop;
        
+       s16 m_hp;
        v3f m_velocity;
        v3f m_acceleration;
        float m_yaw;
+       ItemGroupList m_armor_groups;
+
        float m_last_sent_yaw;
        v3f m_last_sent_position;
        v3f m_last_sent_velocity;
diff --git a/src/itemgroup.h b/src/itemgroup.h
new file mode 100644 (file)
index 0000000..927811d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+Minetest-c55
+Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef ITEMGROUP_HEADER
+#define ITEMGROUP_HEADER
+
+#include "common_irrlicht.h"
+#include <string>
+#include <map>
+
+typedef std::map<std::string, int> ItemGroupList;
+
+static inline int itemgroup_get(const ItemGroupList &groups,
+               const std::string &name)
+{
+       std::map<std::string, int>::const_iterator i = groups.find(name);
+       if(i == groups.end())
+               return 0;
+       return i->second;
+}
+
+#endif
+
index 40dc4de350f7053d40474ed9300e57b034770a38..63c3f2d6b13c0e0a6b6b21d212ffc7243ae4de82 100644 (file)
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define PP2(x) "("<<(x).X<<","<<(x).Y<<")"
 
 LuaEntityProperties::LuaEntityProperties():
+       hp_max(1),
        physical(false),
        weight(5),
        collisionbox(-0.5,-0.5,-0.5, 0.5,0.5,0.5),
@@ -39,7 +40,8 @@ LuaEntityProperties::LuaEntityProperties():
 std::string LuaEntityProperties::dump()
 {
        std::ostringstream os(std::ios::binary);
-       os<<"physical="<<physical;
+       os<<"hp_max="<<hp_max;
+       os<<", physical="<<physical;
        os<<", weight="<<weight;
        os<<", collisionbox="<<PP(collisionbox.MinEdge)<<","<<PP(collisionbox.MaxEdge);
        os<<", visual="<<visual;
@@ -56,7 +58,8 @@ std::string LuaEntityProperties::dump()
 
 void LuaEntityProperties::serialize(std::ostream &os)
 {
-       writeU8(os, 0); // version
+       writeU8(os, 1); // version
+       writeS16(os, hp_max);
        writeU8(os, physical);
        writeF1000(os, weight);
        writeV3F1000(os, collisionbox.MinEdge);
@@ -74,8 +77,9 @@ void LuaEntityProperties::serialize(std::ostream &os)
 void LuaEntityProperties::deSerialize(std::istream &is)
 {
        int version = readU8(is);
-       if(version != 0) throw SerializationError(
+       if(version != 1) throw SerializationError(
                        "unsupported LuaEntityProperties version");
+       hp_max = readS16(is);
        physical = readU8(is);
        weight = readF1000(is);
        collisionbox.MinEdge = readV3F1000(is);
index bc2871a94e34031dbacd95d947f201b4af31e8ff..b6366382859e4a13f355cc3208ed1f668312bc85 100644 (file)
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 struct LuaEntityProperties
 {
        // Values are BS=1
+       s16 hp_max;
        bool physical;
        float weight;
        core::aabbox3d<f32> collisionbox;
@@ -42,5 +43,10 @@ struct LuaEntityProperties
        void deSerialize(std::istream &is);
 };
 
+#define LUAENTITY_CMD_UPDATE_POSITION 0
+#define LUAENTITY_CMD_SET_TEXTURE_MOD 1
+#define LUAENTITY_CMD_SET_SPRITE 2
+#define LUAENTITY_CMD_PUNCHED 3
+
 #endif
 
index 2ee727b3f010c16aa9d6dd9f0d788a6d79f5845f..c3059ec55d2e81addec12e679c9a0c485770c5a1 100644 (file)
@@ -2297,17 +2297,22 @@ private:
                return 0;
        }
 
-       // punch(self, puncher); puncher = an another ObjectRef
+       // punch(self, puncher, tool_capabilities, direction, time_from_last_punch)
        static int l_punch(lua_State *L)
        {
                ObjectRef *ref = checkobject(L, 1);
-               ObjectRef *ref2 = checkobject(L, 2);
+               ObjectRef *puncher_ref = checkobject(L, 2);
                ServerActiveObject *co = getobject(ref);
-               ServerActiveObject *co2 = getobject(ref2);
+               ServerActiveObject *puncher = getobject(puncher_ref);
                if(co == NULL) return 0;
-               if(co2 == NULL) return 0;
+               if(puncher == NULL) return 0;
+               ToolCapabilities toolcap = read_tool_capabilities(L, 3);
+               v3f dir = read_v3f(L, 4);
+               float time_from_last_punch = 1000000;
+               if(lua_isnumber(L, 5))
+                       time_from_last_punch = lua_tonumber(L, 5);
                // Do it
-               co->punch(co2);
+               puncher->punch(dir, &toolcap, puncher, time_from_last_punch);
                return 0;
        }
 
@@ -2878,7 +2883,7 @@ private:
                if(item.empty() || !item.isKnown(get_server(L)->idef()))
                        return 0;
                // Do it
-               ServerActiveObject *obj = new ItemSAO(env, pos, item.getItemString());
+               ServerActiveObject *obj = createItemSAO(env, pos, item.getItemString());
                int objectid = env->addActiveObject(obj);
                // If failed to add, return nothing (reads as nil)
                if(objectid == 0)
@@ -2892,15 +2897,8 @@ private:
        // pos = {x=num, y=num, z=num}
        static int l_add_rat(lua_State *L)
        {
-               infostream<<"EnvRef::l_add_rat()"<<std::endl;
-               EnvRef *o = checkobject(L, 1);
-               ServerEnvironment *env = o->m_env;
-               if(env == NULL) return 0;
-               // pos
-               v3f pos = checkFloatPos(L, 2);
-               // Do it
-               ServerActiveObject *obj = new RatSAO(env, pos);
-               env->addActiveObject(obj);
+               infostream<<"EnvRef::l_add_rat(): C++ mobs have been removed."
+                               <<" Doing nothing."<<std::endl;
                return 0;
        }
 
@@ -2908,15 +2906,8 @@ private:
        // pos = {x=num, y=num, z=num}
        static int l_add_firefly(lua_State *L)
        {
-               infostream<<"EnvRef::l_add_firefly()"<<std::endl;
-               EnvRef *o = checkobject(L, 1);
-               ServerEnvironment *env = o->m_env;
-               if(env == NULL) return 0;
-               // pos
-               v3f pos = checkFloatPos(L, 2);
-               // Do it
-               ServerActiveObject *obj = new FireflySAO(env, pos);
-               env->addActiveObject(obj);
+               infostream<<"EnvRef::l_add_firefly(): C++ mobs have been removed."
+                               <<" Doing nothing."<<std::endl;
                return 0;
        }
 
@@ -4348,6 +4339,8 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
 
        /* Read stuff */
        
+       prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
+
        getboolfield(L, -1, "physical", prop->physical);
 
        getfloatfield(L, -1, "weight", prop->weight);
@@ -4415,9 +4408,11 @@ void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime)
                script_error(L, "error running function 'on_step': %s\n", lua_tostring(L, -1));
 }
 
-// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch)
+// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
+//                       tool_capabilities, direction)
 void scriptapi_luaentity_punch(lua_State *L, u16 id,
-               ServerActiveObject *puncher, float time_from_last_punch)
+               ServerActiveObject *puncher, float time_from_last_punch,
+               const ToolCapabilities *toolcap, v3f dir)
 {
        realitycheck(L);
        assert(lua_checkstack(L, 20));
@@ -4436,8 +4431,10 @@ void scriptapi_luaentity_punch(lua_State *L, u16 id,
        lua_pushvalue(L, object); // self
        objectref_get_or_create(L, puncher); // Clicker reference
        lua_pushnumber(L, time_from_last_punch);
-       // Call with 2 arguments, 0 results
-       if(lua_pcall(L, 3, 0, 0))
+       push_tool_capabilities(L, *toolcap);
+       push_v3f(L, dir);
+       // Call with 5 arguments, 0 results
+       if(lua_pcall(L, 5, 0, 0))
                script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1));
 }
 
index df8ae344e9e15be44d8e5f6d39c9799e59c0ae37..aa2d9d4c72a7c480b1c5d7691c5a185a902c8ca8 100644 (file)
@@ -33,6 +33,7 @@ struct LuaEntityProperties;
 struct ItemStack;
 struct PointedThing;
 //class IGameDef;
+struct ToolCapabilities;
 
 void scriptapi_export(lua_State *L, Server *server);
 bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,
@@ -82,7 +83,8 @@ void scriptapi_luaentity_get_properties(lua_State *L, u16 id,
                LuaEntityProperties *prop);
 void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime);
 void scriptapi_luaentity_punch(lua_State *L, u16 id,
-               ServerActiveObject *puncher, float time_from_last_punch);
+               ServerActiveObject *puncher, float time_from_last_punch,
+               const ToolCapabilities *toolcap, v3f dir);
 void scriptapi_luaentity_rightclick(lua_State *L, u16 id,
                ServerActiveObject *clicker);
 
index 443a2a39b636b570d23db5b0010c93c618803363..899624633312261d35be5c9bcdf8d5c216ceb5e0 100644 (file)
@@ -47,6 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mods.h"
 #include "sha1.h"
 #include "base64.h"
+#include "tool.h"
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
@@ -1244,7 +1245,7 @@ void Server::AsyncRunStep()
                                explosion.
                        */
                        player->m_last_good_position_age += dtime;
-                       if(player->m_last_good_position_age >= 2.0){
+                       if(player->m_last_good_position_age >= 1.0){
                                float age = player->m_last_good_position_age;
                                v3f diff = (player->getPosition() - player->m_last_good_position);
                                float d_vert = diff.Y;
@@ -2870,7 +2871,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                if(action == 0 || action == 2 || action == 3)
                {
                        float d = player_pos.getDistanceFrom(pointed_pos_under);
-                       float max_d = BS * 10; // Just some large enough value
+                       float max_d = BS * 14; // Just some large enough value
                        if(d > max_d){
                                actionstream<<"Player "<<player->getName()
                                                <<" tried to access "<<pointed.dump()
@@ -2933,8 +2934,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                actionstream<<player->getName()<<" punches object "
                                        <<pointed.object_id<<std::endl;
 
-                               // Do stuff
-                               pointed_object->punch(srp, srp->m_time_from_last_punch);
+                               ItemStack punchitem = srp->getWieldedItem();
+                               ToolCapabilities toolcap =
+                                               punchitem.getToolCapabilities(m_itemdef);
+                               v3f dir = (pointed_object->getBasePosition() -
+                                               (srp->getPosition() + srp->getEyeOffset())
+                                                       ).normalize();
+                               pointed_object->punch(dir, &toolcap, srp,
+                                               srp->m_time_from_last_punch);
                                srp->m_time_from_last_punch = 0;
                        }
 
index 380bf7302a55b3b7d1f67aaf1ff2905f44cff376..15bbe52f7bbf8e132d2e3497ff3868c434eb4564 100644 (file)
@@ -44,7 +44,7 @@ Some planning
 class ServerEnvironment;
 struct ItemStack;
 class Player;
-struct ToolDiggingProperties;
+struct ToolCapabilities;
 
 class ServerActiveObject : public ActiveObject
 {
@@ -133,10 +133,12 @@ public:
        virtual bool isStaticAllowed() const
        {return true;}
        
-       // time_from_last_punch is used for lessening damage if punching fast
-       virtual void punch(ServerActiveObject *puncher,
+       // Returns tool wear
+       virtual int punch(v3f dir,
+                       const ToolCapabilities *toolcap=NULL,
+                       ServerActiveObject *puncher=NULL,
                        float time_from_last_punch=1000000)
-       {}
+       { return 0; }
        virtual void rightClick(ServerActiveObject *clicker)
        {}
        virtual void setHP(s16 hp)
index c57794ea2f673393d634e7f16598eed10860c9a4..667ece7f22c8b0ab85717115ed6ea8ac5bbcd631 100644 (file)
@@ -169,16 +169,18 @@ std::string ServerRemotePlayer::getStaticData()
        return "";
 }
 
-void ServerRemotePlayer::punch(ServerActiveObject *puncher,
+int ServerRemotePlayer::punch(v3f dir,
+               const ToolCapabilities *toolcap,
+               ServerActiveObject *puncher,
                float time_from_last_punch)
 {
-       if(!puncher)
-               return;
+       if(!toolcap)
+               return 0;
        
        // No effect if PvP disabled
        if(g_settings->getBool("enable_pvp") == false){
                if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER)
-                       return;
+                       return 0;
        }
        
        // "Material" groups of the player
@@ -186,19 +188,13 @@ void ServerRemotePlayer::punch(ServerActiveObject *puncher,
        groups["choppy"] = 2;
        groups["fleshy"] = 3;
 
-       IItemDefManager *idef = m_env->getGameDef()->idef();
-       ItemStack punchitem = puncher->getWieldedItem();
-       ToolCapabilities tp = punchitem.getToolCapabilities(idef);
-
-       HitParams hitparams = getHitParams(groups, &tp, time_from_last_punch);
+       HitParams hitparams = getHitParams(groups, toolcap, time_from_last_punch);
        
        actionstream<<"Player "<<getName()<<" punched by "
                        <<puncher->getDescription()<<", damage "<<hitparams.hp
                        <<" HP"<<std::endl;
        
        setHP(getHP() - hitparams.hp);
-       punchitem.addWear(hitparams.wear, idef);
-       puncher->setWieldedItem(punchitem);
        
        if(hitparams.hp != 0)
        {
@@ -211,6 +207,8 @@ void ServerRemotePlayer::punch(ServerActiveObject *puncher,
                ActiveObjectMessage aom(getId(), false, os.str());
                m_messages_out.push_back(aom);
        }
+
+       return hitparams.wear;
 }
 
 void ServerRemotePlayer::rightClick(ServerActiveObject *clicker)
index 94926c824c4479c4a7fdcc62c0093b149e9674fc..2ff1b0013582189dae7c0f51b23e665dd06d82ab 100644 (file)
@@ -67,7 +67,10 @@ public:
        void step(float dtime, bool send_recommended);
        std::string getClientInitializationData();
        std::string getStaticData();
-       void punch(ServerActiveObject *puncher, float time_from_last_punch);
+       int punch(v3f dir,
+                       const ToolCapabilities *toolcap,
+                       ServerActiveObject *puncher,
+                       float time_from_last_punch);
        void rightClick(ServerActiveObject *clicker);
        void setPos(v3f pos);
        void moveTo(v3f pos, bool continuous);