aboutsummaryrefslogtreecommitdiff
path: root/src/hud.cpp
Commit message (Collapse)AuthorAge
* Add z-index management to HUDPierre-Yves Rollo2019-12-06
|
* Minimap: Fix radar restriction broken by 9649e47SmallJoker2019-02-23
| | | | | Server-side radar restriction is now possible again Thanks to @pgimeno for this nice catch.
* Fix last clang-tidy reported problems for performance-type-promotion-in-math-fnLoic Blot2018-04-03
| | | | | | Based on https://travis-ci.org/minetest/minetest/jobs/361810382 output Also fix 2 missing copyright notices
* [CSM] Add basic HUD manipulation. (#6067)red-0012018-01-20
| | | | | | * [CSM] Add basic HUD manipulation. Workaround for on_connect not working right now.
* Move files to subdirectories (#6599)Vitaliy2017-11-08
| | | | * Move files around
* Statbars: fix incorrect half-images in non-standard orientations (fixes #6198)Nathanaël Courant2017-08-27
|
* Add clientside translations.Ekdohibs2017-08-24
|
* Optimize headers (part 2) (#6272)Loïc Blot2017-08-18
| | | | | | | | | | | | | | * Optimize headers (part 2) * less debug.h in headers * less remoteplayer.h for everybody * Cleanup (part 2) * camera.h: mesh.h * mapgen.h: mapnode.h * serverenvironment.h: mapblock.h * nodedef.h: shader.h
* Modernize various files (part 2)Loic Blot2017-08-18
| | | | | | | | | * range-based for loops * emplace_back instead of push_back * code style * C++ headers instead of C headers * Default operators * empty stl function
* Irrlicht cleanup: cleanup various object to use RenderingEngine (#6088)Loïc Blot2017-07-02
| | | | | | | | | | | * Irrlicht cleanup: cleanup various object to use RenderingEngine * CAO doesn't need scenemanager in addToScene * Camera doesn't need VideoDriver pointer or SceneManager in constructor * Hud doesn't need driver & scene manager in constructor * Hud doesn't need scenemanager pointer * Tile.h doesn't need IrrlichtDevice header (just SMaterial) * WieldMeshSceneNode: only take scene, we always use scene root node as parent
* Isolate irrlicht references and use a singleton (#6041)Loïc Blot2017-06-26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Add Device3D class which will contain IrrlichtDevice interface move getSupportedVideoDrivers to Device3D Add Device3D singleton & use it in various places Rename Device3D to Rendering engine & add helper functions to various device pointers More singleton work RenderingEngine owns draw_load_screen move draw functions to RenderingEngine Reduce IrrlichtDevice exposure and guienvironment RenderingEngine: Expose get_timer_time() to remove device from guiEngine Make irrlichtdevice & scene manager less exposed * Code style fixes * Move porting::getVideoDriverName, getVideoDriverFriendlyName, getDisplayDensity, getDisplaySize to RenderingEngine Fix XORG_USED macro -> RenderingEngine + create_engine_device from RenderingEngine constructor directly * enum paralax => enum parallax
* hud.cpp: fix wrong indent in drawItemLoïc Blot2017-06-19
|
* Cpp11 initializers 2 (#5999)Loïc Blot2017-06-17
| | | | | | | | | | * C++11 patchset 10: continue cleanup on constructors * Drop obsolete bool MainMenuData::enable_public (setting is called with cURL in server loop) * More classes cleanup * More classes cleanup + change NULL tests to boolean tests
* Use thread_local instead from some static settings (#5955)Loïc Blot2017-06-11
| | | | | thread_local permits to limit variable lifetime to thread duration. Use it on each setting place which uses static to cache variable result only for thread lifetime. This permits to keep the same performance level & reconfigure server from MT gui in those various variables places. Add thread_local to undersampling calculation too.
* Do not shade inventory items with textures (#5869)Dániel Juhász2017-06-01
| | | | This commit restores the old behavior: if an inventory item has an own inventory texture, it will not be shaded.
* Time: Change old `u32` timestamps to 64-bit (#5818)SmallJoker2017-05-26
| | | | MacOSX build fix + cleanups
* Add option to use neither node highlighting nor outliningezhh2017-05-15
|
* Clean up getTime helpersShadowNinja2017-04-28
| | | | | | This increases size of the getTime return values to 64 bits. It also removes the TimeGetter classes since the getTime functions are now very precise.
* Soft node overlay (#5186)Dániel Juhász2017-04-21
| | | | This commit adds node overlays, which are tiles that are drawn on top of other tiles.
* Hardware coloring for itemstacksDániel Juhász2017-04-08
| | | | | | | | | | Adds the possibility to colorize item stacks based on their metadata. In the item/node definition you can specify palette (an image file) and color (fallback color if the item has no palette or metadata). Then you can add palette_index to the metadata. Dropped itemstacks with different colors do not merge.
* Environment & IGameDef code refactoring (#4985)Ner'zhul2017-01-09
| | | | | | | | | | | | | | | | | | | | | * Environment code refactoring * Cleanup includes & class declarations in client & server environment to improve build speed * ServerEnvironment::m_gamedef is now a pointer to Server instead of IGameDef, permitting to cleanup many casts. * Cleanup IGameDef * Move ITextureSource* IGameDef::getTextureSource() to Client only. * Also move ITextureSource *IGameDef::tsrc() helper * drop getShaderSource, getSceneManager, getSoundManager & getCamera abstract call * drop unused emerge() call * cleanup server unused functions (mentionned before) * Drop one unused parameter from ContentFeatures::updateTextures * move checkLocalPrivilege to Client * Remove some unnecessary casts * create_formspec_menu: remove IWritableTextureSource pointer, as client already knows it * Fix some comments * Change required IGameDef to Server/Client pointers * Previous change that game.cpp sometimes calls functions with Client + InventoryManager + IGameDef in same functions but it's the same objects * Remove duplicate Client pointer in GUIFormSpecMenu::GUIFormSpecMenu * drop ClientMap::sectorWasDrawn which is unused
* Halo: Highlight selected faceRealBadAngel2016-11-12
| | | | | This is a slightly modified and cleaned up version of #3774 by RealBadAngel. By sofar: Remove color change (just make it lighter) and some minor cleanups.
* Escape more strings: formspecs, item descriptions, infotexts...Ekdohibs2016-04-24
| | | | | | Also, change the escape character to the more standard \x1b Thus, it can be used in the future for translation or colored text, for example.
* Fix inventory hud scalingrubenwardy2016-04-12
|
* Fix hotbar placement on displays with low screen densityPilzAdam2016-04-11
|
* Hud: Cache hud_scaling, fix minor style issueskwolekr2016-04-10
|
* Hud: Fix offset being ignored by inventory barrubenwardy2016-04-10
|
* Use single box for halo meshRealBadAngel2016-02-11
|
* Cleanup selection mesh code, add shaders for halo and selection boxesRealBadAngel2016-02-08
|
* small drawItemStack cleanupest312016-02-08
| | | | | | -> Replace the three bool params with an enum -> Add struct for the static content, leads to less repetition -> cache enable_animations setting
* Use meshes to display inventory itemsRealBadAngel2016-02-07
|
* Change i++ to ++iDavid Jones2015-08-25
|
* Use UTF-8 instead of narrowest312015-07-08
| | | | | Use wide_to_utf8 and utf8_to_wide instead of wide_to_narrow and narrow_to_wide at almost all places. Only exceptions: test functions for narrow conversion, and chat, which is done in a separate commit.
* Move globals from main.cpp to more sane locationsCraig Robbins2015-04-01
| | | | | | | | | | | | Move debug streams to log.cpp|h Move GUI-related globals to clientlauncher Move g_settings and g_settings_path to settings.cpp|h Move g_menuclouds to clouds.cpp|h Move g_profiler to profiler.cpp|h
* Clean scaling pre-filter for formspec/HUD.Aaron Suen2015-04-01
|
* Replace std::list to std::vector into tile.cpp (m_texture_trash) and move ↵Loic Blot2015-03-05
| | | | tile.hpp to src/client/
* Hud: Modify Y-positioning of health/breath starbars to prevent overlapping ↵kwolekr2015-02-08
| | | | with Hotbar
* Split gui_scaling to gui_scaling + hud_scaling as those elements need ↵sapier2015-01-09
| | | | different handling on some devices
* Fix MSVC buildSmallJoker2014-12-05
| | | | Note: The unit test was technically incorrect for all platforms but passes due to implicit casting
* Make hud use fontengine toosapier2014-11-30
| | | | | Fix non coding style conforming glb_fontengine to g_fontengine Fix fonts never been deleted due to grabbed to often
* Add support for Android 2.3+sapier2014-06-29
| | | | | | | | | | | | | There have been plenty of ppl involved in creating this version. I don't wanna mention names as I'm sure I'd forget someone so I just tell where help has been done: - The partial android versions done by various ppl - Testing on different android devices - reviewing code (especially the in core changes) - testing controls - reviewing texts A big thank you to everyone helping this to be completed!
* Support for scalable font and gui elementssapier2014-06-22
| | | | | Fix positioning of tabheader in order to be usable for scaling GUIs WARNING: this changes position of current tabheaders, mods have to adjust!
* Small cleanup of hud add/remove codesapier2014-05-31
|
* Add support for interlaced polarized 3d screenssapier2014-05-18
| | | | Add (experimental) support for topbottom as well as sidebyside 3d mode
* Fix old client showing duplicated health bar on new serversapier2014-05-11
| | | | | Fix client not showing hearts and bubbles on connecting to old server Fix server not remembering hud flags correctly
* Fix incorrect scaling of customized hud item selection markersapier2014-05-11
|
* Fix heart + bubble bar size on different texture packssapier2014-05-07
| | | | | | | Add DPI support for statbar Move heart+bubble bar to Lua HUD Add statbar size (based upon an idea by blue42u) Add support for customizing breath and statbar
* Bugfix: make waypoints respect camera offsetRealBadAngel2014-05-05
|
* Fix rounding issue of hud dpi on some machinessapier2014-04-27
|
* Add support for dpi based HUD scalingsapier2014-04-27
| | | | | | Add support for (configurable) multiline hotbar Improved screensize handling Add userdefined gui scale by BlockMen
ef='#n1079'>1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
/*
Minetest-c55
Copyright (C) 2010 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.
*/

// This file contains the DEPRECATED MapBlockObject system

#ifndef MAPBLOCKOBJECT_HEADER
#define MAPBLOCKOBJECT_HEADER

#include "common_irrlicht.h"
#include <math.h>
#include <string>
#include "serialization.h"
#include "mapnode.h"
#include "constants.h"
#include "debug.h"

#define MAPBLOCKOBJECT_TYPE_PLAYER 0
#define MAPBLOCKOBJECT_TYPE_SIGN 2
#define MAPBLOCKOBJECT_TYPE_RAT 3
#define MAPBLOCKOBJECT_TYPE_ITEM 4
// Used for handling selecting special stuff
//#define MAPBLOCKOBJECT_TYPE_PSEUDO 1000

class MapBlock;

class MapBlockObject
{
public:
	MapBlockObject(MapBlock *block, s16 id, v3f pos):
		m_collision_box(NULL),
		m_selection_box(NULL),
		m_block(block),
		m_id(id),
		m_pos(pos)
	{
	}
	virtual ~MapBlockObject()
	{
	}

	s16 getId()
	{
		return m_id;
	}
	MapBlock* getBlock()
	{
		return m_block;
	}
	
	// Writes id, pos and typeId
	void serializeBase(std::ostream &os, u8 version)
	{
		u8 buf[6];

		// id
		writeS16(buf, m_id);
		os.write((char*)buf, 2);
		
		// position
		// stored as x1000/BS v3s16
		v3s16 pos_i(m_pos.X*1000/BS, m_pos.Y*1000/BS, m_pos.Z*1000/BS);
		writeV3S16(buf, pos_i);
		os.write((char*)buf, 6);

		// typeId
		writeU16(buf, getTypeId());
		os.write((char*)buf, 2);
	}
	
	// Position where the object is drawn relative to block
	virtual v3f getRelativeShowPos()
	{
		return m_pos;
	}
	// Get floating point position on map
	v3f getAbsolutePos();

	void setBlockChanged();

	// Shootline is relative to block
	bool isSelected(core::line3d<f32> shootline)
	{
		if(m_selection_box == NULL)
			return false;

		core::aabbox3d<f32> offsetted_box(
				m_selection_box->MinEdge + m_pos,
				m_selection_box->MaxEdge + m_pos
		);

		return offsetted_box.intersectsWithLine(shootline);
	}

	core::aabbox3d<f32> getSelectionBoxOnMap()
	{
		v3f absolute_pos = getAbsolutePos();

		core::aabbox3d<f32> box(
				m_selection_box->MinEdge + absolute_pos,
				m_selection_box->MaxEdge + absolute_pos
		);

		return box;
	}
	
	/*
		Implementation interface
	*/

	virtual u16 getTypeId() const = 0;
	// Shall call serializeBase and then write the parameters
	virtual void serialize(std::ostream &os, u8 version) = 0;
	// Shall read parameters from stream
	virtual void update(std::istream &is, u8 version) = 0;

	virtual std::string getInventoryString() { return "None"; }
	
	// Reimplementation shall call this.
	virtual void updatePos(v3f pos)
	{
		m_pos = pos;
	}
	
	// Shall move the object around, modify it and possibly delete it.
	// Typical dtimes are 0.2 and 10000.
	// A return value of true requests deletion of the object by the caller.
	// NOTE: Only server calls this.
	virtual bool serverStep(float dtime, u32 daynight_ratio)
	{ return false; };

#ifdef SERVER
	void clientStep(float dtime) {};
	void addToScene(void *smgr) {};
	void removeFromScene() {};
	void updateLight(u8 light_at_pos) {};
#else
	// This should do slight animations only or so
	virtual void clientStep(float dtime) {};

	// NOTE: These functions should do nothing if the asked state is
	//       same as the current state
	// Shall add and remove relevant scene nodes for rendering the
	// object in the game world
	virtual void addToScene(scene::ISceneManager *smgr) = 0;
	// Shall remove stuff from the scene
	// Should return silently if there is nothing to remove
	// NOTE: This has to be called before calling destructor
	virtual void removeFromScene() = 0;
	
	// 0 <= light_at_pos <= LIGHT_SUN
	virtual void updateLight(u8 light_at_pos) {};
#endif

	virtual std::string infoText() { return ""; }
	
	// Shall be left NULL if doesn't collide
	// Position is relative to m_pos in block
	core::aabbox3d<f32> * m_collision_box;
	
	// Shall be left NULL if can't be selected
	core::aabbox3d<f32> * m_selection_box;

protected:
	MapBlock *m_block;
	// This differentiates the instance of the object
	// Not same as typeId.
	s16 m_id;
	// Position of the object inside the block
	// Units is node coordinates * BS
	v3f m_pos;

	friend class MapBlockObjectList;
};

#if 0
/*
	Used for handling selections of special stuff
*/
class PseudoMBObject : public MapBlockObject
{
public:
	// The constructor of every MapBlockObject should be like this
	PseudoMBObject(MapBlock *block, s16 id, v3f pos):
		MapBlockObject(block, id, pos)
	{
	}
	virtual ~PseudoMBObject()
	{
		if(m_selection_box)
			delete m_selection_box;
	}
	
	/*
		Implementation interface
	*/
	virtual u16 getTypeId() const
	{
		return MAPBLOCKOBJECT_TYPE_PSEUDO;
	}
	virtual void serialize(std::ostream &os, u8 version)
	{
		assert(0);
	}
	virtual void update(std::istream &is, u8 version)
	{
		assert(0);
	}
	virtual bool serverStep(float dtime, u32 daynight_ratio)
	{
		assert(0);
	}

	/*
		Special methods
	*/
	
	void setSelectionBox(core::aabbox3d<f32> box)
	{
		m_selection_box = new core::aabbox3d<f32>(box);
	}
	
protected:
};
#endif

class MovingObject : public MapBlockObject
{
public:
	// The constructor of every MapBlockObject should be like this
	MovingObject(MapBlock *block, s16 id, v3f pos):
		MapBlockObject(block, id, pos),
		m_speed(0,0,0),
		m_oldpos(pos),
		m_pos_animation_time(0),
		m_showpos(pos)
	{
		m_touching_ground = false;
	}
	virtual ~MovingObject()
	{
	}
	
	/*
		Implementation interface
	*/
	
	virtual u16 getTypeId() const = 0;

	virtual void serialize(std::ostream &os, u8 version)
	{
		serializeBase(os, version);

		u8 buf[6];

		// Write speed
		// stored as x100/BS v3s16
		v3s16 speed_i(m_speed.X*100/BS, m_speed.Y*100/BS, m_speed.Z*100/BS);
		writeV3S16(buf, speed_i);
		os.write((char*)buf, 6);
	}
	virtual void update(std::istream &is, u8 version)
	{
		u8 buf[6];
		
		// Read speed
		// stored as x100/BS v3s16
		is.read((char*)buf, 6);
		v3s16 speed_i = readV3S16(buf);
		v3f speed((f32)speed_i.X/100*BS,
				(f32)speed_i.Y/100*BS,
				(f32)speed_i.Z/100*BS);

		m_speed = speed;
	}
	
	// Reimplementation shall call this.
	virtual void updatePos(v3f pos)
	{
		m_oldpos = m_showpos;
		m_pos = pos;
		
		if(m_pos_animation_time < 0.001 || m_pos_animation_time > 1.0)
			m_pos_animation_time = m_pos_animation_time_counter;
		else
			m_pos_animation_time = m_pos_animation_time * 0.9
					+ m_pos_animation_time_counter * 0.1;
		m_pos_animation_time_counter = 0;
		m_pos_animation_counter = 0;
	}
	
	// Position where the object is drawn relative to block
	virtual v3f getRelativeShowPos()
	{
		return m_showpos;
	}
	// Returns m_showpos relative to whole map
	v3f getAbsoluteShowPos();

	virtual bool serverStep(float dtime, u32 daynight_ratio)
	{ return false; };
	virtual void clientStep(float dtime)
	{};
	
	/*virtual void addToScene(scene::ISceneManager *smgr) = 0;
	virtual void removeFromScene() = 0;*/

	/*
		Special methods
	*/
	
	// Move with collision detection, server side
	void move(float dtime, v3f acceleration);

	// Move from old position to new position, client side
	void simpleMove(float dtime);
	
protected:
	v3f m_speed;
	bool m_touching_ground;
	// Client-side moving
	v3f m_oldpos;
	f32 m_pos_animation_counter;
	f32 m_pos_animation_time;
	f32 m_pos_animation_time_counter;
	v3f m_showpos;
};

class SignObject : public MapBlockObject
{
public:
	// The constructor of every MapBlockObject should be like this
	SignObject(MapBlock *block, s16 id, v3f pos):
		MapBlockObject(block, id, pos),
		m_node(NULL)
	{
		m_selection_box = new core::aabbox3d<f32>
				(-BS*0.4,-BS*0.5,-BS*0.4, BS*0.4,BS*0.5,BS*0.4);
	}
	virtual ~SignObject()
	{
		delete m_selection_box;
	}
	
	/*
		Implementation interface
	*/
	virtual u16 getTypeId() const
	{
		return MAPBLOCKOBJECT_TYPE_SIGN;
	}
	virtual void serialize(std::ostream &os, u8 version)
	{
		serializeBase(os, version);
		u8 buf[2];

		// Write yaw * 10
		writeS16(buf, m_yaw * 10);
		os.write((char*)buf, 2);

		// Write text length
		writeU16(buf, m_text.size());
		os.write((char*)buf, 2);
		
		// Write text
		os.write(m_text.c_str(), m_text.size());
	}
	virtual void update(std::istream &is, u8 version)
	{
		u8 buf[2];

		// Read yaw * 10
		is.read((char*)buf, 2);
		s16 yaw_i = readS16(buf);
		m_yaw = (f32)yaw_i / 10;

		// Read text length
		is.read((char*)buf, 2);
		u16 size = readU16(buf);

		// Read text
		m_text.clear();
		for(u16 i=0; i<size; i++)
		{
			is.read((char*)buf, 1);
			m_text += buf[0];
		}

		updateSceneNode();
	}
	virtual bool serverStep(float dtime, u32 daynight_ratio)
	{
		return false;
	}
#ifndef SERVER
	virtual void addToScene(scene::ISceneManager *smgr)
	{
		if(m_node != NULL)
			return;
		
		video::IVideoDriver* driver = smgr->getVideoDriver();
		
		scene::SMesh *mesh = new scene::SMesh();
		{ // Front
		scene::IMeshBuffer *buf = new scene::SMeshBuffer();
		video::SColor c(255,255,255,255);
		video::S3DVertex vertices[4] =
		{
			video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 0,1),
			video::S3DVertex(-BS/2,-BS/2,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, driver->getTexture(porting::getDataPath("sign.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_REF;
		// Add to mesh
		mesh->addMeshBuffer(buf);
		buf->drop();
		}
		{ // Back
		scene::IMeshBuffer *buf = new scene::SMeshBuffer();
		video::SColor c(255,255,255,255);
		video::S3DVertex vertices[4] =
		{
			video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
			video::S3DVertex(BS/2,-BS/2,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, driver->getTexture(porting::getDataPath("sign_back.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_REF;
		// Add to mesh
		mesh->addMeshBuffer(buf);
		buf->drop();
		}
		m_node = smgr->addMeshSceneNode(mesh, NULL);
		mesh->drop();

		updateSceneNode();
	}
	virtual void removeFromScene()
	{
		if(m_node != NULL)
		{
			m_node->remove();
			m_node = NULL;
		}
	}
	virtual void 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();
		
		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;
			}
		}
	}
#endif

	virtual std::string infoText()
	{
		return std::string("\"") + m_text + "\"";
	}

	virtual std::string getInventoryString()
	{
		return std::string("Sign ")+m_text;
	}

	/*
		Special methods
	*/
	void updateSceneNode()
	{
#ifndef SERVER
		if(m_node != NULL)
		{
			m_node->setPosition(getAbsolutePos());
			m_node->setRotation(v3f(0, m_yaw, 0));
		}
#endif
	}

	void setText(std::string text)
	{
		if(text.size() > SIGN_TEXT_MAX_LENGTH)
			text = text.substr(0, SIGN_TEXT_MAX_LENGTH);
		m_text = text;

		setBlockChanged();
	}

	std::string getText()
	{
		return m_text;
	}

	void setYaw(f32 yaw)
	{
		m_yaw = yaw;

		setBlockChanged();
	}
	
protected:
	scene::IMeshSceneNode *m_node;
	std::string m_text;
	f32 m_yaw;
};

class RatObject : public MovingObject
{
public:
	RatObject(MapBlock *block, s16 id, v3f pos):
		MovingObject(block, id, pos),
		m_node(NULL)
	{
		m_collision_box = new core::aabbox3d<f32>
				(-BS*0.3,-BS*.25,-BS*0.3, BS*0.3,BS*0.25,BS*0.3);
		m_selection_box = new core::aabbox3d<f32>
				(-BS*0.3,-BS*.25,-BS*0.3, BS*0.3,BS*0.25,BS*0.3);
		
		m_yaw = 0;
		m_counter1 = 0;
		m_counter2 = 0;
		m_age = 0;
	}
	virtual ~RatObject()
	{
		delete m_collision_box;
		delete m_selection_box;
	}
	
	/*
		Implementation interface
	*/
	virtual u16 getTypeId() const
	{
		return MAPBLOCKOBJECT_TYPE_RAT;
	}
	virtual void serialize(std::ostream &os, u8 version)
	{
		MovingObject::serialize(os, version);
		u8 buf[2];

		// Write yaw * 10
		writeS16(buf, m_yaw * 10);
		os.write((char*)buf, 2);

	}
	virtual void update(std::istream &is, u8 version)
	{
		MovingObject::update(is, version);
		u8 buf[2];
		
		// Read yaw * 10
		is.read((char*)buf, 2);
		s16 yaw_i = readS16(buf);
		m_yaw = (f32)yaw_i / 10;

		updateNodePos();
	}

	virtual bool serverStep(float dtime, u32 daynight_ratio)
	{
		m_age += dtime;
		if(m_age > 60)
			// Die
			return true;

		v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));

		f32 speed = 2*BS;

		m_speed.X = speed * dir.X;
		m_speed.Z = speed * dir.Z;

		if(m_touching_ground && (m_oldpos - m_pos).getLength() < dtime*speed/2)
		{
			m_counter1 -= dtime;
			if(m_counter1 < 0.0)
			{
				m_counter1 += 1.0;
				m_speed.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_pos;

		//m_yaw += dtime*90;

		move(dtime, v3f(0, -9.81*BS, 0));

		//updateNodePos();

		return false;
	}
#ifndef SERVER
	virtual void clientStep(float dtime)
	{
		//m_pos += m_speed * dtime;
		MovingObject::simpleMove(dtime);

		updateNodePos();
	}
	
	virtual void addToScene(scene::ISceneManager *smgr);

	virtual void removeFromScene()
	{
		if(m_node == NULL)
			return;

		m_node->remove();
		m_node = NULL;
	}

	virtual void 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();
		
		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;
			}
		}
	}
	
#endif

	virtual std::string getInventoryString()
	{
		// There must be a space after the name
		// Or does there?
		return std::string("Rat ");
	}

	/*
		Special methods
	*/
	
	void updateNodePos()
	{
		if(m_node == NULL)
			return;

		m_node->setPosition(getAbsoluteShowPos());
		m_node->setRotation(v3f(0, -m_yaw+180, 0));
	}
	
protected:
	scene::IMeshSceneNode *m_node;
	float m_yaw;

	float m_counter1;
	float m_counter2;
	float m_age;
};

/*
	An object on the map that represents an inventory item
*/

class InventoryItem;

class ItemObject : public MapBlockObject
{
public:
	// The constructor of every MapBlockObject should be like this
	ItemObject(MapBlock *block, s16 id, v3f pos):
		MapBlockObject(block, id, pos),
		m_node(NULL)
	{
		/*m_selection_box = new core::aabbox3d<f32>
				(-BS*0.4,-BS*0.5,-BS*0.4, BS*0.4,BS*0.5,BS*0.4);*/
		m_selection_box = new core::aabbox3d<f32>
				(-BS/3,-BS/2,-BS/3, BS/3,-BS/2+BS*2/3,BS/3);
		m_yaw = 0.0;
	}
	virtual ~ItemObject()
	{
		delete m_selection_box;
	}
	
	/*
		Implementation interface
	*/
	virtual u16 getTypeId() const
	{
		return MAPBLOCKOBJECT_TYPE_ITEM;
	}
	virtual void serialize(std::ostream &os, u8 version)
	{
		serializeBase(os, version);
		u8 buf[2];

		// Write text length
		writeU16(buf, m_itemstring.size());
		os.write((char*)buf, 2);
		
		// Write text
		os.write(m_itemstring.c_str(), m_itemstring.size());
	}
	virtual void update(std::istream &is, u8 version)
	{
		u8 buf[2];

		// Read text length
		is.read((char*)buf, 2);
		u16 size = readU16(buf);

		// Read text
		std::string old_itemstring = m_itemstring;
		m_itemstring.clear();
		for(u16 i=0; i<size; i++)
		{
			is.read((char*)buf, 1);
			m_itemstring += buf[0];
		}
		
#ifndef SERVER
		if(m_itemstring != old_itemstring && m_node)
		{
			/*
				Update texture
			*/
			video::ITexture *texture = getItemImage();
			scene::IMesh *mesh = m_node->getMesh();
			if(mesh->getMeshBufferCount() >= 1)
			{
				scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
				//dstream<<"Setting texture "<<texture<<std::endl;
				buf->getMaterial().setTexture(0, texture);
			}
		}
		
		updateSceneNode();
#endif
	}

	virtual bool serverStep(float dtime, u32 daynight_ratio)
	{
		return false;
	}

#ifndef SERVER
	virtual void clientStep(float dtime)
	{
		m_yaw += dtime * 60;
		if(m_yaw >= 360.)
			m_yaw -= 360.;

		updateSceneNode();
	}
	
	virtual void addToScene(scene::ISceneManager *smgr);
	
	virtual void removeFromScene()
	{
		if(m_node != NULL)
		{
			m_node->remove();
			m_node = NULL;
		}
	}
	virtual void 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();
		
		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;
			}
		}
	}
#endif

	virtual std::string infoText()
	{
		return std::string("\"") + m_itemstring + "\"";
	}

	virtual std::string getInventoryString()
	{
		return std::string("ItemObj ")+m_itemstring;
	}

	/*
		Special methods
	*/

	InventoryItem * createInventoryItem();
	
#ifndef SERVER
	video::ITexture * getItemImage();

	void updateSceneNode()
	{
		if(m_node != NULL)
		{
			m_node->setPosition(getAbsolutePos());
			m_node->setRotation(v3f(0, m_yaw, 0));
		}
	}
#endif

	void setItemString(std::string inventorystring)
	{
		m_itemstring = inventorystring;
		setBlockChanged();
	}

	std::string getItemString()
	{
		return m_itemstring;
	}

protected:
	scene::IMeshSceneNode *m_node;
	std::string m_itemstring;
	f32 m_yaw;
};

/*
	NOTE: Not used.
*/
class PlayerObject : public MovingObject
{
public:
	PlayerObject(MapBlock *block, s16 id, v3f pos):
		MovingObject(block, id, pos),
		m_node(NULL),
		m_yaw(0)
	{
		m_collision_box = new core::aabbox3d<f32>
				(-BS*0.3,-BS*.25,-BS*0.3, BS*0.3,BS*0.25,BS*0.3);
		/*m_selection_box = new core::aabbox3d<f32>
				(-BS*0.3,-BS*.25,-BS*0.3, BS*0.3,BS*0.25,BS*0.3);*/
	}
	virtual ~PlayerObject()
	{
		if(m_collision_box)
			delete m_collision_box;
		if(m_selection_box)
			delete m_selection_box;
	}
	
	/*
		Implementation interface
	*/
	virtual u16 getTypeId() const
	{
		return MAPBLOCKOBJECT_TYPE_PLAYER;
	}
	virtual void serialize(std::ostream &os, u8 version)
	{
		// Object data is generated from actual player
	}
	virtual void update(std::istream &is, u8 version)
	{
		MovingObject::update(is, version);
		u8 buf[2];
		
		// Read yaw * 10
		is.read((char*)buf, 2);
		s16 yaw_i = readS16(buf);
		m_yaw = (f32)yaw_i / 10;

		updateNodePos();
	}

	virtual bool serverStep(float dtime, u32 daynight_ratio)
	{
		// Player is handled elsewhere.
		// Die.
		//return true;
		// Actually, fail very loudly:
		assert(0);
	}

#ifndef SERVER
	virtual void clientStep(float dtime)
	{
		MovingObject::simpleMove(dtime);

		updateNodePos();
	}
	
	virtual void addToScene(scene::ISceneManager *smgr);

	virtual void removeFromScene()
	{
		if(m_node == NULL)
			return;

		m_node->remove();
		m_node = NULL;
	}

	virtual void 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();
		
		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;
			}
		}
	}
	
#endif

	/*
		Special methods
	*/
	
	void updateNodePos()
	{
		if(m_node == NULL)
			return;

		m_node->setPosition(getAbsoluteShowPos());
		m_node->setRotation(v3f(0, -m_yaw+180, 0));
	}
	
protected:
	scene::IMeshSceneNode *m_node;
	float m_yaw;

	v3f m_oldpos;
};

struct DistanceSortedObject
{
	DistanceSortedObject(MapBlockObject *a_obj, f32 a_d)
	{
		obj = a_obj;
		d = a_d;
	}
	
	MapBlockObject *obj;
	f32 d;

	bool operator < (DistanceSortedObject &other)
	{
		return d < other.d;
	}
};

class MapBlockObjectList
{
public:
	MapBlockObjectList(MapBlock *block);
	~MapBlockObjectList();

	// Writes the count, id, the type id and the parameters of all objects
	void serialize(std::ostream &os, u8 version);

	// Reads ids, type_ids and parameters.
	// Creates, updates and deletes objects.
	// If smgr!=NULL, new objects are added to the scene
	void update(std::istream &is, u8 version, scene::ISceneManager *smgr,
			u32 daynight_ratio);

	// Finds a new unique id
	s16 getFreeId() throw(ContainerFullException);
	/*
		Adds an object.
		Set id to -1 to have this set it to a suitable one.
		The block pointer member is set to this block.
	*/
	void add(MapBlockObject *object)
			throw(ContainerFullException, AlreadyExistsException);

	// Deletes and removes all objects
	void clear();

	/*
		Removes an object.
		Ignores inexistent objects
	*/
	void remove(s16 id);
	/*
		References an object.
		The object will not be valid after step() or of course if
		it is removed.
		Grabbing the lock is recommended while processing.
	*/
	MapBlockObject * get(s16 id);

	// You'll want to grab this in a SharedPtr
	JMutexAutoLock * getLock()
	{
		return new JMutexAutoLock(m_mutex);
	}

	// Steps all objects and if server==true, removes those that
	// want to be removed
	void step(float dtime, bool server, u32 daynight_ratio);

	// Wraps an object that wants to move onto this block from an another
	// Returns true if wrapping was impossible
	bool wrapObject(MapBlockObject *object);
	
	// origin is relative to block
	void getObjects(v3f origin, f32 max_d,
			core::array<DistanceSortedObject> &dest);
	
	// Number of objects
	s32 getCount()
	{
		return m_objects.size();
	}

private:
	JMutex m_mutex;
	// Key is id
	core::map<s16, MapBlockObject*> m_objects;
	MapBlock *m_block;

	u32 m_last_update_daynight_ratio;
};


#endif