Cuberite
A lightweight, fast and extensible game server for Minecraft
ArrowEntity.cpp
Go to the documentation of this file.
1 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2 
3 #include "Player.h"
4 #include "ArrowEntity.h"
5 #include "../Chunk.h"
6 #include "../Blocks/BlockButton.h"
7 
8 
9 
10 
11 
12 cArrowEntity::cArrowEntity(cEntity * a_Creator, Vector3d a_Pos, Vector3d a_Speed):
13  Super(pkArrow, a_Creator, a_Pos, a_Speed, 0.5f, 0.5f),
14  m_PickupState(psNoPickup),
15  m_DamageCoeff(2),
16  m_IsCritical(false),
17  m_Timer(0),
18  m_bIsCollected(false)
19 {
20  SetMass(0.1);
21  SetGravity(-20.0f);
22 
23  FLOGD("Created arrow {0} with speed {1:.02f} and rot {{{2:.02f}, {3:.02f}}}",
25  );
26 }
27 
28 
29 
30 
31 
32 cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
33  cArrowEntity(&a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20))
34 {
35  m_IsCritical = a_Force >= 1;
37 }
38 
39 
40 
41 
42 
43 bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
44 {
45  switch (m_PickupState)
46  {
47  case psNoPickup: return false;
48  case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
49  case psInCreative: return a_Player.IsGameModeCreative();
50  }
51  UNREACHABLE("Unsupported arrow pickup state");
52 }
53 
54 
55 
56 
57 
59 {
60  // Save the direction we're going in before Super resets it
61  auto Speed = GetSpeed();
62  Speed.Normalize();
63 
64  /*
65  The line tracer returns the arrow hit position located on the face of a block;
66  if the arrow hit a block at -5, 95, -5 then a_HitPos would start off as -4, 95.5, -4.1,
67  i.e. it collided with the X face.
68 
69  First we subtract a bit of speed vector so it doesn't appear black clientside.
70 
71  Then we add a bit of speed vector to make a_HitPos -4.0001, 95.5, -4.1
72  and floor to get exactly -5, 95, -5 which is stored in m_HitBlockPos.
73  */
74 
75  // Shift the arrow's position slightly back so that less than 50% of the hitbox
76  // is in the block. Otherwise the arrow can appear black
77  Super::OnHitSolidBlock(a_HitPos - (Speed / 100), a_HitFace);
78 
79  // Nudge into the block a tiny bit according to its direction of travel
80  // Floor to give the coordinates of the block it crashed into
81  m_HitBlockPos = (a_HitPos + (Speed / 100000)).Floor();
82 
83  // Broadcast arrow hit sound
84  m_World->BroadcastSoundEffect("entity.arrow.hit", m_HitBlockPos, 0.5f, static_cast<float>(0.75 + (static_cast<float>((GetUniqueID() * 23) % 32)) / 64));
85 
86  // Trigger any buttons that were hit
87  // Wooden buttons will be depressed by the arrow
89 
91  {
94  }
95 }
96 
97 
98 
99 
100 
101 void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, Vector3d a_HitPos)
102 {
103  Super::OnHitEntity(a_EntityHit, a_HitPos);
104 
105  int Damage = static_cast<int>(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
106  if (m_IsCritical)
107  {
108  Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
109  }
110 
112  if (PowerLevel > 0)
113  {
114  int ExtraDamage = static_cast<int>(ceil(0.25 * (PowerLevel + 1)));
115  Damage += ExtraDamage;
116  }
117 
118  double Knockback = 10;
119 
121  unsigned int PunchLevelMultiplier = 8;
122 
123  Knockback += PunchLevelMultiplier * PunchLevel;
124  a_EntityHit.TakeDamage(dtRangedAttack, GetCreatorUniqueID(), Damage, Knockback);
125 
126  if (IsOnFire() && !a_EntityHit.IsInWater())
127  {
128  a_EntityHit.StartBurning(100);
129  }
130 
131  // Broadcast successful hit sound
132  GetWorld()->BroadcastSoundEffect("entity.arrow.hit", GetPosition(), 0.5, static_cast<float>(0.75 + (static_cast<float>((GetUniqueID() * 23) % 32)) / 64));
133 
134  Destroy();
135 }
136 
137 
138 
139 
140 
142 {
143  if (m_IsInGround && !m_bIsCollected && CanPickup(a_Dest))
144  {
145  // Do not add the arrow to the inventory when the player is in creative:
146  if (!a_Dest.IsGameModeCreative())
147  {
148  int NumAdded = a_Dest.GetInventory().AddItem(cItem(E_ITEM_ARROW));
149  if (NumAdded == 0)
150  {
151  // No space in the inventory
152  return;
153  }
154  }
155 
156  GetWorld()->BroadcastCollectEntity(*this, a_Dest, 1);
157  GetWorld()->BroadcastSoundEffect("entity.item.pickup", GetPosition(), 0.3f, (1.2f + (static_cast<float>((GetUniqueID() * 23) % 32)) / 64));
158  m_bIsCollected = true;
159  }
160 }
161 
162 
163 
164 
165 
166 void cArrowEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
167 {
168  Super::Tick(a_Dt, a_Chunk);
169  if (!IsTicking())
170  {
171  // The base class tick destroyed us
172  return;
173  }
174  m_Timer += a_Dt;
175 
176  if (m_bIsCollected)
177  {
178  if (m_Timer > std::chrono::milliseconds(500))
179  {
180  Destroy();
181  return;
182  }
183  }
184  else if (m_Timer > std::chrono::minutes(5))
185  {
186  Destroy();
187  return;
188  }
189 
190  if (m_IsInGround)
191  {
192  if (m_World->GetBlock(m_HitBlockPos) == E_BLOCK_AIR) // Block attached to was destroyed?
193  {
194  m_IsInGround = false; // Yes, begin simulating physics again
195  }
196  }
197  else if (IsInWater()) // Arrow in water?
198  {
199  ApplyFriction(m_Speed, ARROW_WATER_FRICTION, static_cast<float>(a_Dt.count())); // Yes, slow down arrow
200  }
201 }
202 
203 
204 
205 
206 
208 {
209  return false;
210 }
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_TNT
Definition: BlockType.h:56
@ E_ITEM_ARROW
Definition: BlockType.h:306
@ dtRangedAttack
Definition: Defines.h:247
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc.
Definition: Defines.h:38
#define UNREACHABLE(x)
Definition: Globals.h:288
#define FLOGD
Definition: LoggerSimple.h:91
unsigned char PowerLevel
static void OnArrowHit(cWorld &a_World, const Vector3i a_Position, const eBlockFace a_HitFace)
Event handler for an arrow striking a block.
Definition: BlockButton.h:34
Definition: Chunk.h:36
unsigned int GetLevel(int a_EnchantmentID) const
Returns the level for the specified enchantment; 0 if not stored.
double m_DamageCoeff
The coefficient applied to the damage that the arrow will deal, based on the bow enchantment.
Definition: ArrowEntity.h:89
bool m_IsCritical
If true, the arrow deals more damage.
Definition: ArrowEntity.h:92
ePickupState m_PickupState
Determines when the arrow can be picked up by players.
Definition: ArrowEntity.h:86
virtual bool DoesPreventBlockPlacement(void) const override
Returns whether blocks can be placed intersecting this entities' hitbox.
cArrowEntity(cEntity *a_Creator, Vector3d a_Pos, Vector3d a_Speed)
Creates a new arrow with psNoPickup state and default damage modifier coeff.
Definition: ArrowEntity.cpp:12
std::chrono::milliseconds m_Timer
Timer for pickup collection animation or five minute timeout.
Definition: ArrowEntity.h:95
bool CanPickup(const cPlayer &a_Player) const
Returns true if the specified player can pick the arrow up.
Definition: ArrowEntity.cpp:43
bool m_bIsCollected
If true, the arrow is in the process of being collected - don't go to anyone else.
Definition: ArrowEntity.h:98
virtual void OnHitSolidBlock(Vector3d a_HitPos, eBlockFace a_HitFace) override
Called by the physics blocktracer when the entity hits a solid block, the hit position and the face h...
Definition: ArrowEntity.cpp:58
virtual void OnHitEntity(cEntity &a_EntityHit, Vector3d a_HitPos) override
Called by the physics blocktracer when the entity hits another entity.
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
@ psInSurvivalOrCreative
Definition: ArrowEntity.h:36
virtual void CollectedBy(cPlayer &a_Player) override
Called by Chunk when the projectile is eligible for player collection.
static constexpr float ARROW_WATER_FRICTION
Value used to calculate arrow speed in water.
Definition: ArrowEntity.h:42
Vector3i m_HitBlockPos
Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air.
Definition: ArrowEntity.h:101
Definition: Entity.h:76
const Vector3d & GetSpeed(void) const
Exported in ManualBindings.
Definition: Entity.h:300
virtual bool IsInWater(void) const
Returns true if any part of the entity is in a water block.
Definition: Entity.h:501
bool IsTicking(void) const
Returns true if the entity is valid and ticking.
Definition: Entity.cpp:2259
UInt32 m_UniqueID
The ID of the entity that is guaranteed to be unique within a single run of the server.
Definition: Entity.h:582
void SetGravity(float a_Gravity)
Definition: Entity.h:282
cWorld * m_World
Definition: Entity.h:624
UInt32 GetUniqueID(void) const
Definition: Entity.h:253
void Destroy()
Destroys the entity, schedules it for memory freeing and broadcasts the DestroyEntity packet.
Definition: Entity.cpp:243
double GetPitch(void) const
Definition: Entity.h:199
virtual bool IsOnFire(void) const
Definition: Entity.h:489
Vector3d m_Speed
Measured in meters / second (m / s)
Definition: Entity.h:577
void TakeDamage(cEntity &a_Attacker)
Makes this pawn take damage from an attack by a_Attacker.
Definition: Entity.cpp:272
void SetMass(double a_Mass)
Definition: Entity.cpp:2113
static void ApplyFriction(Vector3d &a_Speed, double a_SlowdownMultiplier, float a_Dt)
Applies friction to an entity.
Definition: Entity.cpp:1230
double GetYaw(void) const
Definition: Entity.h:198
const Vector3d & GetPosition(void) const
Exported in ManualBindings.
Definition: Entity.h:297
void StartBurning(int a_TicksLeftBurning)
Puts the entity on fire for the specified amount of ticks.
Definition: Entity.cpp:1908
cWorld * GetWorld(void) const
Definition: Entity.h:190
Definition: Player.h:29
bool IsGameModeSurvival(void) const
Returns true if the player is in Survival mode, either explicitly, or by inheriting from current worl...
Definition: Player.cpp:1034
bool IsGameModeCreative(void) const
Returns true if the player is in Creative mode, either explicitly, or by inheriting from current worl...
Definition: Player.cpp:1025
cInventory & GetInventory(void)
Definition: Player.h:156
UInt32 GetCreatorUniqueID(void) const
Returns the unique ID of the entity who created this projectile May return an ID <0.
virtual void OnHitSolidBlock(Vector3d a_HitPos, eBlockFace a_HitFace)
Called by the physics blocktracer when the entity hits a solid block, the hit position and the face h...
CreatorData m_CreatorData
The structure for containing the entity ID and name who has created this projectile The ID and / or n...
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
bool m_IsInGround
True if the projectile has hit the ground and is stuck there.
virtual void OnHitEntity(cEntity &a_EntityHit, Vector3d a_HitPos)
Called by the physics blocktracer when the entity hits another entity.
char AddItem(const cItem &a_ItemStack, bool a_AllowNewStacks=true)
Adds as many items out of a_ItemStack as can fit.
Definition: Inventory.cpp:106
Definition: Item.h:37
Vector3< int > Floor(void) const
Returns a new Vector3i with coords set to std::floor() of this vector's coords.
Definition: Vector3.h:177
double Length(void) const
Definition: Vector3.h:100
UInt32 SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec=80, double a_InitialVelocityCoeff=1, bool a_ShouldPlayFuseSound=true)
Definition: World.h:519
BLOCKTYPE GetBlock(Vector3i a_BlockPos) const
Returns the block type at the specified position.
Definition: World.h:363
virtual void BroadcastCollectEntity(const cEntity &a_Collected, const cEntity &a_Collector, unsigned a_Count, const cClientHandle *a_Exclude=nullptr) override
int GetTickRandomNumber(int a_Range)
Returns a random number in range [0 .
Definition: World.cpp:2978
virtual void BroadcastSoundEffect(const AString &a_SoundName, Vector3d a_Position, float a_Volume, float a_Pitch, const cClientHandle *a_Exclude=nullptr) override
void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
Definition: World.cpp:1743