make some creatures tameable

This commit is contained in:
darkrose 2014-10-14 23:56:10 +10:00
parent 566537ee0c
commit e3206c679c
15 changed files with 184 additions and 85 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -1536,7 +1536,7 @@ void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
{
if(connectedAndInitialized() == false){
if (connectedAndInitialized() == false) {
infostream<<"Client::clickActiveObject() "
"cancelled (not connected)"
<<std::endl;
@ -1544,33 +1544,26 @@ void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
}
Player *player = m_env.getLocalPlayer();
if(player == NULL)
if (player == NULL)
return;
ClientActiveObject *obj = m_env.getActiveObject(id);
if(obj){
if(button == 0){
ToolItem *titem = NULL;
std::string toolname = "";
if (obj) {
if (button == 0) {
content_t punch_item = CONTENT_IGNORE;
InventoryList *mlist = player->inventory.getList("main");
if(mlist != NULL)
{
if (mlist != NULL) {
InventoryItem *item = mlist->getItem(item_i);
if(item && (std::string)item->getName() == "ToolItem")
{
titem = (ToolItem*)item;
toolname = titem->getToolName();
}
if (item)
punch_item = item->getContent();
}
v3f playerpos = player->getPosition();
v3f objpos = obj->getPosition();
v3f dir = (objpos - playerpos).normalize();
bool disable_send = obj->directReportPunch(toolname, dir);
if(disable_send)
if (obj->directReportPunch(punch_item, dir))
return;
}
}

View File

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "activeobject.h"
#include "mapnode.h"
/*
@ -72,7 +73,7 @@ public:
static ClientActiveObject* create(u8 type);
// If returns true, punch will not be sent to the server
virtual bool directReportPunch(const std::string &toolname, v3f dir)
virtual bool directReportPunch(content_t punch_item, v3f dir)
{ return false; }
protected:

View File

@ -509,10 +509,16 @@ void MobCAO::initialize(const std::string &data)
updateNodePos();
}
bool MobCAO::directReportPunch(const std::string &toolname, v3f dir)
bool MobCAO::directReportPunch(content_t punch_item, v3f dir)
{
if (content_mob_features(m_content).punch_action == MPA_IGNORE)
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) {

View File

@ -207,7 +207,7 @@ public:
//bool doShowSelectionBox(){return false;}
// If returns true, punch will not be sent to the server
bool directReportPunch(const std::string &toolname, v3f dir);
bool directReportPunch(content_t punch_item, v3f dir);
private:
void setAnimation(MobAnimation anim);
aabb3f m_selection_box;

View File

@ -333,6 +333,7 @@ void content_mob_init()
f->setAnimationFrames(MA_MOVE,0,60);
f->setAnimationFrames(MA_ATTACK,0,60);
f->punch_action = MPA_HARM;
f->tamed_mob = CONTENT_MOB_TAMESTAG;
f->dropped_item = std::string("CraftItem2 ")+itos(CONTENT_CRAFTITEM_MEAT)+" 2";
f->motion = MM_WANDER;
f->motion_type = MMT_WALK;
@ -350,6 +351,27 @@ void content_mob_init()
f->lifetime = 900.0;
f->setCollisionBox(aabb3f(-0.7*BS, 0., -0.7*BS, 0.7*BS, 1.5*BS, 0.7*BS));
i = CONTENT_MOB_TAMESTAG;
f = &g_content_mob_features[i];
f->content = i;
f->level = MOB_PASSIVE;
f->hp = 40;
f->model = "stag.b3d";
f->model_scale = v3f(1,1,1);
f->model_rotation = v3f(0,-90,0);
f->model_offset = v3f(0,1.1,0);
f->setTexture("mob_tamestag.png");
f->setAnimationFrames(MA_STAND,61,120);
f->setAnimationFrames(MA_MOVE,0,60);
f->setAnimationFrames(MA_ATTACK,0,60);
f->punch_action = MPA_HARM;
f->dropped_item = std::string("CraftItem2 ")+itos(CONTENT_CRAFTITEM_FUR)+" 2";
f->motion = MM_SEEKER;
f->motion_type = MMT_WALK;
f->notices_player = true;
f->lifetime = 900.0;
f->setCollisionBox(aabb3f(-0.7*BS, 0., -0.7*BS, 0.7*BS, 1.5*BS, 0.7*BS));
i = CONTENT_MOB_FISH;
f = &g_content_mob_features[i];
f->content = i;
@ -414,6 +436,7 @@ void content_mob_init()
f->setAnimationFrames(MA_MOVE,61,120);
f->setAnimationFrames(MA_ATTACK,61,120);
f->punch_action = MPA_HARM;
f->tamed_mob = CONTENT_MOB_TAMEWOLF;
f->motion = MM_SEEKER;
f->motion_type = MMT_WALK;
f->spawn_on = CONTENT_WILDGRASS_LONG;
@ -428,6 +451,27 @@ void content_mob_init()
f->lifetime = 900.0;
f->setCollisionBox(aabb3f(-0.5*BS, 0., -0.5*BS, 0.5*BS, 1.*BS, 0.5*BS));
i = CONTENT_MOB_TAMEWOLF;
f = &g_content_mob_features[i];
f->content = i;
f->level = MOB_PASSIVE;
f->hp = 40;
f->model = "wolf.b3d";
f->model_scale = v3f(1,1,1);
f->model_rotation = v3f(0,-90,0);
f->model_offset = v3f(0,0.5,0);
f->setTexture("mob_tamewolf.png");
f->setAnimationFrames(MA_STAND,1,60);
f->setAnimationFrames(MA_MOVE,61,120);
f->setAnimationFrames(MA_ATTACK,61,120);
f->punch_action = MPA_HARM;
f->dropped_item = std::string("CraftItem2 ")+itos(CONTENT_CRAFTITEM_FUR)+" 2";
f->motion = MM_SEEKER;
f->motion_type = MMT_WALK;
f->notices_player = true;
f->lifetime = 900.0;
f->setCollisionBox(aabb3f(-0.5*BS, 0., -0.5*BS, 0.5*BS, 1.*BS, 0.5*BS));
i = CONTENT_MOB_SHEEP;
f = &g_content_mob_features[i];
f->content = i;
@ -444,7 +488,9 @@ void content_mob_init()
f->punch_action = MPA_HARM;
f->dropped_item = std::string("CraftItem2 ")+itos(CONTENT_CRAFTITEM_MEAT)+" 2";
f->special_punch_item = TT_SHEAR;
f->special_dropped_item = std::string("CraftItem2 ")+itos(CONTENT_CRAFTITEM_STRING)+" 4";
f->special_dropped_item = CONTENT_CRAFTITEM_STRING;
f->special_dropped_count = 4;
f->special_dropped_max = 8;
f->motion = MM_SEEKER;
f->motion_type = MMT_WALK;
f->spawn_on = CONTENT_WILDGRASS_SHORT;

View File

@ -105,7 +105,6 @@ struct MobFeatures {
MobMotion motion;
MobMotionType motion_type;
MobMotion angry_motion;
bool is_tamable;
content_t hunted_node;
content_t fleed_node;
bool notices_player;
@ -119,7 +118,9 @@ struct MobFeatures {
u16 hp;
std::string dropped_item;
ToolType special_punch_item;
std::string special_dropped_item;
content_t special_dropped_item;
u16 special_dropped_count;
u16 special_dropped_max;
f32 lifetime;
u16 contact_explosion_diameter;
@ -220,7 +221,6 @@ struct MobFeatures {
motion = MM_STATIC;
motion_type = MMT_WALK;
angry_motion = MM_STATIC;
is_tamable = false;
hunted_node = CONTENT_IGNORE;
fleed_node = CONTENT_IGNORE;
notices_player = false;
@ -234,7 +234,9 @@ struct MobFeatures {
hp = 20;
dropped_item = "";
special_punch_item = TT_NONE;
special_dropped_item = "";
special_dropped_item = CONTENT_IGNORE;
special_dropped_count = 0;
special_dropped_max = 0;
lifetime = 0.0;
contact_explosion_diameter = 0;
spawn_on = CONTENT_IGNORE;
@ -281,10 +283,11 @@ void content_mob_init();
#define CONTENT_MOB_FIREBALL (CONTENT_MOB_MASK | 0x05)
#define CONTENT_MOB_DOE (CONTENT_MOB_MASK | 0x06)
#define CONTENT_MOB_STAG (CONTENT_MOB_MASK | 0x07)
#define CONTENT_MOB_FISH (CONTENT_MOB_MASK | 0x08)
#define CONTENT_MOB_SHARK (CONTENT_MOB_MASK | 0x09)
#define CONTENT_MOB_WOLF (CONTENT_MOB_MASK | 0x0A)
#define CONTENT_MOB_TAMEWOLF (CONTENT_MOB_MASK | 0x0B)
#define CONTENT_MOB_SHEEP (CONTENT_MOB_MASK | 0x0C)
#define CONTENT_MOB_TAMESTAG (CONTENT_MOB_MASK | 0x08)
#define CONTENT_MOB_FISH (CONTENT_MOB_MASK | 0x09)
#define CONTENT_MOB_SHARK (CONTENT_MOB_MASK | 0x0A)
#define CONTENT_MOB_WOLF (CONTENT_MOB_MASK | 0x0B)
#define CONTENT_MOB_TAMEWOLF (CONTENT_MOB_MASK | 0x0C)
#define CONTENT_MOB_SHEEP (CONTENT_MOB_MASK | 0x0D)
#endif

View File

@ -188,12 +188,12 @@ InventoryItem * ItemSAO::createInventoryItem()
}
}
void ItemSAO::rightClick(Player *player)
bool ItemSAO::rightClick(Player *player)
{
infostream<<__FUNCTION_NAME<<std::endl;
InventoryItem *item = createInventoryItem();
if(item == NULL)
return;
if (item == NULL)
return false;
bool to_be_deleted = item->use(m_env, player);
@ -204,6 +204,7 @@ void ItemSAO::rightClick(Player *player)
m_inventorystring = item->getItemString();
delete item;
return false;
}
static void get_random_u32_array(u32 a[], u32 len)
@ -246,6 +247,7 @@ MobSAO::MobSAO(ServerEnvironment *env, u16 id, v3f pos, content_t type):
m_age(0),
m_hp(10),
m_angry(false),
m_special_count(0),
m_disturb_timer(100000),
m_random_disturb_timer(0),
m_walk_around(false),
@ -256,8 +258,10 @@ MobSAO::MobSAO(ServerEnvironment *env, u16 id, v3f pos, content_t type):
m_shoot_y(0)
{
ServerActiveObject::registerType(getType(), create);
if ((type&CONTENT_MOB_MASK) == CONTENT_MOB_MASK)
if ((type&CONTENT_MOB_MASK) == CONTENT_MOB_MASK) {
m_hp = content_mob_features(type).hp;
m_special_count = content_mob_features(type).special_dropped_max;
}
}
MobSAO::MobSAO(ServerEnvironment *env, u16 id, v3f pos, v3f speed, content_t type):
ServerActiveObject(env, id, pos),
@ -273,6 +277,7 @@ MobSAO::MobSAO(ServerEnvironment *env, u16 id, v3f pos, v3f speed, content_t typ
m_age(0),
m_hp(10),
m_angry(false),
m_special_count(0),
m_disturb_timer(100000),
m_random_disturb_timer(0),
m_walk_around(false),
@ -283,8 +288,10 @@ MobSAO::MobSAO(ServerEnvironment *env, u16 id, v3f pos, v3f speed, content_t typ
m_shoot_y(0)
{
ServerActiveObject::registerType(getType(), create);
if ((type&CONTENT_MOB_MASK) == CONTENT_MOB_MASK)
if ((type&CONTENT_MOB_MASK) == CONTENT_MOB_MASK) {
m_hp = content_mob_features(type).hp;
m_special_count = content_mob_features(type).special_dropped_max;
}
}
MobSAO::~MobSAO()
{
@ -354,6 +361,9 @@ void MobSAO::step(float dtime, bool send_recommended)
return;
}
if (m.special_dropped_max > 0 && m_special_count < m.special_dropped_max && myrand_range(0,50) == 0)
m_special_count++;
m_random_disturb_timer += dtime;
if (m.notices_player) {
if (m_random_disturb_timer >= 5.0) {
@ -1115,10 +1125,21 @@ InventoryItem* MobSAO::createPickedUpItem(content_t punch_item)
ToolItemFeatures f = content_toolitem_features(punch_item);
if (m.punch_action != MPA_PICKUP) {
if (!m_removed) {
if (m.special_dropped_item != "" && (m.special_punch_item == TT_NONE || f.type == m.special_punch_item)) {
std::istringstream is(m.special_dropped_item, std::ios_base::binary);
InventoryItem *item = InventoryItem::deSerialize(is);
return item;
if (m.special_dropped_item != CONTENT_IGNORE && (m.special_punch_item == TT_NONE || f.type == m.special_punch_item)) {
if (m_special_count < m.special_dropped_count)
return NULL;
m_special_count -= m.special_dropped_count;
if (m_special_count < 0) {
m_special_count = 0;
return NULL;
}
if ((m.special_dropped_item&CONTENT_CRAFTITEM_MASK) == CONTENT_CRAFTITEM_MASK) {
return new CraftItem(m.special_dropped_item,m.special_dropped_count);
}else if ((m.special_dropped_item&CONTENT_TOOLITEM_MASK) == CONTENT_TOOLITEM_MASK) {
return new ToolItem(m.special_dropped_item,0);
}else{
return new MaterialItem(m.special_dropped_item,m.special_dropped_count);
}
}
return NULL;
}
@ -1142,6 +1163,9 @@ u16 MobSAO::punch(content_t punch_item, v3f dir, const std::string &playername)
<<" with a \""<<wide_to_narrow(f.description)<<"\" at "
<<PP(m_base_position/BS)<<std::endl;
if (m.special_dropped_item != CONTENT_IGNORE && (m.special_punch_item == TT_NONE || f.type == m.special_punch_item))
return 0;
if (m.punch_action == MPA_HARM) {
m_disturb_timer = 0;
m_disturbing_player = playername;
@ -1178,6 +1202,56 @@ u16 MobSAO::punch(content_t punch_item, v3f dir, const std::string &playername)
return 655;
}
bool MobSAO::rightClick(Player *player)
{
// so get the player
if (!player)
return false;
// see if mob is tamable
MobFeatures m = content_mob_features(m_content);
if (m.tamed_mob == CONTENT_IGNORE)
return false;
// get the wielded item
u16 item_i = player->getSelectedItem();
InventoryList *ilist = player->inventory.getList("main");
if (ilist == NULL)
return false;
InventoryItem *item = ilist->getItem(item_i);
if (!item)
return false;
// check if it's a craft item
content_t c = item->getContent();
if ((c&CONTENT_CRAFTITEM_MASK) != CONTENT_CRAFTITEM_MASK)
return false;
CraftItemFeatures f = content_craftitem_features(c);
if (f.content != c)
return false;
// and edible
if (!f.edible)
return false;
// feed the mob
// after this always return true as inventory has been modified
if (g_settings->getBool("infinite_inventory") == false && ilist) {
// Remove from inventory
if (item->getCount() == 1) {
ilist->deleteItem(item_i);
}else{
item->remove(1);
}
}
// tame it maybe
if (m.level < MOB_AGGRESSIVE || myrand_range(0,m.level*2) == 0)
return true;
// add new tamed mob
ServerActiveObject *obj = new MobSAO(m_env, 0, m_base_position, m.tamed_mob);
if (obj)
m_env->addActiveObject(obj);
// delete this one
m_removed = true;
return true;
}
u8 MobSAO::level()
{
return content_mob_features(m_content).level;

View File

@ -45,7 +45,7 @@ public:
std::string getStaticData();
InventoryItem* createInventoryItem();
InventoryItem* createPickedUpItem(content_t punch_item){return createInventoryItem();}
void rightClick(Player *player);
bool rightClick(Player *player);
private:
std::string m_inventorystring;
v3f m_speed_f;
@ -68,6 +68,7 @@ public:
void step(float dtime, bool send_recommended);
InventoryItem* createPickedUpItem(content_t punch_item);
u16 punch(content_t punch_item, v3f dir, const std::string &playername);
bool rightClick(Player *player);
u8 level();
private:
void sendPosition();
@ -106,6 +107,7 @@ private:
float m_age;
u8 m_hp;
bool m_angry;
u16 m_special_count;
float m_disturb_timer;
std::string m_disturbing_player;

View File

@ -3453,38 +3453,9 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
// The block in which the object resides in
v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
// If known by some client, don't immediately delete.
bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
// If block is active, don't remove
if (m_active_blocks.contains(blockpos_o)) {
if (obj->m_static_exists && blockpos_o != obj->m_static_block) {
std::string staticdata_new = obj->getStaticData();
StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
if (block) {
block->m_static_objects.remove(id);
obj->m_static_exists = false;
block->raiseModified(MOD_STATE_WRITE_NEEDED);
}
block = m_map->emergeBlock(blockpos_o);
if (block) {
if (block->m_static_objects.m_stored.size() < 50) {
u16 new_id = pending_delete ? id : 0;
block->m_static_objects.insert(new_id, s_obj);
block->raiseModified(MOD_STATE_WRITE_NEEDED);
obj->m_static_exists = true;
obj->m_static_block = block->getPos();
}else{
obj->m_removed = true;
}
}
}
if (m_active_blocks.contains(blockpos_o))
continue;
}
verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
<<"deactivating object id="<<id<<" on inactive block "
@ -3533,6 +3504,9 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete)
}
}
// If known by some client, don't immediately delete.
bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
// Add to the block where the object is located in
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
// Get or generate the block

View File

@ -19,11 +19,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifdef NDEBUG
#ifdef _WIN32
#pragma message ("Disabling unit tests")
#else
#warning "Disabling unit tests"
#endif
// Disable unit tests
#define ENABLE_TESTS 0
#else

View File

@ -126,6 +126,7 @@ public:
return list->getItem(m_selected_item);
return NULL;
}
virtual u16 getSelectedItem() {return m_selected_item;}
const char * getName()
{

View File

@ -1322,7 +1322,7 @@ void Server::AsyncRunStep()
for (core::map<u16, RemoteClient*>::Iterator i = m_clients.getIterator(); i.atEnd() == false; i++) {
RemoteClient *client = i.getNode()->getValue();
Player *player = m_env.getPlayer(client->peer_id);
if (player==NULL) {
if (player == NULL) {
// This can happen if the client timeouts somehow
continue;
}
@ -2351,8 +2351,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
}
// Right click, do something with object
if(button == 1)
{
if (button == 1) {
actionstream<<player->getName()<<" right clicks object "
<<obj->getId()<<std::endl;
@ -2361,8 +2360,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
u16 oldair = player->air;
u16 oldhunger = player->hunger;
// Do stuff
obj->rightClick(player);
// Do stuff - resend inventory if returns true
if (obj->rightClick(player)) {
UpdateCrafting(peer_id);
SendInventory(peer_id);
}
// Send back stuff
if (player->hp != oldhp || player->air != oldair || player->hunger != oldhunger)
@ -3898,7 +3900,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
InventoryList *ilist = player->inventory.getList("main");
if(g_settings->getBool("infinite_inventory") == false && ilist) {
// Remove from inventory and send inventory
if(mitem->getCount() == 1)
if (mitem->getCount() == 1)
ilist->deleteItem(item_i);
else
mitem->remove(1);

View File

@ -31,9 +31,10 @@
#include "mapnode.h"
#include "utility.h"
#define MOB_PASSIVE 0
#define MOB_AGGRESSIVE 1
#define MOB_DESTRUCTIVE 2
#define MOB_NONE 0
#define MOB_PASSIVE 1
#define MOB_AGGRESSIVE 2
#define MOB_DESTRUCTIVE 3
/*
@ -118,8 +119,9 @@ public:
virtual u16 punch(content_t punch_item, v3f dir, const std::string &playername) {return 0;}
/*
return true if inventory is modified
*/
virtual void rightClick(Player *player){}
virtual bool rightClick(Player *player) {return false;}
virtual u8 level(){return MOB_PASSIVE;}