Shooting a bow kinda works.
The arrow is released, but sometimes hits wrong blocks or disappears completely.master
parent
6677a5e8ca
commit
17ad4c2610
|
@ -2239,6 +2239,10 @@
|
|||
RelativePath="..\source\items\ItemBed.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\Items\ItemBow.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\Items\ItemBrewingStand.h"
|
||||
>
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue