Shooting a bow kinda works.
The arrow is released, but sometimes hits wrong blocks or disappears completely.
This commit is contained in:
parent
6677a5e8ca
commit
17ad4c2610
@ -2239,6 +2239,10 @@
|
|||||||
RelativePath="..\source\items\ItemBed.h"
|
RelativePath="..\source\items\ItemBed.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\Items\ItemBow.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\Items\ItemBrewingStand.h"
|
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++
|
// 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!
|
// 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_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)
|
// A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ItemHandler->OnItemShoot(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||||
}
|
}
|
||||||
LOGINFO("%s: Status SHOOT not implemented", __FUNCTION__);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,16 +790,16 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, c
|
|||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, 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))
|
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
|
// A plugin doesn't agree with using the block, abort
|
||||||
return;
|
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);
|
PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
|
|||||||
, m_IsSwimming(false)
|
, m_IsSwimming(false)
|
||||||
, m_IsSubmerged(false)
|
, m_IsSubmerged(false)
|
||||||
, m_EatingFinishTick(-1)
|
, m_EatingFinishTick(-1)
|
||||||
|
, m_IsChargingBow(false)
|
||||||
|
, m_BowCharge(0)
|
||||||
{
|
{
|
||||||
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
|
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
|
||||||
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
|
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
|
||||||
@ -214,6 +216,13 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
// Handle air drowning stuff
|
// Handle air drowning stuff
|
||||||
HandleAir();
|
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)
|
if (m_bDirtyPosition)
|
||||||
{
|
{
|
||||||
// Apply food exhaustion from movement:
|
// Apply food exhaustion from movement:
|
||||||
@ -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)
|
void cPlayer::SetTouchGround(bool a_bTouchGround)
|
||||||
{
|
{
|
||||||
// If just
|
// If just
|
||||||
|
@ -63,6 +63,18 @@ public:
|
|||||||
/// Returns the currently equipped boots; empty item if none
|
/// Returns the currently equipped boots; empty item if none
|
||||||
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
|
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 );
|
void SetTouchGround( bool a_bTouchGround );
|
||||||
inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; }
|
inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; }
|
||||||
double GetEyeHeight(void) const; // tolua_export
|
double GetEyeHeight(void) const; // tolua_export
|
||||||
@ -352,6 +364,9 @@ protected:
|
|||||||
/// The world tick in which eating will be finished. -1 if not eating
|
/// The world tick in which eating will be finished. -1 if not eating
|
||||||
Int64 m_EatingFinishTick;
|
Int64 m_EatingFinishTick;
|
||||||
|
|
||||||
|
bool m_IsChargingBow;
|
||||||
|
int m_BowCharge;
|
||||||
|
|
||||||
virtual void Destroyed(void);
|
virtual void Destroyed(void);
|
||||||
|
|
||||||
/// Filters out damage for creative mode
|
/// Filters out damage for creative mode
|
||||||
|
@ -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
|
bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
|
||||||
{
|
{
|
||||||
switch (m_PickupState)
|
switch (m_PickupState)
|
||||||
|
@ -103,8 +103,17 @@ public:
|
|||||||
/// Creates a new arrow with psNoPickup state and default damage modifier coeff
|
/// 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);
|
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
|
// 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
|
/// Returns whether the arrow can be picked up by players
|
||||||
ePickupState GetPickupState(void) const { return m_PickupState; }
|
ePickupState GetPickupState(void) const { return m_PickupState; }
|
||||||
|
|
||||||
|
80
source/Items/ItemBow.h
Normal file
80
source/Items/ItemBow.h
Normal 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);
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
// Handlers:
|
// Handlers:
|
||||||
#include "ItemBed.h"
|
#include "ItemBed.h"
|
||||||
|
#include "ItemBow.h"
|
||||||
#include "ItemBrewingStand.h"
|
#include "ItemBrewingStand.h"
|
||||||
#include "ItemBucket.h"
|
#include "ItemBucket.h"
|
||||||
#include "ItemCauldron.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)
|
if (!m_HandlerInitialized)
|
||||||
{ //We have to initialize
|
{
|
||||||
|
// We need to initialize
|
||||||
memset(m_ItemHandler, 0, sizeof(m_ItemHandler));
|
memset(m_ItemHandler, 0, sizeof(m_ItemHandler));
|
||||||
m_HandlerInitialized = true;
|
m_HandlerInitialized = true;
|
||||||
}
|
}
|
||||||
if(m_ItemHandler[a_ItemType])
|
if (m_ItemHandler[a_ItemType] == NULL)
|
||||||
return m_ItemHandler[a_ItemType];
|
{
|
||||||
m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType);
|
m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType);
|
||||||
|
}
|
||||||
return m_ItemHandler[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_SAPLING: return new cItemSaplingHandler(a_ItemType);
|
||||||
case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType);
|
case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType);
|
||||||
case E_ITEM_BED: return new cItemBedHandler(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_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
|
||||||
case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
|
case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
|
||||||
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
|
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
|
||||||
|
@ -21,8 +21,11 @@ class cItemHandler
|
|||||||
public:
|
public:
|
||||||
cItemHandler(int a_ItemType);
|
cItemHandler(int a_ItemType);
|
||||||
|
|
||||||
/// Called when the player tries to use the item. Return false to make the item unusable. DEFAULT: False
|
/// 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); //eg for fishing or hoes
|
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
|
/// 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);
|
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;
|
int m_ItemType;
|
||||||
static cItemHandler *CreateItemHandler(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
|
static bool m_HandlerInitialized; //used to detect if the itemhandlers are initialized
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user