add support for throwing objects, add snowball mob

This commit is contained in:
darkrose 2014-11-22 01:31:18 +10:00
parent 0523c7c905
commit 0460fa439b
10 changed files with 382 additions and 230 deletions

View File

@ -1591,6 +1591,39 @@ void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
} }
} }
void Client::throwItem(v3f dir, u16 item)
{
std::ostringstream os(std::ios_base::binary);
u8 buf[15];
LocalPlayer* player = m_env.getLocalPlayer();
// Write command
writeU16(buf, TOSERVER_THROWITEM);
os.write((char*)buf, 2);
// Write position
v3f pf = player->getEyePosition();
v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
writeV3S32(buf,position);
os.write((char*)buf, 12);
// Write speed/direction
v3s32 dir_i(dir.X*100, dir.Y*100, dir.Z*100);
writeV3S32(buf,dir_i);
os.write((char*)buf, 12);
// Write item
writeU16(buf, item);
os.write((char*)buf, 2);
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
Send(0, data, true);
}
void Client::clickActiveObject(u8 button, u16 id, u16 item_i) void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
{ {
if (connectedAndInitialized() == false) { if (connectedAndInitialized() == false) {

View File

@ -207,6 +207,7 @@ public:
void groundAction(u8 action, v3s16 nodepos_undersurface, void groundAction(u8 action, v3s16 nodepos_undersurface,
v3s16 nodepos_oversurface, u16 item); v3s16 nodepos_oversurface, u16 item);
void throwItem(v3f dir, u16 item);
void clickActiveObject(u8 button, u16 id, u16 item_i); void clickActiveObject(u8 button, u16 id, u16 item_i);
void sendNodemetaFields(v3s16 p, const std::string &formname, void sendNodemetaFields(v3s16 p, const std::string &formname,

View File

@ -251,6 +251,14 @@ enum ToServerCommand
[0] u16 TOSERVER_INIT2 [0] u16 TOSERVER_INIT2
*/ */
TOSERVER_THROWITEM = 0x12,
/*
[0] u16 command
[2] v3s32 position*100
[14] v3s32 speed*100
[26] u16 item
*/
TOSERVER_GETBLOCK=0x20, // Obsolete TOSERVER_GETBLOCK=0x20, // Obsolete
TOSERVER_ADDNODE = 0x21, // Obsolete TOSERVER_ADDNODE = 0x21, // Obsolete
TOSERVER_REMOVENODE = 0x22, // Obsolete TOSERVER_REMOVENODE = 0x22, // Obsolete

View File

@ -375,6 +375,7 @@ void content_craftitem_init()
f->texture = "snow_ball.png"; f->texture = "snow_ball.png";
f->name = "snow_ball"; f->name = "snow_ball";
f->description = wgettext("Snow Ball"); f->description = wgettext("Snow Ball");
f->thrown_item = CONTENT_MOB_SNOWBALL;
i = CONTENT_CRAFTITEM_STICK; i = CONTENT_CRAFTITEM_STICK;
f = &g_content_craftitem_features[i]; f = &g_content_craftitem_features[i];

View File

@ -44,6 +44,8 @@ struct CraftItemFeatures {
s16 drop_count; s16 drop_count;
// used by mobs that are picked up // used by mobs that are picked up
content_t drop_item; content_t drop_item;
// used by snowballs and such... things that are thrown
content_t thrown_item;
CraftItemFeatures(): CraftItemFeatures():
content(CONTENT_IGNORE), content(CONTENT_IGNORE),
@ -54,7 +56,8 @@ struct CraftItemFeatures {
fuel_time(0.0), fuel_time(0.0),
edible(0), edible(0),
drop_count(-1), drop_count(-1),
drop_item(CONTENT_IGNORE) drop_item(CONTENT_IGNORE),
thrown_item(CONTENT_IGNORE)
{} {}
}; };

View File

@ -513,4 +513,21 @@ void content_mob_init()
f->spawn_max_nearby_mobs = 3; f->spawn_max_nearby_mobs = 3;
f->lifetime = 900.0; f->lifetime = 900.0;
f->setCollisionBox(aabb3f(-0.4*BS, 0., -0.4*BS, 0.4*BS, 1.*BS, 0.4*BS)); f->setCollisionBox(aabb3f(-0.4*BS, 0., -0.4*BS, 0.4*BS, 1.*BS, 0.4*BS));
i = CONTENT_MOB_SNOWBALL;
f = &g_content_mob_features[i];
f->content = i;
f->level = MOB_AGGRESSIVE;
f->setTexture("snow_ball.png");
f->model_offset = v3f(0,0.2,0);
f->punch_action = MPA_IGNORE;
f->motion = MM_THROWN;
f->motion_type = MMT_FLY;
f->notices_player = true;
f->attack_player_damage = 1;
f->attack_player_range = v3f(1,1,1);
f->lifetime = 10.0;
f->contact_place_node = CONTENT_SNOW;
f->contact_drop_item = CONTENT_CRAFTITEM_SNOW_BALL;
f->setCollisionBox(aabb3f(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.));
} }

View File

@ -105,6 +105,7 @@ struct MobFeatures {
MobMotion motion; MobMotion motion;
MobMotionType motion_type; MobMotionType motion_type;
MobMotion angry_motion; MobMotion angry_motion;
f32 static_thrown_speed;
content_t hunted_node; content_t hunted_node;
content_t fleed_node; content_t fleed_node;
bool notices_player; bool notices_player;
@ -123,6 +124,8 @@ struct MobFeatures {
u16 special_dropped_max; u16 special_dropped_max;
f32 lifetime; f32 lifetime;
u16 contact_explosion_diameter; u16 contact_explosion_diameter;
content_t contact_place_node;
content_t contact_drop_item;
std::string sound_death; std::string sound_death;
std::string sound_attack; std::string sound_attack;
@ -225,6 +228,7 @@ struct MobFeatures {
motion = MM_STATIC; motion = MM_STATIC;
motion_type = MMT_WALK; motion_type = MMT_WALK;
angry_motion = MM_STATIC; angry_motion = MM_STATIC;
static_thrown_speed = 20.0;
hunted_node = CONTENT_IGNORE; hunted_node = CONTENT_IGNORE;
fleed_node = CONTENT_IGNORE; fleed_node = CONTENT_IGNORE;
notices_player = false; notices_player = false;
@ -243,6 +247,8 @@ struct MobFeatures {
special_dropped_max = 0; special_dropped_max = 0;
lifetime = 0.0; lifetime = 0.0;
contact_explosion_diameter = 0; contact_explosion_diameter = 0;
contact_place_node = CONTENT_IGNORE;
contact_drop_item = CONTENT_IGNORE;
sound_death = ""; sound_death = "";
sound_attack = ""; sound_attack = "";
sound_punch = "mob-dig"; sound_punch = "mob-dig";
@ -300,5 +306,6 @@ void content_mob_init();
#define CONTENT_MOB_WOLF (CONTENT_MOB_MASK | 0x0B) #define CONTENT_MOB_WOLF (CONTENT_MOB_MASK | 0x0B)
#define CONTENT_MOB_TAMEWOLF (CONTENT_MOB_MASK | 0x0C) #define CONTENT_MOB_TAMEWOLF (CONTENT_MOB_MASK | 0x0C)
#define CONTENT_MOB_SHEEP (CONTENT_MOB_MASK | 0x0D) #define CONTENT_MOB_SHEEP (CONTENT_MOB_MASK | 0x0D)
#define CONTENT_MOB_SNOWBALL (CONTENT_MOB_MASK | 0x0E)
#endif #endif

View File

@ -1091,12 +1091,24 @@ void MobSAO::stepMotionThrown(float dtime)
{ {
MobFeatures m = content_mob_features(m_content); MobFeatures m = content_mob_features(m_content);
m_base_position += m_speed * dtime; m_base_position += m_speed * dtime;
m_base_position.Y -= 0.1*BS*dtime; m_speed.Y -= 10.0*BS*dtime;
v3s16 pos_i = floatToInt(m_base_position, BS); v3s16 pos_i = floatToInt(m_base_position, BS);
if (!checkFreePosition(pos_i)) { if (!checkFreePosition(pos_i)) {
if (m.contact_explosion_diameter > 0) if (m.contact_explosion_diameter > 0)
explodeSquare(pos_i, v3s16(m.contact_explosion_diameter,m.contact_explosion_diameter,m.contact_explosion_diameter)); explodeSquare(pos_i, v3s16(m.contact_explosion_diameter,m.contact_explosion_diameter,m.contact_explosion_diameter));
if (m.contact_place_node != CONTENT_IGNORE && checkFreeAndWalkablePosition(pos_i+v3s16(0,1,0))) {
v3s16 pos = pos_i+v3s16(0,1,0);
m_env->getMap().addNodeWithEvent(pos,MapNode(m.contact_place_node));
}else if (m.contact_drop_item != CONTENT_IGNORE) {
v3f pos = intToFloat(pos_i+v3s16(0,1,0),BS);
InventoryItem *i = InventoryItem::create(m.contact_drop_item,1);
if (i) {
ServerActiveObject *obj = i->createSAO(m_env,0,m_base_position);
if (obj)
m_env->addActiveObject(obj);
}
}
m_removed = true; m_removed = true;
return; return;
} }

View File

@ -1621,7 +1621,7 @@ void the_game(
{ {
// Read client events // Read client events
for (;;) { while (1) {
ClientEvent event = client.getClientEvent(); ClientEvent event = client.getClientEvent();
if (event.type == CE_NONE) { if (event.type == CE_NONE) {
break; break;
@ -1666,8 +1666,7 @@ void the_game(
//bool camera_offset_changed = (camera_offset != old_camera_offset); //bool camera_offset_changed = (camera_offset != old_camera_offset);
if (!disable_camera_update) { if (!disable_camera_update) {
client.updateCamera(camera_position, client.updateCamera(camera_position, camera_direction, camera_fov, camera_offset);
camera_direction, camera_fov, camera_offset);
client.updateCameraOffset(camera_offset); client.updateCameraOffset(camera_offset);
client.getEnv().updateObjectsCameraOffset(camera_offset); client.getEnv().updateObjectsCameraOffset(camera_offset);
update_particles_camera_offset(camera_offset); update_particles_camera_offset(camera_offset);
@ -1675,20 +1674,30 @@ void the_game(
clouds->updateCameraOffset(camera_offset); clouds->updateCameraOffset(camera_offset);
} }
bool left_punch = false;
bool left_punch_muted = false;
InventoryItem *wield = (InventoryItem*)client.getLocalPlayer()->getWieldItem();
if (
wield
&& (
content_craftitem_features(wield->getContent()).thrown_item != CONTENT_IGNORE
//|| (
//content_toolitem_features(wield->getContent()).thrown_item != CONTENT_IGNORE
//&& client.getLocalPlayer()->inventory.find(content_toolitem_features(wield->getContent()).thrown_item) > -1
//)
) && input->getLeftClicked()
) {
client.throwItem(camera_direction,g_selected_item);
}else{
/* /*
Calculate what block is the crosshair pointing to Calculate what block is the crosshair pointing to
*/ */
f32 d = 4; // max. distance f32 d = 4; // max. distance
core::line3d<f32> shootline(camera_position, core::line3d<f32> shootline(camera_position, camera_position + camera_direction * BS * (d+1));
camera_position + camera_direction * BS * (d+1));
ClientActiveObject *selected_active_object ClientActiveObject *selected_active_object = client.getSelectedActiveObject(d*BS, camera_position, shootline);
= client.getSelectedActiveObject
(d*BS, camera_position, shootline);
bool left_punch = false;
bool left_punch_muted = false;
if (selected_active_object != NULL) { if (selected_active_object != NULL) {
client.setPointedContent(selected_active_object->getContent()); client.setPointedContent(selected_active_object->getContent());
@ -1717,8 +1726,7 @@ void the_game(
infotext = narrow_to_wide(selected_active_object->infoText()); infotext = narrow_to_wide(selected_active_object->infoText());
if(input->getLeftState()) if (input->getLeftState()) {
{
bool do_punch = false; bool do_punch = false;
bool do_punch_damage = false; bool do_punch_damage = false;
if (object_hit_delay_timer <= 0.0){ if (object_hit_delay_timer <= 0.0){
@ -1734,20 +1742,13 @@ void the_game(
left_punch = true; left_punch = true;
} }
if (do_punch_damage) { if (do_punch_damage) {
client.clickActiveObject(0, client.clickActiveObject(0, selected_active_object->getId(), g_selected_item);
selected_active_object->getId(), g_selected_item);
} }
} }else if (input->getRightClicked()) {
else if(input->getRightClicked())
{
infostream<<"Right-clicked object"<<std::endl; infostream<<"Right-clicked object"<<std::endl;
client.clickActiveObject(1, client.clickActiveObject(1, selected_active_object->getId(), g_selected_item);
selected_active_object->getId(), g_selected_item);
} }
} }else{ // selected_object == NULL
else // selected_object == NULL
{
/* /*
Find out which node we are pointing at Find out which node we are pointing at
*/ */
@ -1917,6 +1918,7 @@ void the_game(
} }
} // selected_object == NULL } // selected_object == NULL
}
if (left_punch || (input->getLeftClicked() && !left_punch_muted)) if (left_punch || (input->getLeftClicked() && !left_punch_muted))
camera.setDigging(0); // left click animation camera.setDigging(0); // left click animation
@ -2026,8 +2028,7 @@ void the_game(
/* /*
Update gui stuff (0ms) Update gui stuff (0ms)
*/ */
const char program_name_and_version[] = const char program_name_and_version[] = "Voxelands " VERSION_STRING;
"Voxelands " VERSION_STRING;
if (show_debug) { if (show_debug) {
static float drawtime_avg = 0; static float drawtime_avg = 0;
drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05; drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;

View File

@ -44,6 +44,7 @@
#include "content_nodemeta.h" #include "content_nodemeta.h"
#include "mapblock.h" #include "mapblock.h"
#include "serverobject.h" #include "serverobject.h"
#include "content_sao.h"
#include "settings.h" #include "settings.h"
#include "profiler.h" #include "profiler.h"
#include "log.h" #include "log.h"
@ -2102,6 +2103,74 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return; return;
} }
switch (command) { switch (command) {
case TOSERVER_THROWITEM:
{
if (datasize < 2+12+12+2)
return;
v3s32 ps = readV3S32(&data[2]);
v3s32 ss = readV3S32(&data[2+12]);
u16 item_i = readU16(&data[2+12+12]);
InventoryList *ilist = player->inventory.getList("main");
if (ilist == NULL)
return;
// Get item
InventoryItem *item = ilist->getItem(item_i);
// If there is no item, it is not possible to throw it
if (item == NULL)
return;
content_t thrown = content_craftitem_features(item->getContent()).thrown_item;
// We can throw it, right?
if (thrown == CONTENT_IGNORE)
return;
if (g_settings->getBool("droppable_inventory") == false || (getPlayerPrivs(player) & PRIV_BUILD) == 0) {
infostream<<"Not allowing player to drop item: creative mode and no build privs"<<std::endl;
return;
}
v3f pf((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
v3f sf((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
ServerActiveObject *obj = new MobSAO(&m_env, 0, pf, sf*content_mob_features(thrown).static_thrown_speed*BS, thrown);
if (obj == NULL) {
infostream<<"WARNING: item resulted in NULL object, "
<<"not throwing into map"
<<std::endl;
}else{
actionstream<<player->getName()<<" throws "<<thrown<<" at "<<PP(pf/BS)<<" ("<<PP(sf/BS)")"<<std::endl;
// Add the object to the environment
m_env.addActiveObject(obj);
}
if (g_settings->getBool("infinite_inventory") == false) {
// Delete the right amount of items from the slot
// Delete item if all gone
if (item->getCount() <= 1) {
if (item->getCount() < 1)
infostream<<"WARNING: Server: dropped more items"
<<" than the slot contains"<<std::endl;
InventoryList *ilist = player->inventory.getList("main");
if (ilist)
// Remove from inventory and send inventory
ilist->deleteItem(item_i);
}else{
item->remove(1);
}
// Send inventory
UpdateCrafting(peer_id);
SendInventory(peer_id);
}
}
break;
case TOSERVER_PLAYERPOS: case TOSERVER_PLAYERPOS:
{ {
if (datasize < 2+12+12+4+4) if (datasize < 2+12+12+4+4)