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
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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.
+GNU Lesser General Public License for more details.
-You should have received a copy of the GNU General Public License along
+You should have received a copy of the GNU Lesser 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 "clientobject.h"
#include "content_object.h"
#include "mesh.h"
-#include "utility.h" // For IntervalLimiter
#include "itemdef.h"
#include "tool.h"
#include "content_cso.h"
#include "sound.h"
#include "nodedef.h"
+#include "localplayer.h"
+#include "util/numeric.h" // For IntervalLimiter
+#include "util/serialize.h"
+#include "util/mathconstants.h"
+#include "map.h"
+#include <IMeshManipulator.h>
+
class Settings;
struct ToolCapabilities;
bool m_is_player;
bool m_is_local_player; // determined locally
// Property-ish things
- s16 m_hp_max;
- bool m_physical;
- float m_weight;
- core::aabbox3d<f32> m_collisionbox;
- std::string m_visual;
- v2f m_visual_size;
- core::array<std::string> m_textures;
- v2s16 m_spritediv;
- bool m_is_visible;
- bool m_makes_footstep_sound;
+ ObjectProperties m_prop;
//
scene::ISceneManager *m_smgr;
IrrlichtDevice *m_irr;
// Spritesheet/animation stuff
v2f m_tx_size;
v2s16 m_tx_basepos;
+ bool m_initial_tx_basepos_set;
bool m_tx_select_horiz_by_yawpitch;
int m_anim_frame;
int m_anim_num_frames;
float m_reset_textures_timer;
bool m_visuals_expired;
float m_step_distance_counter;
+ u8 m_last_light;
public:
GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
m_is_player(false),
m_is_local_player(false),
//
- m_hp_max(1),
- m_physical(false),
- m_weight(5),
- m_collisionbox(-0.5,-0.5,-0.5, 0.5,0.5,0.5),
- m_visual("sprite"),
- m_visual_size(1,1),
- m_spritediv(1,1),
- m_is_visible(true),
- m_makes_footstep_sound(false),
- //
m_smgr(NULL),
m_irr(NULL),
m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
m_hp(1),
m_tx_size(1,1),
m_tx_basepos(0,0),
+ m_initial_tx_basepos_set(false),
m_tx_select_horiz_by_yawpitch(false),
m_anim_frame(0),
m_anim_num_frames(1),
m_anim_timer(0),
m_reset_textures_timer(-1),
m_visuals_expired(false),
- m_step_distance_counter(0)
+ m_step_distance_counter(0),
+ m_last_light(255)
{
- m_textures.push_back("unknown_object.png");
if(gamedef == NULL)
ClientActiveObject::registerType(getType(), create);
}
}
core::aabbox3d<f32>* getSelectionBox()
{
- if(!m_is_visible || m_is_local_player)
+ if(!m_prop.is_visible || m_is_local_player)
return NULL;
return &m_selection_box;
}
m_visuals_expired = false;
- if(!m_is_visible || m_is_local_player)
+ if(!m_prop.is_visible || m_is_local_player)
return;
//video::IVideoDriver* driver = smgr->getVideoDriver();
- if(m_visual == "sprite"){
+ if(m_prop.visual == "sprite"){
infostream<<"GenericCAO::addToScene(): single_sprite"<<std::endl;
m_spritenode = smgr->addBillboardSceneNode(
NULL, v2f(1, 1), v3f(0,0,0), -1);
m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
- m_spritenode->setColor(video::SColor(255,0,0,0));
- m_spritenode->setVisible(false); /* Set visible when brightness is known */
- m_spritenode->setSize(m_visual_size*BS);
+ u8 li = m_last_light;
+ m_spritenode->setColor(video::SColor(255,li,li,li));
+ m_spritenode->setSize(m_prop.visual_size*BS);
{
const float txs = 1.0 / 1;
const float tys = 1.0 / 1;
txs, tys, 0, 0);
}
}
- else if(m_visual == "upright_sprite")
+ else if(m_prop.visual == "upright_sprite")
{
scene::SMesh *mesh = new scene::SMesh();
- double dx = BS*m_visual_size.X/2;
- double dy = BS*m_visual_size.Y/2;
+ double dx = BS*m_prop.visual_size.X/2;
+ double dy = BS*m_prop.visual_size.Y/2;
{ // Front
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
- video::SColor c(255,255,255,255);
+ u8 li = m_last_light;
+ video::SColor c(255,li,li,li);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-dx,-dy,0, 0,0,0, c, 0,1),
}
{ // Back
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
- video::SColor c(255,255,255,255);
+ u8 li = m_last_light;
+ video::SColor c(255,li,li,li);
video::S3DVertex vertices[4] =
{
video::S3DVertex(dx,-dy,0, 0,0,0, c, 1,1),
// This is needed for changing the texture in the future
m_meshnode->setReadOnlyMaterials(true);
}
- else if(m_visual == "cube"){
+ else if(m_prop.visual == "cube"){
infostream<<"GenericCAO::addToScene(): cube"<<std::endl;
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
- m_meshnode->setScale(v3f(1));
- // Will be shown when we know the brightness
- m_meshnode->setVisible(false);
+ m_meshnode->setScale(v3f(m_prop.visual_size.X,
+ m_prop.visual_size.Y,
+ m_prop.visual_size.X));
+ u8 li = m_last_light;
+ setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li));
+ } else if(m_prop.visual == "wielditem"){
+ infostream<<"GenericCAO::addToScene(): node"<<std::endl;
+ infostream<<"textures: "<<m_prop.textures.size()<<std::endl;
+ if(m_prop.textures.size() >= 1){
+ infostream<<"textures[0]: "<<m_prop.textures[0]<<std::endl;
+ IItemDefManager *idef = m_gamedef->idef();
+ ItemStack item(m_prop.textures[0], 1, 0, "", idef);
+ scene::IMesh *item_mesh = item.getDefinition(idef).wield_mesh;
+
+ // Copy mesh to be able to set unique vertex colors
+ scene::IMeshManipulator *manip =
+ irr->getVideoDriver()->getMeshManipulator();
+ scene::IMesh *mesh = manip->createMeshUniquePrimitives(item_mesh);
+
+ m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
+ mesh->drop();
+
+ m_meshnode->setScale(v3f(m_prop.visual_size.X/2,
+ m_prop.visual_size.Y/2,
+ m_prop.visual_size.X/2));
+ u8 li = m_last_light;
+ setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li));
+ }
} else {
- infostream<<"GenericCAO::addToScene(): \""<<m_visual
+ infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
<<"\" not supported"<<std::endl;
}
updateTextures("");
{
bool is_visible = (m_hp != 0);
u8 li = decode_light(light_at_pos);
- video::SColor color(255,li,li,li);
- if(m_meshnode){
- setMeshColor(m_meshnode->getMesh(), color);
- m_meshnode->setVisible(is_visible);
- }
- if(m_spritenode){
- m_spritenode->setColor(color);
- m_spritenode->setVisible(is_visible);
+ if(li != m_last_light){
+ m_last_light = li;
+ video::SColor color(255,li,li,li);
+ if(m_meshnode){
+ setMeshColor(m_meshnode->getMesh(), color);
+ m_meshnode->setVisible(is_visible);
+ }
+ if(m_spritenode){
+ m_spritenode->setColor(color);
+ m_spritenode->setVisible(is_visible);
+ }
}
}
addToScene(m_smgr, m_gamedef->tsrc(), m_irr);
}
- if(m_physical){
- core::aabbox3d<f32> box = m_collisionbox;
+ if(m_prop.physical){
+ core::aabbox3d<f32> box = m_prop.collisionbox;
box.MinEdge *= BS;
box.MaxEdge *= BS;
collisionMoveResult moveresult;
- f32 pos_max_d = BS*0.25; // Distance per iteration
+ f32 pos_max_d = BS*0.125; // Distance per iteration
+ f32 stepheight = 0;
v3f p_pos = m_position;
v3f p_velocity = m_velocity;
+ v3f p_acceleration = m_acceleration;
IGameDef *gamedef = env->getGameDef();
- moveresult = collisionMovePrecise(&env->getMap(), gamedef,
- pos_max_d, box, dtime, p_pos, p_velocity);
+ moveresult = collisionMoveSimple(&env->getMap(), gamedef,
+ pos_max_d, box, stepheight, dtime,
+ p_pos, p_velocity, p_acceleration);
// Apply results
m_position = p_pos;
m_velocity = p_velocity;
+ m_acceleration = p_acceleration;
bool is_end_position = moveresult.collides;
pos_translator.update(m_position, is_end_position, dtime);
pos_translator.translate(dtime);
updateNodePos();
-
- m_velocity += dtime * m_acceleration;
} else {
m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
m_velocity += dtime * m_acceleration;
m_step_distance_counter += moved;
if(m_step_distance_counter > 1.5*BS){
m_step_distance_counter = 0;
- if(!m_is_local_player && m_makes_footstep_sound){
+ if(!m_is_local_player && m_prop.makes_footstep_sound){
INodeDefManager *ndef = m_gamedef->ndef();
- v3s16 p = floatToInt(getPosition()+v3f(0,-0.5*BS, 0), BS);
+ v3s16 p = floatToInt(getPosition() + v3f(0,
+ (m_prop.collisionbox.MinEdge.Y-0.5)*BS, 0), BS);
MapNode n = m_env->getMap().getNodeNoEx(p);
SimpleSoundSpec spec = ndef->get(n).sound_footstep;
m_gamedef->sound()->playSoundAt(spec, false, getPosition());
updateTextures("");
}
}
+ if(fabs(m_prop.automatic_rotate) > 0.001){
+ m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI;
+ updateNodePos();
+ }
}
void updateTexturePos()
else if(cam_to_entity.Y < -0.75)
col += 4;
else{
- float mob_dir = atan2(cam_to_entity.Z, cam_to_entity.X) / PI * 180.;
+ float mob_dir = atan2(cam_to_entity.Z, cam_to_entity.X) / M_PI * 180.;
float dir = mob_dir - m_yaw;
dir = wrapDegrees_180(dir);
//infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
if(m_spritenode)
{
- if(m_visual == "sprite")
+ if(m_prop.visual == "sprite")
{
std::string texturestring = "unknown_block.png";
- if(m_textures.size() >= 1)
- texturestring = m_textures[0];
+ if(m_prop.textures.size() >= 1)
+ texturestring = m_prop.textures[0];
texturestring += mod;
m_spritenode->setMaterialTexture(0,
tsrc->getTextureRaw(texturestring));
}
if(m_meshnode)
{
- if(m_visual == "cube")
+ if(m_prop.visual == "cube")
{
for (u32 i = 0; i < 6; ++i)
{
std::string texturestring = "unknown_block.png";
- if(m_textures.size() > i)
- texturestring = m_textures[i];
+ if(m_prop.textures.size() > i)
+ texturestring = m_prop.textures[i];
texturestring += mod;
AtlasPointer ap = tsrc->getTexture(texturestring);
material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
}
}
- else if(m_visual == "upright_sprite")
+ else if(m_prop.visual == "upright_sprite")
{
scene::IMesh *mesh = m_meshnode->getMesh();
{
std::string tname = "unknown_object.png";
- if(m_textures.size() >= 1)
- tname = m_textures[0];
+ if(m_prop.textures.size() >= 1)
+ tname = m_prop.textures[0];
tname += mod;
scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
buf->getMaterial().setTexture(0,
}
{
std::string tname = "unknown_object.png";
- if(m_textures.size() >= 2)
- tname = m_textures[1];
- else if(m_textures.size() >= 1)
- tname = m_textures[0];
+ if(m_prop.textures.size() >= 2)
+ tname = m_prop.textures[1];
+ else if(m_prop.textures.size() >= 1)
+ tname = m_prop.textures[0];
tname += mod;
scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
buf->getMaterial().setTexture(0,
u8 cmd = readU8(is);
if(cmd == GENERIC_CMD_SET_PROPERTIES)
{
- m_hp_max = readS16(is);
- m_physical = readU8(is);
- m_weight = readF1000(is);
- m_collisionbox.MinEdge = readV3F1000(is);
- m_collisionbox.MaxEdge = readV3F1000(is);
- m_visual = deSerializeString(is);
- m_visual_size = readV2F1000(is);
- m_textures.clear();
- u32 texture_count = readU16(is);
- for(u32 i=0; i<texture_count; i++){
- m_textures.push_back(deSerializeString(is));
- }
- m_spritediv = readV2S16(is);
- m_is_visible = readU8(is);
- m_makes_footstep_sound = readU8(is);
+ m_prop = gob_read_set_properties(is);
- m_selection_box = m_collisionbox;
+ m_selection_box = m_prop.collisionbox;
m_selection_box.MinEdge *= BS;
m_selection_box.MaxEdge *= BS;
- m_tx_size.X = 1.0 / m_spritediv.X;
- m_tx_size.Y = 1.0 / m_spritediv.Y;
+ m_tx_size.X = 1.0 / m_prop.spritediv.X;
+ m_tx_size.Y = 1.0 / m_prop.spritediv.Y;
+
+ if(!m_initial_tx_basepos_set){
+ m_initial_tx_basepos_set = true;
+ m_tx_basepos = m_prop.initial_sprite_basepos;
+ }
expireVisuals();
}
m_position = readV3F1000(is);
m_velocity = readV3F1000(is);
m_acceleration = readV3F1000(is);
- m_yaw = readF1000(is);
+ if(fabs(m_prop.automatic_rotate) < 0.001)
+ m_yaw = readF1000(is);
bool do_interpolate = readU8(is);
bool is_end_position = readU8(is);
float update_interval = readF1000(is);
+
+ // Place us a bit higher if we're physical, to not sink into
+ // the ground due to sucky collision detection...
+ if(m_prop.physical)
+ m_position += v3f(0,0.002,0);
if(do_interpolate){
- if(!m_physical)
+ if(!m_prop.physical)
pos_translator.update(m_position, is_end_position, update_interval);
} else {
pos_translator.init(m_position);
punchitem,
time_from_last_punch);
- dstream<<"Directly did_punch="<<result.did_punch<<" result.damage="<<result.damage<<std::endl;
-
if(result.did_punch && result.damage != 0)
{
if(result.damage < m_hp){
// As there is no definition, make a smoke puff
ClientSimpleObject *simple = createSmokePuff(
m_smgr, m_env, m_position,
- m_visual_size * BS);
+ m_prop.visual_size * BS);
m_env->addSimpleObject(simple);
}
// TODO: Execute defined fast response