Shooting a bow kinda works.

The arrow is released, but sometimes hits wrong blocks or disappears completely.
master
madmaxoft 2013-08-30 14:24:03 +02:00
parent 6677a5e8ca
commit 17ad4c2610
10 changed files with 221 additions and 15 deletions

View File

@ -2239,6 +2239,10 @@
RelativePath="..\source\items\ItemBed.h"
>
</File>
<File
RelativePath="..\source\Items\ItemBow.h"
>
</File>
<File
RelativePath="..\source\Items\ItemBrewingStand.h"
>

View File

@ -367,7 +367,9 @@ enum ENUM_ITEM_ID
// Keep these two as the last values of the disc list, without a number - they will get their correct number assigned automagically by C++
// IsValidItem() depends on this!
E_ITEM_LAST_DISC_PLUS_ONE, ///< Useless, really, but needs to be present for the following value
E_ITEM_LAST_DISC = E_ITEM_LAST_DISC_PLUS_ONE - 1 ///< Maximum disc itemtype number used
E_ITEM_LAST_DISC = E_ITEM_LAST_DISC_PLUS_ONE - 1, ///< Maximum disc itemtype number used
E_ITEM_LAST = E_ITEM_LAST_DISC, ///< Maximum valid ItemType
};

View File

@ -576,8 +576,8 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
// A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
return;
}
ItemHandler->OnItemShoot(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
}
LOGINFO("%s: Status SHOOT not implemented", __FUNCTION__);
return;
}
@ -790,16 +790,16 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, c
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
cBlockHandler * Handler = cBlockHandler::GetBlockHandler(BlockType);
cBlockHandler * BlockHandler = cBlockHandler::GetBlockHandler(BlockType);
if (Handler->IsUseable() && !m_Player->IsCrouched())
if (BlockHandler->IsUseable() && !m_Player->IsCrouched())
{
if (PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
{
// A plugin doesn't agree with using the block, abort
return;
}
Handler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
BlockHandler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
return;
}

View File

@ -64,6 +64,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_IsSwimming(false)
, m_IsSubmerged(false)
, m_EatingFinishTick(-1)
, m_IsChargingBow(false)
, m_BowCharge(0)
{
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
@ -213,6 +215,13 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
// Handle air drowning stuff
HandleAir();
// Handle charging the bow:
if (m_IsChargingBow)
{
m_BowCharge += 1;
LOGD("Player \"%s\" charging bow: %d", m_PlayerName.c_str(), m_BowCharge);
}
if (m_bDirtyPosition)
{
@ -253,6 +262,41 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
void cPlayer::StartChargingBow(void)
{
LOGD("Player \"%s\" started charging their bow", m_PlayerName.c_str());
m_IsChargingBow = true;
m_BowCharge = 0;
}
int cPlayer::FinishChargingBow(void)
{
LOGD("Player \"%s\" finished charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge);
int res = m_BowCharge;
m_IsChargingBow = false;
m_BowCharge = 0;
return res;
}
void cPlayer::CancelChargingBow(void)
{
LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge);
m_IsChargingBow = false;
m_BowCharge = 0;
}
void cPlayer::SetTouchGround(bool a_bTouchGround)
{
// If just

View File

@ -62,6 +62,18 @@ public:
/// Returns the currently equipped boots; empty item if none
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
/// Starts charging the equipped bow
void StartChargingBow(void);
/// Finishes charging the current bow. Returns the number of ticks for which the bow has been charged
int FinishChargingBow(void);
/// Cancels the current bow charging
void CancelChargingBow(void);
/// Returns true if the player is currently charging the bow
bool IsChargingBox(void) const { return m_IsChargingBow; }
void SetTouchGround( bool a_bTouchGround );
inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; }
@ -351,6 +363,9 @@ protected:
/// The world tick in which eating will be finished. -1 if not eating
Int64 m_EatingFinishTick;
bool m_IsChargingBow;
int m_BowCharge;
virtual void Destroyed(void);

View File

@ -229,6 +229,47 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a
cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
super(pkArrow, &a_Player, PosFromPlayerPos(a_Player), SpeedFromPlayerLook(a_Player, a_Force), 0.5, 0.5),
m_PickupState(psInSurvivalOrCreative),
m_DamageCoeff(2)
{
}
Vector3d cArrowEntity::PosFromPlayerPos(const cPlayer & a_Player)
{
Vector3d res = a_Player.GetEyePosition();
// Adjust the position to be just outside the player's bounding box:
res.x += 0.16 * cos(a_Player.GetPitch());
res.y += -0.1;
res.z += 0.16 * sin(a_Player.GetPitch());
return res;
}
Vector3d cArrowEntity::SpeedFromPlayerLook(const cPlayer & a_Player, double a_Force)
{
Vector3d res = a_Player.GetLookVector();
res.Normalize();
// TODO: Add a slight random change (+-0.0075 in each direction)
return res * a_Force * 1.5 * 20;
}
bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
{
switch (m_PickupState)

View File

@ -103,8 +103,17 @@ public:
/// Creates a new arrow with psNoPickup state and default damage modifier coeff
cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d a_Speed);
/// Creates a new arrow as shot by a player, initializes it from the player object
cArrowEntity(cPlayer & a_Player, double a_Force);
// tolua_begin
/// Returns the initial arrow position, as defined by the player eye position + adjustment.
static Vector3d PosFromPlayerPos(const cPlayer & a_Player);
/// Returns the initial arrow speed, as defined by the player look vector and the force coefficient
static Vector3d SpeedFromPlayerLook(const cPlayer & a_Player, double a_Force);
/// Returns whether the arrow can be picked up by players
ePickupState GetPickupState(void) const { return m_PickupState; }

80
source/Items/ItemBow.h Normal file
View File

@ -0,0 +1,80 @@
// ItemBow.h
// Declares the cItemBowHandler class representing the itemhandler for bows
#pragma once
#include "../Entities/ProjectileEntity.h"
class cItemBowHandler :
public cItemHandler
{
typedef cItemHandler super;
public:
cItemBowHandler(void) :
super(E_ITEM_BOW)
{
}
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
{
ASSERT(a_Player != NULL);
// Check if the player has an arrow in the inventory, or is in Creative:
if (!(a_Player->IsGameModeCreative() || a_Player->GetInventory().HasItems(cItem(E_ITEM_ARROW))))
{
return false;
}
a_Player->StartChargingBow();
return true;
}
virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override
{
// Actual shot - produce the arrow with speed based on the ticks that the bow was charged
ASSERT(a_Player != NULL);
int BowCharge = a_Player->FinishChargingBow();
double Force = (double)BowCharge / 20;
Force = (Force * Force + 2 * Force) / 3; // This formula is used by the 1.6.2 client
if (Force < 0.1)
{
// Too little force, ignore the shot
return;
}
if (Force > 1)
{
Force = 1;
}
// Create the arrow entity:
cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2);
if (Arrow == NULL)
{
return;
}
if (!Arrow->Initialize(a_Player->GetWorld()))
{
delete Arrow;
return;
}
a_Player->GetWorld()->BroadcastSpawnEntity(*Arrow);
}
} ;

View File

@ -8,6 +8,7 @@
// Handlers:
#include "ItemBed.h"
#include "ItemBow.h"
#include "ItemBrewingStand.h"
#include "ItemBucket.h"
#include "ItemCauldron.h"
@ -47,18 +48,24 @@ cItemHandler * cItemHandler::m_ItemHandler[2268];
cItemHandler *cItemHandler::GetItemHandler(int a_ItemType)
cItemHandler * cItemHandler::GetItemHandler(int a_ItemType)
{
if(a_ItemType < 0) a_ItemType = 0;
if (a_ItemType < 0)
{
ASSERT(!"Bad item type");
a_ItemType = 0;
}
if(!m_HandlerInitialized)
{ //We have to initialize
if (!m_HandlerInitialized)
{
// We need to initialize
memset(m_ItemHandler, 0, sizeof(m_ItemHandler));
m_HandlerInitialized = true;
}
if(m_ItemHandler[a_ItemType])
return m_ItemHandler[a_ItemType];
m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType);
if (m_ItemHandler[a_ItemType] == NULL)
{
m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType);
}
return m_ItemHandler[a_ItemType];
}
@ -77,6 +84,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType);
case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType);
case E_ITEM_BED: return new cItemBedHandler(a_ItemType);
case E_ITEM_BOW: return new cItemBowHandler;
case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);

View File

@ -21,8 +21,11 @@ class cItemHandler
public:
cItemHandler(int a_ItemType);
/// Called when the player tries to use the item. Return false to make the item unusable. DEFAULT: False
virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); //eg for fishing or hoes
/// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir);
/// Called when the client sends the SHOOT status in the lclk packet
virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) {}
/// Called while the player diggs a block using this item
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace);
@ -88,7 +91,7 @@ protected:
int m_ItemType;
static cItemHandler *CreateItemHandler(int m_ItemType);
static cItemHandler *m_ItemHandler[2268];
static cItemHandler * m_ItemHandler[E_ITEM_LAST + 1];
static bool m_HandlerInitialized; //used to detect if the itemhandlers are initialized
};