voxelands/src/content_cao.cpp

398 lines
11 KiB
C++

/************************************************************************
* Minetest-c55
* Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
*
* content_cao.cpp
* voxelands - 3d voxel world sandbox game
* Copyright (C) Lisa 'darkrose' Milne 2013-2014 <lisa@ltmnet.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 3 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, see <http://www.gnu.org/licenses/>
*
* License updated from GPLv2 or later to GPLv3 or later by Lisa Milne
* for Voxelands.
************************************************************************/
#include "common.h"
#include "content_cao.h"
#include "content_mob.h"
#include "path.h"
#include "environment.h"
#include "mesh.h"
#include <ICameraSceneNode.h>
#include "sound.h"
core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
/*
MobCAO
*/
// Prototype
MobCAO proto_MobCAO;
MobCAO::MobCAO():
ClientActiveObject(0),
m_selection_box(-0.4*BS,-0.4*BS,-0.4*BS, 0.4*BS,0.8*BS,0.4*BS),
m_node(NULL),
m_position(v3f(0,10*BS,0)),
m_camera_offset(v3s16(0,0,0)),
m_yaw(0),
m_last_light(0),
m_player_hit_timer(0),
m_damage_visual_timer(0),
m_shooting(false),
m_shooting_unset_timer(0),
m_walking(false),
m_walking_unset_timer(0),
m_last_step(0),
m_next_foot(0),
m_draw_type(MDT_AUTO)
{
ClientActiveObject::registerType(getType(), create);
}
MobCAO::~MobCAO()
{
}
ClientActiveObject* MobCAO::create()
{
return new MobCAO();
}
void MobCAO::addToScene(scene::ISceneManager *smgr)
{
if (m_node != NULL)
return;
video::IVideoDriver* driver = smgr->getVideoDriver();
MobFeatures m = content_mob_features(m_content);
if (m.texture_display == MDT_EXTRUDED) {
ExtrudedSpriteSceneNode *node = new ExtrudedSpriteSceneNode(smgr->getRootSceneNode(),smgr,-1,v3f(0,0,0),v3f(0,0,0),v3f(5,5,5));
node->setVisible(true);
node->setSprite(g_texturesource->getTextureRaw(m.texture));
m_node = (scene::IMeshSceneNode*)node;
m_draw_type = MDT_EXTRUDED;
updateNodePos();
}else if (m.model != "") {
scene::IAnimatedMesh* mesh = createModelMesh(smgr,m.model.c_str(),true);
if (!mesh)
return;
scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
if (node) {
int s;
int e;
char buff[1024];
m.getAnimationFrames(MA_STAND,&s,&e);
node->setFrameLoop(s,e);
node->setScale(m.model_scale);
setMeshColor(node->getMesh(), video::SColor(255,255,255,255));
bool use_trilinear_filter = config_get_bool("client.video.trilinear");
bool use_bilinear_filter = config_get_bool("client.video.bilinear");
bool use_anisotropic_filter = config_get_bool("client.video.anisotropic");
// Set material flags and texture
if (path_get((char*)"texture",const_cast<char*>(m.texture.c_str()),1,buff,1024))
node->setMaterialTexture( 0, driver->getTexture(buff));
video::SMaterial& material = node->getMaterial(0);
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
material.setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
material.setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
node->setVisible(true);
m_draw_type = MDT_MODEL;
}
m_node = (scene::IMeshSceneNode*)node;
#if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
mesh->drop();
#endif
updateNodePos();
}else if (m.texture != "") {
char buff[1024];
bool use_trilinear_filter = config_get_bool("client.video.trilinear");
bool use_bilinear_filter = config_get_bool("client.video.bilinear");
bool use_anisotropic_filter = config_get_bool("client.video.anisotropic");
scene::IBillboardSceneNode *bill = smgr->addBillboardSceneNode(NULL, v2f(1, 1), v3f(0,0,0), -1);
if (path_get((char*)"texture",const_cast<char*>(m.texture.c_str()),1,buff,1024))
bill->setMaterialTexture( 0, driver->getTexture(buff));
bill->setMaterialFlag(video::EMF_LIGHTING, false);
bill->setMaterialFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
bill->setMaterialFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
bill->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
bill->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
bill->setMaterialFlag(video::EMF_FOG_ENABLE, true);
bill->setColor(video::SColor(255,0,0,0));
bill->setVisible(true);
#if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
bill->setSize(m.model_scale.X*BS,m.model_scale.Y*BS,m.model_scale.Z*BS);
#else
v2f bb_size(m.model_scale.X*BS,m.model_scale.Y*BS);
bill->setSize(bb_size);
#endif
m_node = (scene::IMeshSceneNode*)bill;
m_draw_type = MDT_SPRITE;
updateNodePos();
}
}
void MobCAO::removeFromScene()
{
if (m_node != NULL) {
m_node->remove();
m_node = NULL;
}
}
void MobCAO::updateLight(u8 light_at_pos)
{
MobFeatures m = content_mob_features(m_content);
if (m.glow_light)
light_at_pos = m.glow_light;
if (m_shooting && m.attack_glow_light)
light_at_pos = m.attack_glow_light;
m_last_light = light_at_pos;
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
if (m_node != NULL) {
if (m_draw_type == MDT_MODEL) {
setMeshVerticesColor(((scene::IAnimatedMeshSceneNode*)m_node)->getMesh(), color);
}else if (m_draw_type == MDT_SPRITE) {
((scene::IBillboardSceneNode*)m_node)->setColor(color);
}else if (m_draw_type == MDT_EXTRUDED) {
((ExtrudedSpriteSceneNode*)m_node)->updateLight(li);
}
}
}
v3s16 MobCAO::getLightPosition()
{
return floatToInt(m_position, BS);
}
void MobCAO::updateNodePos()
{
if (m_node == NULL)
return;
v3f offset = content_mob_features(m_content).model_offset+v3f(0,-0.5,0);
offset.X *= (float)BS;
offset.Y *= (float)BS;
offset.Z *= (float)BS;
offset += pos_translator.vect_show;
m_node->setPosition(offset-intToFloat(m_camera_offset, BS));
v3f rot = m_node->getRotation();
if (m_draw_type == MDT_MODEL) {
rot.Y = (90-pos_translator.yaw_show)+content_mob_features(m_content).model_rotation.Y;
}else if (m_draw_type == MDT_SPRITE) {
rot.Y = pos_translator.yaw_show+content_mob_features(m_content).model_rotation.Y;
}else if (m_draw_type == MDT_EXTRUDED) {
rot.Y = (180-pos_translator.yaw_show)+content_mob_features(m_content).model_rotation.Y;
}
m_node->setRotation(rot);
}
void MobCAO::step(float dtime, ClientEnvironment *env)
{
if (!m_node)
return;
MobFeatures m = content_mob_features(m_content);
pos_translator.translate(dtime);
updateNodePos();
/* Damage local player */
if (m.attack_player_damage && m_player_hit_timer <= 0.0) {
LocalPlayer *player = env->getLocalPlayer();
assert(player);
v3f playerpos = player->getPosition();
if (
fabs(m_position.X - playerpos.X) < m.attack_player_range.X*BS
&& (
fabs(m_position.Y - playerpos.Y) < m.attack_player_range.Y*BS
|| (
m_position.Y > playerpos.Y
&& fabs(m_position.Y-(playerpos.Y+BS)) < m.attack_player_range.Y*BS
)
) && fabs(m_position.Z - playerpos.Z) < m.attack_player_range.Z*BS
) {
env->damageLocalPlayer(PLAYER_TORSO,DAMAGE_ATTACK,m.attack_player_damage);
m_player_hit_timer = 3.0;
}
}
/* Run timers */
m_player_hit_timer -= dtime;
if (m_damage_visual_timer >= 0)
m_damage_visual_timer -= dtime;
m_walking_unset_timer += dtime;
if (m_walking_unset_timer >= 1.0) {
m_walking = false;
setAnimation(MA_STAND);
}
m_shooting_unset_timer -= dtime;
if (m_shooting_unset_timer <= 0.0 && m_shooting) {
if (m.attack_glow_light) {
u8 li = decode_light(m_last_light);
video::SColor color(255,li,li,li);
if (m_draw_type == MDT_MODEL) {
setMeshVerticesColor(((scene::IAnimatedMeshSceneNode*)m_node)->getMesh(), color);
}else if (m_draw_type == MDT_SPRITE) {
((scene::IBillboardSceneNode*)m_node)->setColor(color);
}
}
m_shooting = false;
if (m_walking) {
setAnimation(MA_MOVE);
}else{
setAnimation(MA_STAND);
}
}
if (!m.moves_silently && m_walking && m_draw_type == MDT_MODEL) {
m_last_step += dtime;
/* roughly sort of when a step sound should probably be heard, maybe */
if (m_last_step > 0.5) {
m_last_step -= 0.5;
sound_play_step(&env->getMap(),m_position,m_next_foot, 0.3);
m_next_foot = !m_next_foot;
}
}
}
void MobCAO::processMessage(const std::string &data)
{
//infostream<<"MobCAO: Got message"<<std::endl;
std::istringstream is(data, std::ios::binary);
// command
u8 cmd = readU8(is);
// Move
if (cmd == 0) {
// pos
m_position = readV3F1000(is);
// yaw
m_yaw = readF1000(is);
pos_translator.update(m_position,m_yaw);
if (!m_walking) {
m_walking = true;
m_walking_unset_timer = 0;
setAnimation(MA_MOVE);
}
updateNodePos();
}
// Trigger shooting
else if (cmd == 2) {
// length
m_shooting_unset_timer = readF1000(is);
if (content_mob_features(m_content).attack_glow_light){
u8 li = decode_light(content_mob_features(m_content).attack_glow_light);
video::SColor color(255,li,li,li);
if (m_node != NULL) {
if (m_draw_type == MDT_MODEL) {
setMeshVerticesColor(((scene::IAnimatedMeshSceneNode*)m_node)->getMesh(), color);
}else if (m_draw_type == MDT_SPRITE) {
((scene::IBillboardSceneNode*)m_node)->setColor(color);
}else if (m_draw_type == MDT_EXTRUDED) {
((ExtrudedSpriteSceneNode*)m_node)->updateLight(li);
}
}
}
if (!m_shooting) {
m_shooting = true;
setAnimation(MA_ATTACK);
}
}
}
void MobCAO::initialize(const std::string &data)
{
{
std::istringstream is(data, std::ios::binary);
// version
u8 version = readU8(is);
// check version
if (version < 0 || version > 1)
return;
// pos
m_position = readV3F1000(is);
// content
m_content = readU16(is);
m_draw_type = content_mob_features(m_content).texture_display;
// yaw
m_yaw = readF1000(is);
pos_translator.init(m_position,m_yaw);
if (version == 0) {
// client doesn't use these, but has to read past them
// speed
readV3F1000(is);
// age
readF1000(is);
// hp
readU8(is);
}
// shooting
m_shooting = !!readU8(is);
}
updateNodePos();
}
bool MobCAO::directReportPunch(content_t punch_item, v3f dir)
{
MobFeatures m = content_mob_features(m_content);
if (m.punch_action == MPA_IGNORE)
return false;
ToolItemFeatures f = content_toolitem_features(punch_item);
if (m.special_dropped_item != CONTENT_IGNORE && (m.special_punch_item == TT_NONE || f.type == m.special_punch_item))
return false;
video::SColor color(255,255,0,0);
if (m_node != NULL) {
if (m_draw_type == MDT_MODEL) {
setMeshVerticesColor(((scene::IAnimatedMeshSceneNode*)m_node)->getMesh(), color);
}else if (m_draw_type == MDT_SPRITE) {
((scene::IBillboardSceneNode*)m_node)->setColor(color);
}
}
m_damage_visual_timer = 0.05;
m_position += dir * BS;
pos_translator.sharpen();
pos_translator.update(m_position,m_yaw);
updateNodePos();
return false;
}
void MobCAO::setAnimation(MobAnimation anim)
{
if (m_draw_type != MDT_MODEL)
return;
int s;
int e;
content_mob_features(m_content).getAnimationFrames(anim,&s,&e);
((scene::IAnimatedMeshSceneNode*)m_node)->setFrameLoop(s,e);
}