Browse Source

reorganized a lot of stuff and modified mapgen and objects slightly while doing it

Perttu Ahola 13 years ago
parent
commit
91cfbe2891

+ 5 - 0
.hgignore

@@ -9,7 +9,12 @@ src/jthread/CMakeFiles/*
 src/jthread/Makefile
 src/jthread/cmake_config.h
 src/jthread/cmake_install.cmake
+src/.*.swp
+src/sqlite/libsqlite3.a
+src/session.vim
+util/uloste.png
 minetest.conf
+debug.txt
 bin/
 CMakeCache.txt
 CPackConfig.cmake

BIN
data/oerkki1.png


BIN
data/oerkki1_damaged.png


+ 2 - 0
src/CMakeLists.txt

@@ -61,6 +61,7 @@ configure_file(
 )
 
 set(common_SRCS
+	content_sao.cpp
 	mapgen.cpp
 	content_inventory.cpp
 	content_nodemeta.cpp
@@ -102,6 +103,7 @@ set(common_SRCS
 # Client sources
 set(minetest_SRCS
 	${common_SRCS}
+	content_cao.cpp
 	mapblock_mesh.cpp
 	farmesh.cpp
 	keycode.cpp

+ 3 - 6
src/activeobject.h

@@ -23,6 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "common_irrlicht.h"
 #include <string>
 
+#define ACTIVEOBJECT_TYPE_INVALID 0
+// Other types are defined in content_object.h
+
 struct ActiveObjectMessage
 {
 	ActiveObjectMessage(u16 id_, bool reliable_=true, std::string data_=""):
@@ -36,12 +39,6 @@ struct ActiveObjectMessage
 	std::string datastring;
 };
 
-#define ACTIVEOBJECT_TYPE_INVALID 0
-#define ACTIVEOBJECT_TYPE_TEST 1
-#define ACTIVEOBJECT_TYPE_ITEM 2
-#define ACTIVEOBJECT_TYPE_RAT 3
-#define ACTIVEOBJECT_TYPE_OERKKI1 4
-
 /*
 	Parent class for ServerActiveObject and ClientActiveObject
 */

+ 0 - 673
src/clientobject.cpp

@@ -21,9 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "debug.h"
 #include "porting.h"
 #include "constants.h"
-#include "utility.h"
-#include "environment.h"
-#include "tile.h"
 
 /*
 	ClientActiveObject
@@ -68,674 +65,4 @@ void ClientActiveObject::registerType(u16 type, Factory f)
 	m_types.insert(type, f);
 }
 
-/*
-	TestCAO
-*/
-
-// Prototype
-TestCAO proto_TestCAO;
-
-TestCAO::TestCAO():
-	ClientActiveObject(0),
-	m_node(NULL),
-	m_position(v3f(0,10*BS,0))
-{
-	ClientActiveObject::registerType(getType(), create);
-}
-
-TestCAO::~TestCAO()
-{
-}
-
-ClientActiveObject* TestCAO::create()
-{
-	return new TestCAO();
-}
-
-void TestCAO::addToScene(scene::ISceneManager *smgr)
-{
-	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, driver->getTexture(getTexturePath("rat.png").c_str()));
-	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();
-		//dstream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
-		rot.Y += dtime * 180;
-		m_node->setRotation(rot);
-	}
-}
-
-void TestCAO::processMessage(const std::string &data)
-{
-	dstream<<"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;
-
-ItemCAO::ItemCAO():
-	ClientActiveObject(0),
-	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))
-{
-	ClientActiveObject::registerType(getType(), create);
-}
-
-ItemCAO::~ItemCAO()
-{
-}
-
-ClientActiveObject* ItemCAO::create()
-{
-	return new ItemCAO();
-}
-
-void ItemCAO::addToScene(scene::ISceneManager *smgr)
-{
-	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);
-	//buf->getMaterial().setTexture(0, NULL);
-	// Initialize with the stick texture
-	buf->getMaterial().setTexture
-			(0, driver->getTexture(getTexturePath("stick.png").c_str()));
-	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 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);
-
-	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);
-		video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
-		u16 vc = buf->getVertexCount();
-		for(u16 i=0; i<vc; i++)
-		{
-			vertices[i].Color = color;
-		}
-	}
-}
-
-v3s16 ItemCAO::getLightPosition()
-{
-	return floatToInt(m_position, BS);
-}
-
-void ItemCAO::updateNodePos()
-{
-	if(m_node == NULL)
-		return;
-
-	m_node->setPosition(m_position);
-}
-
-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)
-{
-	dstream<<"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();
-	}
-}
-
-void ItemCAO::initialize(const std::string &data)
-{
-	dstream<<"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);
-		// inventorystring
-		m_inventorystring = deSerializeString(is);
-	}
-	
-	updateNodePos();
-
-	/*
-		Update image of node
-	*/
-
-	if(m_node == NULL)
-		return;
-
-	scene::IMesh *mesh = m_node->getMesh();
-
-	if(mesh == NULL)
-		return;
-	
-	scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
-
-	if(buf == NULL)
-		return;
-
-	// Create an inventory item to see what is its image
-	std::istringstream is(m_inventorystring, std::ios_base::binary);
-	video::ITexture *texture = NULL;
-	try{
-		InventoryItem *item = NULL;
-		item = InventoryItem::deSerialize(is);
-		dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
-				<<m_inventorystring<<"\" -> item="<<item
-				<<std::endl;
-		if(item)
-		{
-			texture = item->getImage();
-			delete item;
-		}
-	}
-	catch(SerializationError &e)
-	{
-		dstream<<"WARNING: "<<__FUNCTION_NAME
-				<<": error deSerializing inventorystring \""
-				<<m_inventorystring<<"\""<<std::endl;
-	}
-	
-	// Set meshbuffer texture
-	buf->getMaterial().setTexture(0, texture);
-	
-}
-
-/*
-	RatCAO
-*/
-
-#include "inventory.h"
-
-// Prototype
-RatCAO proto_RatCAO;
-
-RatCAO::RatCAO():
-	ClientActiveObject(0),
-	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()
-{
-	return new RatCAO();
-}
-
-void RatCAO::addToScene(scene::ISceneManager *smgr)
-{
-	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, driver->getTexture(getTexturePath("rat.png").c_str()));
-	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);
-
-	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);
-		video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
-		u16 vc = buf->getVertexCount();
-		for(u16 i=0; i<vc; i++)
-		{
-			vertices[i].Color = 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)
-{
-	//dstream<<"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)
-{
-	//dstream<<"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;
-
-Oerkki1CAO::Oerkki1CAO():
-	ClientActiveObject(0),
-	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);
-}
-
-Oerkki1CAO::~Oerkki1CAO()
-{
-}
-
-ClientActiveObject* Oerkki1CAO::create()
-{
-	return new Oerkki1CAO();
-}
-
-void Oerkki1CAO::addToScene(scene::ISceneManager *smgr)
-{
-	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, driver->getTexture(getTexturePath("oerkki1.png").c_str()));
-	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);
-
-	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);
-		video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
-		u16 vc = buf->getVertexCount();
-		for(u16 i=0; i<vc; i++)
-		{
-			vertices[i].Color = 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)
-{
-	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) < 3.0*BS &&
-			objectpos_2d.getDistanceFrom(playerpos_2d) < 1.0*BS)
-	{
-		if(m_attack_interval.step(dtime, 0.5))
-		{
-			env->damageLocalPlayer(2);
-		}
-	}
-}
-
-void Oerkki1CAO::processMessage(const std::string &data)
-{
-	//dstream<<"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();
-	}
-}
-
-void Oerkki1CAO::initialize(const std::string &data)
-{
-	//dstream<<"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();
-}
-
 

+ 0 - 217
src/clientobject.h

@@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "common_irrlicht.h"
 #include "activeobject.h"
-#include "utility.h"
 
 /*
 
@@ -36,63 +35,6 @@ Some planning
 
 */
 
-/*
-	SmoothTranslator
-*/
-
-struct SmoothTranslator
-{
-	v3f vect_old;
-	f32 anim_counter;
-	f32 anim_time;
-	f32 anim_time_counter;
-	v3f vect_show;
-	v3f vect_aim;
-
-	SmoothTranslator():
-		vect_old(0,0,0),
-		anim_counter(0),
-		anim_time(0),
-		anim_time_counter(0),
-		vect_show(0,0,0),
-		vect_aim(0,0,0)
-	{}
-
-	void init(v3f vect)
-	{
-		vect_old = vect;
-		vect_show = vect;
-		vect_aim = vect;
-	}
-
-	void update(v3f vect_new)
-	{
-		vect_old = vect_show;
-		vect_aim = vect_new;
-		if(anim_time < 0.001 || anim_time > 1.0)
-			anim_time = anim_time_counter;
-		else
-			anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
-		anim_time_counter = 0;
-		anim_counter = 0;
-	}
-
-	void translate(f32 dtime)
-	{
-		anim_time_counter = anim_time_counter + dtime;
-		anim_counter = anim_counter + dtime;
-		v3f vect_move = vect_aim - vect_old;
-		f32 moveratio = 1.0;
-		if(anim_time > 0.001)
-			moveratio = anim_time_counter / anim_time;
-		// Move a bit less than should, to avoid oscillation
-		moveratio = moveratio * 0.8;
-		if(moveratio > 1.5)
-			moveratio = 1.5;
-		vect_show = vect_old + vect_move * moveratio;
-	}
-};
-
 class ClientEnvironment;
 
 class ClientActiveObject : public ActiveObject
@@ -153,164 +95,5 @@ struct DistanceSortedActiveObject
 	}
 };
 
-/*
-	TestCAO
-*/
-
-class TestCAO : public ClientActiveObject
-{
-public:
-	TestCAO();
-	virtual ~TestCAO();
-	
-	u8 getType() const
-	{
-		return ACTIVEOBJECT_TYPE_TEST;
-	}
-	
-	static ClientActiveObject* create();
-
-	void addToScene(scene::ISceneManager *smgr);
-	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();
-	virtual ~ItemCAO();
-	
-	u8 getType() const
-	{
-		return ACTIVEOBJECT_TYPE_ITEM;
-	}
-	
-	static ClientActiveObject* create();
-
-	void addToScene(scene::ISceneManager *smgr);
-	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;
-	std::string m_inventorystring;
-};
-
-/*
-	RatCAO
-*/
-
-class RatCAO : public ClientActiveObject
-{
-public:
-	RatCAO();
-	virtual ~RatCAO();
-	
-	u8 getType() const
-	{
-		return ACTIVEOBJECT_TYPE_RAT;
-	}
-	
-	static ClientActiveObject* create();
-
-	void addToScene(scene::ISceneManager *smgr);
-	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;
-};
-
-/*
-	Oerkki1CAO
-*/
-
-class Oerkki1CAO : public ClientActiveObject
-{
-public:
-	Oerkki1CAO();
-	virtual ~Oerkki1CAO();
-	
-	u8 getType() const
-	{
-		return ACTIVEOBJECT_TYPE_OERKKI1;
-	}
-	
-	static ClientActiveObject* create();
-
-	void addToScene(scene::ISceneManager *smgr);
-	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:
-	IntervalLimiter m_attack_interval;
-	core::aabbox3d<f32> m_selection_box;
-	scene::IMeshSceneNode *m_node;
-	v3f m_position;
-	float m_yaw;
-	SmoothTranslator pos_translator;
-};
-
 #endif
 

+ 54 - 0
src/collision.cpp

@@ -182,4 +182,58 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
 	return result;
 }
 
+collisionMoveResult collisionMovePrecise(Map *map, f32 pos_max_d,
+		const core::aabbox3d<f32> &box_0,
+		f32 dtime, v3f &pos_f, v3f &speed_f)
+{
+	collisionMoveResult final_result;
+
+	// Maximum time increment (for collision detection etc)
+	// time = distance / speed
+	f32 dtime_max_increment = pos_max_d / speed_f.getLength();
+	
+	// Maximum time increment is 10ms or lower
+	if(dtime_max_increment > 0.01)
+		dtime_max_increment = 0.01;
+	
+	// Don't allow overly huge dtime
+	if(dtime > 2.0)
+		dtime = 2.0;
+	
+	f32 dtime_downcount = dtime;
+
+	u32 loopcount = 0;
+	do
+	{
+		loopcount++;
+
+		f32 dtime_part;
+		if(dtime_downcount > dtime_max_increment)
+		{
+			dtime_part = dtime_max_increment;
+			dtime_downcount -= dtime_part;
+		}
+		else
+		{
+			dtime_part = dtime_downcount;
+			/*
+				Setting this to 0 (no -=dtime_part) disables an infinite loop
+				when dtime_part is so small that dtime_downcount -= dtime_part
+				does nothing
+			*/
+			dtime_downcount = 0;
+		}
+
+		collisionMoveResult result = collisionMoveSimple(map, pos_max_d,
+				box_0, dtime_part, pos_f, speed_f);
+
+		if(result.touching_ground)
+			final_result.touching_ground = true;
+	}
+	while(dtime_downcount > 0.001);
+		
+
+	return final_result;
+}
+
 

+ 6 - 1
src/collision.h

@@ -33,10 +33,15 @@ struct collisionMoveResult
 	{}
 };
 
+// Moves using a single iteration; speed should not exceed pos_max_d/dtime
 collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
 		const core::aabbox3d<f32> &box_0,
 		f32 dtime, v3f &pos_f, v3f &speed_f);
-//{return collisionMoveResult();}
+
+// Moves using as many iterations as needed
+collisionMoveResult collisionMovePrecise(Map *map, f32 pos_max_d,
+		const core::aabbox3d<f32> &box_0,
+		f32 dtime, v3f &pos_f, v3f &speed_f);
 
 enum CollisionType
 {

+ 753 - 0
src/content_cao.cpp

@@ -0,0 +1,753 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 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.
+*/
+
+#include "content_cao.h"
+#include "tile.h"
+#include "environment.h"
+
+/*
+	TestCAO
+*/
+
+// Prototype
+TestCAO proto_TestCAO;
+
+TestCAO::TestCAO():
+	ClientActiveObject(0),
+	m_node(NULL),
+	m_position(v3f(0,10*BS,0))
+{
+	ClientActiveObject::registerType(getType(), create);
+}
+
+TestCAO::~TestCAO()
+{
+}
+
+ClientActiveObject* TestCAO::create()
+{
+	return new TestCAO();
+}
+
+void TestCAO::addToScene(scene::ISceneManager *smgr)
+{
+	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, driver->getTexture(getTexturePath("rat.png").c_str()));
+	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();
+		//dstream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
+		rot.Y += dtime * 180;
+		m_node->setRotation(rot);
+	}
+}
+
+void TestCAO::processMessage(const std::string &data)
+{
+	dstream<<"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;
+
+ItemCAO::ItemCAO():
+	ClientActiveObject(0),
+	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))
+{
+	ClientActiveObject::registerType(getType(), create);
+}
+
+ItemCAO::~ItemCAO()
+{
+}
+
+ClientActiveObject* ItemCAO::create()
+{
+	return new ItemCAO();
+}
+
+void ItemCAO::addToScene(scene::ISceneManager *smgr)
+{
+	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);
+	//buf->getMaterial().setTexture(0, NULL);
+	// Initialize with the stick texture
+	buf->getMaterial().setTexture
+			(0, driver->getTexture(getTexturePath("stick.png").c_str()));
+	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 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);
+
+	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);
+		video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
+		u16 vc = buf->getVertexCount();
+		for(u16 i=0; i<vc; i++)
+		{
+			vertices[i].Color = color;
+		}
+	}
+}
+
+v3s16 ItemCAO::getLightPosition()
+{
+	return floatToInt(m_position, BS);
+}
+
+void ItemCAO::updateNodePos()
+{
+	if(m_node == NULL)
+		return;
+
+	m_node->setPosition(m_position);
+}
+
+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)
+{
+	dstream<<"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();
+	}
+}
+
+void ItemCAO::initialize(const std::string &data)
+{
+	dstream<<"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);
+		// inventorystring
+		m_inventorystring = deSerializeString(is);
+	}
+	
+	updateNodePos();
+
+	/*
+		Update image of node
+	*/
+
+	if(m_node == NULL)
+		return;
+
+	scene::IMesh *mesh = m_node->getMesh();
+
+	if(mesh == NULL)
+		return;
+	
+	scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
+
+	if(buf == NULL)
+		return;
+
+	// Create an inventory item to see what is its image
+	std::istringstream is(m_inventorystring, std::ios_base::binary);
+	video::ITexture *texture = NULL;
+	try{
+		InventoryItem *item = NULL;
+		item = InventoryItem::deSerialize(is);
+		dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
+				<<m_inventorystring<<"\" -> item="<<item
+				<<std::endl;
+		if(item)
+		{
+			texture = item->getImage();
+			delete item;
+		}
+	}
+	catch(SerializationError &e)
+	{
+		dstream<<"WARNING: "<<__FUNCTION_NAME
+				<<": error deSerializing inventorystring \""
+				<<m_inventorystring<<"\""<<std::endl;
+	}
+	
+	// Set meshbuffer texture
+	buf->getMaterial().setTexture(0, texture);
+	
+}
+
+/*
+	RatCAO
+*/
+
+#include "inventory.h"
+
+// Prototype
+RatCAO proto_RatCAO;
+
+RatCAO::RatCAO():
+	ClientActiveObject(0),
+	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()
+{
+	return new RatCAO();
+}
+
+void RatCAO::addToScene(scene::ISceneManager *smgr)
+{
+	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, driver->getTexture(getTexturePath("rat.png").c_str()));
+	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);
+
+	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);
+		video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
+		u16 vc = buf->getVertexCount();
+		for(u16 i=0; i<vc; i++)
+		{
+			vertices[i].Color = 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)
+{
+	//dstream<<"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)
+{
+	//dstream<<"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;
+
+Oerkki1CAO::Oerkki1CAO():
+	ClientActiveObject(0),
+	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()
+{
+	return new Oerkki1CAO();
+}
+
+void Oerkki1CAO::addToScene(scene::ISceneManager *smgr)
+{
+	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, driver->getTexture(getTexturePath("oerkki1.png").c_str()));
+	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);
+
+	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);
+		video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
+		u16 vc = buf->getVertexCount();
+		for(u16 i=0; i<vc; i++)
+		{
+			vertices[i].Color = 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)
+{
+	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) < 3.0*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, driver->getTexture(
+							getTexturePath("oerkki1_damaged.png").c_str()));
+				}
+			}
+			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, driver->getTexture(
+							getTexturePath("oerkki1.png").c_str()));
+				}
+			}
+			m_damage_texture_enabled = false;
+		}
+	}
+}
+
+void Oerkki1CAO::processMessage(const std::string &data)
+{
+	//dstream<<"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)
+{
+	//dstream<<"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();
+}
+
+

+ 248 - 0
src/content_cao.h

@@ -0,0 +1,248 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 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 CONTENT_CAO_HEADER
+#define CONTENT_CAO_HEADER
+
+#include "clientobject.h"
+#include "content_object.h"
+#include "utility.h" // For IntervalLimiter
+
+/*
+	SmoothTranslator
+*/
+
+struct SmoothTranslator
+{
+	v3f vect_old;
+	f32 anim_counter;
+	f32 anim_time;
+	f32 anim_time_counter;
+	v3f vect_show;
+	v3f vect_aim;
+
+	SmoothTranslator():
+		vect_old(0,0,0),
+		anim_counter(0),
+		anim_time(0),
+		anim_time_counter(0),
+		vect_show(0,0,0),
+		vect_aim(0,0,0)
+	{}
+
+	void init(v3f vect)
+	{
+		vect_old = vect;
+		vect_show = vect;
+		vect_aim = vect;
+	}
+
+	void update(v3f vect_new)
+	{
+		vect_old = vect_show;
+		vect_aim = vect_new;
+		if(anim_time < 0.001 || anim_time > 1.0)
+			anim_time = anim_time_counter;
+		else
+			anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
+		anim_time_counter = 0;
+		anim_counter = 0;
+	}
+
+	void translate(f32 dtime)
+	{
+		anim_time_counter = anim_time_counter + dtime;
+		anim_counter = anim_counter + dtime;
+		v3f vect_move = vect_aim - vect_old;
+		f32 moveratio = 1.0;
+		if(anim_time > 0.001)
+			moveratio = anim_time_counter / anim_time;
+		// Move a bit less than should, to avoid oscillation
+		moveratio = moveratio * 0.8;
+		if(moveratio > 1.5)
+			moveratio = 1.5;
+		vect_show = vect_old + vect_move * moveratio;
+	}
+};
+
+
+/*
+	TestCAO
+*/
+
+class TestCAO : public ClientActiveObject
+{
+public:
+	TestCAO();
+	virtual ~TestCAO();
+	
+	u8 getType() const
+	{
+		return ACTIVEOBJECT_TYPE_TEST;
+	}
+	
+	static ClientActiveObject* create();
+
+	void addToScene(scene::ISceneManager *smgr);
+	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();
+	virtual ~ItemCAO();
+	
+	u8 getType() const
+	{
+		return ACTIVEOBJECT_TYPE_ITEM;
+	}
+	
+	static ClientActiveObject* create();
+
+	void addToScene(scene::ISceneManager *smgr);
+	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;
+	std::string m_inventorystring;
+};
+
+/*
+	RatCAO
+*/
+
+class RatCAO : public ClientActiveObject
+{
+public:
+	RatCAO();
+	virtual ~RatCAO();
+	
+	u8 getType() const
+	{
+		return ACTIVEOBJECT_TYPE_RAT;
+	}
+	
+	static ClientActiveObject* create();
+
+	void addToScene(scene::ISceneManager *smgr);
+	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;
+};
+
+/*
+	Oerkki1CAO
+*/
+
+class Oerkki1CAO : public ClientActiveObject
+{
+public:
+	Oerkki1CAO();
+	virtual ~Oerkki1CAO();
+	
+	u8 getType() const
+	{
+		return ACTIVEOBJECT_TYPE_OERKKI1;
+	}
+	
+	static ClientActiveObject* create();
+
+	void addToScene(scene::ISceneManager *smgr);
+	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:
+	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;
+};
+
+
+#endif
+

+ 2 - 1
src/content_inventory.cpp

@@ -19,8 +19,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "content_inventory.h"
 #include "inventory.h"
-#include "serverobject.h"
 #include "content_mapnode.h"
+//#include "serverobject.h"
+#include "content_sao.h"
 
 bool item_material_is_cookable(u8 content)
 {

+ 29 - 0
src/content_object.h

@@ -0,0 +1,29 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 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 CONTENT_OBJECT_HEADER
+#define CONTENT_OBJECT_HEADER
+
+#define ACTIVEOBJECT_TYPE_TEST 1
+#define ACTIVEOBJECT_TYPE_ITEM 2
+#define ACTIVEOBJECT_TYPE_RAT 3
+#define ACTIVEOBJECT_TYPE_OERKKI1 4
+
+#endif
+

+ 694 - 0
src/content_sao.cpp

@@ -0,0 +1,694 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 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.
+*/
+
+#include "content_sao.h"
+#include "collision.h"
+#include "environment.h"
+
+/*
+	TestSAO
+*/
+
+// Prototype
+TestSAO proto_TestSAO(NULL, 0, v3f(0,0,0));
+
+TestSAO::TestSAO(ServerEnvironment *env, u16 id, v3f pos):
+	ServerActiveObject(env, id, pos),
+	m_timer1(0),
+	m_age(0)
+{
+	ServerActiveObject::registerType(getType(), create);
+}
+
+ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos,
+		const std::string &data)
+{
+	return new TestSAO(env, id, 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;
+		//dstream<<"TestSAO: id="<<getId()<<" sending data"<<std::endl;
+
+		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, 0, v3f(0,0,0), "");
+
+ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
+		const std::string inventorystring):
+	ServerActiveObject(env, id, pos),
+	m_inventorystring(inventorystring),
+	m_speed_f(0,0,0),
+	m_last_sent_position(0,0,0)
+{
+	ServerActiveObject::registerType(getType(), create);
+}
+
+ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, 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 inventorystring = deSerializeString(is);
+	dstream<<"ItemSAO::create(): Creating item \""
+			<<inventorystring<<"\""<<std::endl;
+	return new ItemSAO(env, id, pos, inventorystring);
+}
+
+void ItemSAO::step(float dtime, bool send_recommended)
+{
+	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;
+	moveresult = collisionMoveSimple(&m_env->getMap(), 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);
+		char buf[6];
+		// command (0 = update position)
+		buf[0] = 0;
+		os.write(buf, 1);
+		// pos
+		writeS32((u8*)buf, m_base_position.X*1000);
+		os.write(buf, 4);
+		writeS32((u8*)buf, m_base_position.Y*1000);
+		os.write(buf, 4);
+		writeS32((u8*)buf, m_base_position.Z*1000);
+		os.write(buf, 4);
+		// 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);
+	char buf[6];
+	// version
+	buf[0] = 0;
+	os.write(buf, 1);
+	// pos
+	writeS32((u8*)buf, m_base_position.X*1000);
+	os.write(buf, 4);
+	writeS32((u8*)buf, m_base_position.Y*1000);
+	os.write(buf, 4);
+	writeS32((u8*)buf, m_base_position.Z*1000);
+	os.write(buf, 4);
+	// inventorystring
+	os<<serializeString(m_inventorystring);
+	return os.str();
+}
+
+std::string ItemSAO::getStaticData()
+{
+	dstream<<__FUNCTION_NAME<<std::endl;
+	std::ostringstream os(std::ios::binary);
+	char buf[1];
+	// version
+	buf[0] = 0;
+	os.write(buf, 1);
+	// inventorystring
+	os<<serializeString(m_inventorystring);
+	return os.str();
+}
+
+InventoryItem * ItemSAO::createInventoryItem()
+{
+	try{
+		std::istringstream is(m_inventorystring, std::ios_base::binary);
+		InventoryItem *item = InventoryItem::deSerialize(is);
+		dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
+				<<m_inventorystring<<"\" -> item="<<item
+				<<std::endl;
+		return item;
+	}
+	catch(SerializationError &e)
+	{
+		dstream<<__FUNCTION_NAME<<": serialization error: "
+				<<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
+		return NULL;
+	}
+}
+
+
+/*
+	RatSAO
+*/
+
+// Prototype
+RatSAO proto_RatSAO(NULL, 0, v3f(0,0,0));
+
+RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos):
+	ServerActiveObject(env, id, 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* RatSAO::create(ServerEnvironment *env, u16 id, 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, id, pos);
+}
+
+void RatSAO::step(float dtime, bool send_recommended)
+{
+	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;
+	moveresult = collisionMoveSimple(&m_env->getMap(), 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()
+{
+	//dstream<<__FUNCTION_NAME<<std::endl;
+	std::ostringstream os(std::ios::binary);
+	// version
+	writeU8(os, 0);
+	return os.str();
+}
+
+InventoryItem* RatSAO::createPickedUpItem()
+{
+	std::istringstream is("CraftItem rat 1", std::ios_base::binary);
+	InventoryItem *item = InventoryItem::deSerialize(is);
+	return item;
+}
+
+/*
+	Oerkki1SAO
+*/
+
+// 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;
+}
+
+// Prototype
+Oerkki1SAO proto_Oerkki1SAO(NULL, 0, v3f(0,0,0));
+
+Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos):
+	ServerActiveObject(env, id, 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, u16 id, 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, id, pos);
+	o->m_hp = hp;
+	return o;
+}
+
+void Oerkki1SAO::step(float dtime, bool send_recommended)
+{
+	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*1.45)
+		{
+			player_is_too_close = true;
+			near_player_pos = playerpos;
+			break;
+		}
+		else if(dist < BS*15.0)
+		{
+			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;
+	moveresult = collisionMovePrecise(&m_env->getMap(), pos_max_d,
+			box, dtime, pos_f, m_speed_f);
+	m_touching_ground = moveresult.touching_ground;
+	
+	// Do collision damage
+	float tolerance = BS*12;
+	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()
+{
+	//dstream<<__FUNCTION_NAME<<std::endl;
+	std::ostringstream os(std::ios::binary);
+	// version
+	writeU8(os, 0);
+	// hp
+	writeU8(os, m_hp);
+	return os.str();
+}
+
+u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir)
+{
+	m_speed_f += dir*12*BS;
+
+	u16 amount = 5;
+	doDamage(amount);
+	return 65536/100;
+}
+
+void Oerkki1SAO::doDamage(u16 d)
+{
+	dstream<<"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);
+	}
+}
+
+

+ 118 - 0
src/content_sao.h

@@ -0,0 +1,118 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 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 CONTENT_SAO_HEADER
+#define CONTENT_SAO_HEADER
+
+#include "serverobject.h"
+#include "content_object.h"
+
+class TestSAO : public ServerActiveObject
+{
+public:
+	TestSAO(ServerEnvironment *env, u16 id, v3f pos);
+	u8 getType() const
+		{return ACTIVEOBJECT_TYPE_TEST;}
+	static ServerActiveObject* create(ServerEnvironment *env, u16 id, 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, u16 id, v3f pos,
+			const std::string inventorystring);
+	u8 getType() const
+		{return ACTIVEOBJECT_TYPE_ITEM;}
+	static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+			const std::string &data);
+	void step(float dtime, bool send_recommended);
+	std::string getClientInitializationData();
+	std::string getStaticData();
+	InventoryItem* createInventoryItem();
+	InventoryItem* createPickedUpItem(){return createInventoryItem();}
+private:
+	std::string m_inventorystring;
+	v3f m_speed_f;
+	v3f m_last_sent_position;
+	IntervalLimiter m_move_interval;
+};
+
+class RatSAO : public ServerActiveObject
+{
+public:
+	RatSAO(ServerEnvironment *env, u16 id, v3f pos);
+	u8 getType() const
+		{return ACTIVEOBJECT_TYPE_RAT;}
+	static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+			const std::string &data);
+	void step(float dtime, bool send_recommended);
+	std::string getClientInitializationData();
+	std::string getStaticData();
+	InventoryItem* createPickedUpItem();
+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, u16 id, v3f pos);
+	u8 getType() const
+		{return ACTIVEOBJECT_TYPE_OERKKI1;}
+	static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+			const std::string &data);
+	void step(float dtime, bool send_recommended);
+	std::string getClientInitializationData();
+	std::string getStaticData();
+	InventoryItem* createPickedUpItem(){return NULL;}
+	u16 punch(const std::string &toolname, v3f dir);
+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;
+};
+
+
+#endif
+

+ 24 - 12
src/environment.cpp

@@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "collision.h"
 #include "content_mapnode.h"
 #include "mapblock.h"
+#include "serverobject.h"
+#include "content_sao.h"
 
 Environment::Environment():
 	m_time_of_day(9000)
@@ -918,8 +920,14 @@ void ServerEnvironment::step(float dtime)
 			// Don't step if is to be removed or stored statically
 			if(obj->m_removed || obj->m_pending_deactivation)
 				continue;
-			// Step object, putting messages directly to the queue
-			obj->step(dtime, m_active_object_messages, send_recommended);
+			// Step object
+			obj->step(dtime, send_recommended);
+			// Read messages from object
+			while(obj->m_messages_out.size() > 0)
+			{
+				m_active_object_messages.push_back(
+						obj->m_messages_out.pop_front());
+			}
 		}
 	}
 	
@@ -1660,17 +1668,21 @@ void ClientEnvironment::step(float dtime)
 		ClientActiveObject* obj = i.getNode()->getValue();
 		// Step object
 		obj->step(dtime, this);
-		// Update lighting
-		//u8 light = LIGHT_MAX;
-		u8 light = 0;
-		try{
-			// Get node at head
-			v3s16 p = obj->getLightPosition();
-			MapNode n = m_map->getNode(p);
-			light = n.getLightBlend(getDayNightRatio());
+
+		if(m_active_object_light_update_interval.step(dtime, 0.5))
+		{
+			// Update lighting
+			//u8 light = LIGHT_MAX;
+			u8 light = 0;
+			try{
+				// Get node at head
+				v3s16 p = obj->getLightPosition();
+				MapNode n = m_map->getNode(p);
+				light = n.getLightBlend(getDayNightRatio());
+			}
+			catch(InvalidPositionException &e) {}
+			obj->updateLight(light);
 		}
-		catch(InvalidPositionException &e) {}
-		obj->updateLight(light);
 	}
 }
 

+ 6 - 5
src/environment.h

@@ -36,6 +36,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "map.h"
 #include <ostream>
 #include "utility.h"
+#include "activeobject.h"
+
+class Server;
+class ActiveBlockModifier;
+class ServerActiveObject;
 
 class Environment
 {
@@ -118,11 +123,6 @@ private:
 	This is not thread-safe. Server uses an environment mutex.
 */
 
-#include "serverobject.h"
-
-class Server;
-class ActiveBlockModifier;
-
 class ServerEnvironment : public Environment
 {
 public:
@@ -412,6 +412,7 @@ private:
 	scene::ISceneManager *m_smgr;
 	core::map<u16, ClientActiveObject*> m_active_objects;
 	Queue<ClientEnvEvent> m_client_event_queue;
+	IntervalLimiter m_active_object_light_update_interval;
 };
 
 #endif

+ 11 - 1
src/game.cpp

@@ -661,7 +661,9 @@ void the_game(
 	screensize = driver->getScreenSize();
 
 	const s32 hotbar_itemcount = 8;
-	const s32 hotbar_imagesize = 36;
+	//const s32 hotbar_imagesize = 36;
+	//const s32 hotbar_imagesize = 64;
+	s32 hotbar_imagesize = 48;
 	
 	// The color of the sky
 
@@ -967,6 +969,14 @@ void the_game(
 		screensize = driver->getScreenSize();
 		v2s32 displaycenter(screensize.X/2,screensize.Y/2);
 		//bool screensize_changed = screensize != last_screensize;
+
+		// Resize hotbar
+		if(screensize.Y <= 600)
+			hotbar_imagesize = 32;
+		else if(screensize.Y <= 1024)
+			hotbar_imagesize = 48;
+		else
+			hotbar_imagesize = 64;
 		
 		// Hilight boxes collected during the loop and displayed
 		core::list< core::aabbox3d<f32> > hilightboxes;

+ 1 - 0
src/inventory.cpp

@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serverobject.h"
 #include "content_mapnode.h"
 #include "content_inventory.h"
+#include "content_sao.h"
 
 /*
 	InventoryItem

+ 3 - 7
src/map.cpp

@@ -26,10 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "utility.h"
 #include "voxel.h"
 #include "porting.h"
-#include "mineral.h"
-#include "noise.h"
-#include "serverobject.h"
-#include "content_mapnode.h"
 #include "mapgen.h"
 #include "nodemetadata.h"
 
@@ -901,7 +897,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
 	{
 	}
 
-#if 1
+#if 0
 	/*
 		If the new node is solid and there is grass below, change it to mud
 	*/
@@ -2869,10 +2865,10 @@ MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load
 		// format. Just go ahead and create the sector.
 		if(fs::PathExists(sectordir))
 		{
-			dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
+			/*dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
 					<<fullpath<<" doesn't exist but directory does."
 					<<" Continuing with a sector with no metadata."
-					<<std::endl;
+					<<std::endl;*/
 			sector = new ServerMapSector(this, p2d);
 			m_sectors.insert(p2d, sector);
 		}

+ 86 - 10
src/mapgen.cpp

@@ -23,8 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "noise.h"
 #include "mapblock.h"
 #include "map.h"
-#include "serverobject.h"
 #include "mineral.h"
+//#include "serverobject.h"
+#include "content_sao.h"
 
 namespace mapgen
 {
@@ -503,7 +504,7 @@ static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
 	else
 		length = random.range(1,6);
 	length = random.range(1,13);
-	u32 partlength = random.range(1,length);
+	u32 partlength = random.range(1,13);
 	u32 partcount = 0;
 	s16 make_stairs = 0;
 	if(random.next()%2 == 0 && partlength >= 3)
@@ -672,14 +673,63 @@ public:
 				continue;
 			v3s16 roomplace;
 			// X east, Z north, Y up
+#if 0
+			if(doordir == v3s16(1,0,0)) // X+
+				roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2+
+						m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1));
+			if(doordir == v3s16(-1,0,0)) // X-
+				roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2
+						+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1));
+			if(doordir == v3s16(0,0,1)) // Z+
+				roomplace = doorplace + v3s16(-roomsize.X/2
+						+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,0);
+			if(doordir == v3s16(0,0,-1)) // Z-
+				roomplace = doorplace + v3s16(-roomsize.X/2
+						+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,
+								-roomsize.Z+1);
+#endif
+#if 0
+			if(doordir == v3s16(1,0,0)) // X+
+				roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2+
+						m_random.range(-roomsize.Z/2+(roomsize.Z%2==0?2:1),
+								roomsize.Z/2-1));
+			if(doordir == v3s16(-1,0,0)) // X-
+				roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2
+						+m_random.range(-roomsize.Z/2+(roomsize.Z%2==0?2:1),
+								roomsize.Z/2-1));
+			if(doordir == v3s16(0,0,1)) // Z+
+				roomplace = doorplace + v3s16(-roomsize.X/2
+						+m_random.range(-roomsize.X/2+(roomsize.X%2==0?2:1),
+								roomsize.X/2-1),-1,0);
+			if(doordir == v3s16(0,0,-1)) // Z-
+				roomplace = doorplace + v3s16(-roomsize.X/2
+						+m_random.range(-roomsize.X/2+(roomsize.X%2==0?2:1),
+								roomsize.X/2-1),-1, -roomsize.Z+1);
+#endif
+#if 1
+			if(doordir == v3s16(1,0,0)) // X+
+				roomplace = doorplace +
+						v3s16(0,-1,m_random.range(-roomsize.Z+1,-2));
+			if(doordir == v3s16(-1,0,0)) // X-
+				roomplace = doorplace +
+						v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+1,-2));
+			if(doordir == v3s16(0,0,1)) // Z+
+				roomplace = doorplace +
+						v3s16(m_random.range(-roomsize.X+1,-2),-1,0);
+			if(doordir == v3s16(0,0,-1)) // Z-
+				roomplace = doorplace +
+						v3s16(m_random.range(-roomsize.X+1,-2),-1,-roomsize.Z+1);
+#endif
+#if 0
 			if(doordir == v3s16(1,0,0)) // X+
-				roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1));
+				roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
 			if(doordir == v3s16(-1,0,0)) // X-
-				roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2+m_random.range(-roomsize.Z/2+1,roomsize.Z/2-1));
+				roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
 			if(doordir == v3s16(0,0,1)) // Z+
-				roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,0);
+				roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
 			if(doordir == v3s16(0,0,-1)) // Z-
-				roomplace = doorplace + v3s16(-roomsize.X/2+m_random.range(-roomsize.X/2+1,roomsize.X/2-1),-1,-roomsize.Z+1);
+				roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
+#endif
 			
 			// Check fit
 			bool fits = true;
@@ -790,7 +840,7 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
 		
 		// Determine walker start position
 
-		bool start_in_last_room = (random.range(0,1)==0);
+		bool start_in_last_room = (random.range(0,2)!=0);
 		//bool start_in_last_room = true;
 
 		v3s16 walker_start_place;
@@ -858,7 +908,9 @@ NoiseParams get_cave_noise1_params(u64 seed)
 {
 	/*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
 			200, CAVE_NOISE_SCALE);*/
-	return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
+	/*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
+			100, CAVE_NOISE_SCALE);*/
+	return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
 			100, CAVE_NOISE_SCALE);
 }
 
@@ -866,7 +918,9 @@ NoiseParams get_cave_noise2_params(u64 seed)
 {
 	/*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
 			200, CAVE_NOISE_SCALE);*/
-	return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
+	/*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
+			100, CAVE_NOISE_SCALE);*/
+	return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.6,
 			100, CAVE_NOISE_SCALE);
 }
 
@@ -1054,6 +1108,7 @@ double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
 	v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
 	v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
 	double a = -31000;
+	// Corners
 	a = MYMAX(a, find_ground_level_from_noise(seed,
 			v2s16(node_min.X, node_min.Y), p));
 	a = MYMAX(a, find_ground_level_from_noise(seed,
@@ -1062,8 +1117,18 @@ double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
 			v2s16(node_max.X, node_max.Y), p));
 	a = MYMAX(a, find_ground_level_from_noise(seed,
 			v2s16(node_min.X, node_min.Y), p));
+	// Center
 	a = MYMAX(a, find_ground_level_from_noise(seed,
 			v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
+	// Side middle points
+	a = MYMAX(a, find_ground_level_from_noise(seed,
+			v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
+	a = MYMAX(a, find_ground_level_from_noise(seed,
+			v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
+	a = MYMAX(a, find_ground_level_from_noise(seed,
+			v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
+	a = MYMAX(a, find_ground_level_from_noise(seed,
+			v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
 	return a;
 }
 
@@ -1074,6 +1139,7 @@ double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
 	v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
 	v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
 	double a = 31000;
+	// Corners
 	a = MYMIN(a, find_ground_level_from_noise(seed,
 			v2s16(node_min.X, node_min.Y), p));
 	a = MYMIN(a, find_ground_level_from_noise(seed,
@@ -1082,8 +1148,18 @@ double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
 			v2s16(node_max.X, node_max.Y), p));
 	a = MYMIN(a, find_ground_level_from_noise(seed,
 			v2s16(node_min.X, node_min.Y), p));
+	// Center
 	a = MYMIN(a, find_ground_level_from_noise(seed,
 			v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
+	// Side middle points
+	a = MYMIN(a, find_ground_level_from_noise(seed,
+			v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
+	a = MYMIN(a, find_ground_level_from_noise(seed,
+			v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
+	a = MYMIN(a, find_ground_level_from_noise(seed,
+			v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
+	a = MYMIN(a, find_ground_level_from_noise(seed,
+			v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
 	return a;
 }
 
@@ -1328,7 +1404,7 @@ void make_block(BlockMakeData *data)
 		If block is deep underground, this is set to true and ground
 		density noise is not generated, for speed optimization.
 	*/
-	bool all_is_ground_except_caves = (minimum_ground_depth > 16);
+	bool all_is_ground_except_caves = (minimum_ground_depth > 40);
 	
 	/*
 		Create a block-specific seed

+ 6 - 1
src/server.cpp

@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "content_craft.h"
 #include "content_nodemeta.h"
 #include "mapblock.h"
+#include "serverobject.h"
 
 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
 
@@ -2411,8 +2412,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 							toolname = titem->getToolName();
 						}
 					}
+
+					v3f playerpos = player->getPosition();
+					v3f objpos = obj->getBasePosition();
+					v3f dir = (objpos - playerpos).normalize();
 					
-					u16 wear = obj->punch(toolname);
+					u16 wear = obj->punch(toolname, dir);
 					
 					if(titem)
 					{

+ 0 - 598
src/serverobject.cpp

@@ -19,9 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "serverobject.h"
 #include <fstream>
-#include "environment.h"
 #include "inventory.h"
-#include "collision.h"
 
 core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
 
@@ -71,600 +69,4 @@ void ServerActiveObject::registerType(u16 type, Factory f)
 }
 
 
-/*
-	TestSAO
-*/
-
-// Prototype
-TestSAO proto_TestSAO(NULL, 0, v3f(0,0,0));
-
-TestSAO::TestSAO(ServerEnvironment *env, u16 id, v3f pos):
-	ServerActiveObject(env, id, pos),
-	m_timer1(0),
-	m_age(0)
-{
-	ServerActiveObject::registerType(getType(), create);
-}
-
-ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos,
-		const std::string &data)
-{
-	return new TestSAO(env, id, pos);
-}
-
-void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
-		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;
-		//dstream<<"TestSAO: id="<<getId()<<" sending data"<<std::endl;
-
-		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);
-		messages.push_back(aom);
-	}
-}
-
-
-/*
-	ItemSAO
-*/
-
-// Prototype
-ItemSAO proto_ItemSAO(NULL, 0, v3f(0,0,0), "");
-
-ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
-		const std::string inventorystring):
-	ServerActiveObject(env, id, pos),
-	m_inventorystring(inventorystring),
-	m_speed_f(0,0,0),
-	m_last_sent_position(0,0,0)
-{
-	ServerActiveObject::registerType(getType(), create);
-}
-
-ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, 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 inventorystring = deSerializeString(is);
-	dstream<<"ItemSAO::create(): Creating item \""
-			<<inventorystring<<"\""<<std::endl;
-	return new ItemSAO(env, id, pos, inventorystring);
-}
-
-void ItemSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
-		bool send_recommended)
-{
-	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;
-	moveresult = collisionMoveSimple(&m_env->getMap(), 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);
-		char buf[6];
-		// command (0 = update position)
-		buf[0] = 0;
-		os.write(buf, 1);
-		// pos
-		writeS32((u8*)buf, m_base_position.X*1000);
-		os.write(buf, 4);
-		writeS32((u8*)buf, m_base_position.Y*1000);
-		os.write(buf, 4);
-		writeS32((u8*)buf, m_base_position.Z*1000);
-		os.write(buf, 4);
-		// create message and add to list
-		ActiveObjectMessage aom(getId(), false, os.str());
-		messages.push_back(aom);
-	}
-}
-
-std::string ItemSAO::getClientInitializationData()
-{
-	std::ostringstream os(std::ios::binary);
-	char buf[6];
-	// version
-	buf[0] = 0;
-	os.write(buf, 1);
-	// pos
-	writeS32((u8*)buf, m_base_position.X*1000);
-	os.write(buf, 4);
-	writeS32((u8*)buf, m_base_position.Y*1000);
-	os.write(buf, 4);
-	writeS32((u8*)buf, m_base_position.Z*1000);
-	os.write(buf, 4);
-	// inventorystring
-	os<<serializeString(m_inventorystring);
-	return os.str();
-}
-
-std::string ItemSAO::getStaticData()
-{
-	dstream<<__FUNCTION_NAME<<std::endl;
-	std::ostringstream os(std::ios::binary);
-	char buf[1];
-	// version
-	buf[0] = 0;
-	os.write(buf, 1);
-	// inventorystring
-	os<<serializeString(m_inventorystring);
-	return os.str();
-}
-
-InventoryItem * ItemSAO::createInventoryItem()
-{
-	try{
-		std::istringstream is(m_inventorystring, std::ios_base::binary);
-		InventoryItem *item = InventoryItem::deSerialize(is);
-		dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
-				<<m_inventorystring<<"\" -> item="<<item
-				<<std::endl;
-		return item;
-	}
-	catch(SerializationError &e)
-	{
-		dstream<<__FUNCTION_NAME<<": serialization error: "
-				<<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
-		return NULL;
-	}
-}
-
-
-/*
-	RatSAO
-*/
-
-// Prototype
-RatSAO proto_RatSAO(NULL, 0, v3f(0,0,0));
-
-RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos):
-	ServerActiveObject(env, id, 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* RatSAO::create(ServerEnvironment *env, u16 id, 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, id, pos);
-}
-
-void RatSAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
-		bool send_recommended)
-{
-	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;
-	moveresult = collisionMoveSimple(&m_env->getMap(), 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());
-		messages.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()
-{
-	//dstream<<__FUNCTION_NAME<<std::endl;
-	std::ostringstream os(std::ios::binary);
-	// version
-	writeU8(os, 0);
-	return os.str();
-}
-
-InventoryItem* RatSAO::createPickedUpItem()
-{
-	std::istringstream is("CraftItem rat 1", std::ios_base::binary);
-	InventoryItem *item = InventoryItem::deSerialize(is);
-	return item;
-}
-
-/*
-	Oerkki1SAO
-*/
-
-// Prototype
-Oerkki1SAO proto_Oerkki1SAO(NULL, 0, v3f(0,0,0));
-
-Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos):
-	ServerActiveObject(env, id, 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;
-}
-
-ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, 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, id, pos);
-	o->m_hp = hp;
-	return o;
-}
-
-void Oerkki1SAO::step(float dtime, Queue<ActiveObjectMessage> &messages,
-		bool send_recommended)
-{
-	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;
-	}
-
-	// Apply gravity
-	m_speed_f.Y -= dtime*9.81*BS;
-
-	/*
-		Move around if some player is close
-	*/
-	bool player_is_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();
-		if(m_base_position.getDistanceFrom(playerpos) < BS*15.0)
-		{
-			player_is_close = true;
-			near_player_pos = playerpos;
-			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 ndir = near_player_pos - m_base_position;
-		ndir.Y = 0;
-		ndir /= ndir.getLength();
-		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);
-
-		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;
-				// Jump
-				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 += ((float)(myrand()%200)-100)/100*90;
-				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*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;
-	moveresult = collisionMoveSimple(&m_env->getMap(), 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());
-		messages.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()
-{
-	//dstream<<__FUNCTION_NAME<<std::endl;
-	std::ostringstream os(std::ios::binary);
-	// version
-	writeU8(os, 0);
-	// hp
-	writeU8(os, m_hp);
-	return os.str();
-}
-
-u16 Oerkki1SAO::punch(const std::string &toolname)
-{
-	u16 amount = 5;
-	if(amount < m_hp)
-	{
-		m_hp -= amount;
-	}
-	else
-	{
-		// Die
-		m_removed = true;
-	}
-	return 65536/100;
-}
-
 

+ 8 - 94
src/serverobject.h

@@ -78,8 +78,7 @@ public:
 			same time so that the data can be combined in a single
 			packet.
 	*/
-	virtual void step(float dtime, Queue<ActiveObjectMessage> &messages,
-			bool send_recommended){}
+	virtual void step(float dtime, bool send_recommended){}
 	
 	/*
 		The return value of this is passed to the client-side object
@@ -104,7 +103,8 @@ public:
 		If the object doesn't return an item, this will be called.
 		Return value is tool wear.
 	*/
-	virtual u16 punch(const std::string &toolname){return 0;}
+	virtual u16 punch(const std::string &toolname, v3f dir)
+	{return 0;}
 	
 	/*
 		Number of players which know about this object. Object won't be
@@ -144,6 +144,11 @@ public:
 	*/
 	v3s16 m_static_block;
 	
+	/*
+		Queue of messages to be sent to the client
+	*/
+	Queue<ActiveObjectMessage> m_messages_out;
+	
 protected:
 	// Used for creating objects based on type
 	typedef ServerActiveObject* (*Factory)
@@ -159,96 +164,5 @@ private:
 	static core::map<u16, Factory> m_types;
 };
 
-class TestSAO : public ServerActiveObject
-{
-public:
-	TestSAO(ServerEnvironment *env, u16 id, v3f pos);
-	u8 getType() const
-		{return ACTIVEOBJECT_TYPE_TEST;}
-	static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
-			const std::string &data);
-	void step(float dtime, Queue<ActiveObjectMessage> &messages,
-			bool send_recommended);
-private:
-	float m_timer1;
-	float m_age;
-};
-
-class ItemSAO : public ServerActiveObject
-{
-public:
-	ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
-			const std::string inventorystring);
-	u8 getType() const
-		{return ACTIVEOBJECT_TYPE_ITEM;}
-	static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
-			const std::string &data);
-	void step(float dtime, Queue<ActiveObjectMessage> &messages,
-			bool send_recommended);
-	std::string getClientInitializationData();
-	std::string getStaticData();
-	InventoryItem* createInventoryItem();
-	InventoryItem* createPickedUpItem(){return createInventoryItem();}
-private:
-	std::string m_inventorystring;
-	v3f m_speed_f;
-	v3f m_last_sent_position;
-	IntervalLimiter m_move_interval;
-};
-
-class RatSAO : public ServerActiveObject
-{
-public:
-	RatSAO(ServerEnvironment *env, u16 id, v3f pos);
-	u8 getType() const
-		{return ACTIVEOBJECT_TYPE_RAT;}
-	static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
-			const std::string &data);
-	void step(float dtime, Queue<ActiveObjectMessage> &messages,
-			bool send_recommended);
-	std::string getClientInitializationData();
-	std::string getStaticData();
-	InventoryItem* createPickedUpItem();
-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, u16 id, v3f pos);
-	u8 getType() const
-		{return ACTIVEOBJECT_TYPE_OERKKI1;}
-	static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
-			const std::string &data);
-	void step(float dtime, Queue<ActiveObjectMessage> &messages,
-			bool send_recommended);
-	std::string getClientInitializationData();
-	std::string getStaticData();
-	InventoryItem* createPickedUpItem(){return NULL;}
-	u16 punch(const std::string &toolname);
-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;
-	u8 m_hp;
-};
-
 #endif