1
0

Arrows deal damage.

Still needs some tweaks, they hit the shooter most of the time.
This commit is contained in:
madmaxoft 2013-09-01 22:40:35 +02:00
parent 4f04724cfd
commit a884fbb919
2 changed files with 127 additions and 4 deletions

View File

@ -8,6 +8,9 @@
#include "../ClientHandle.h"
#include "Player.h"
#include "../LineBlockTracer.h"
#include "../BoundingBox.h"
#include "../ChunkMap.h"
#include "../Chunk.h"
@ -63,6 +66,82 @@ protected:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProjectileEntityCollisionCallback:
class cProjectileEntityCollisionCallback :
public cEntityCallback
{
public:
cProjectileEntityCollisionCallback(cProjectileEntity * a_Projectile, const Vector3d & a_Pos, const Vector3d & a_NextPos) :
m_Projectile(a_Projectile),
m_Pos(a_Pos),
m_NextPos(a_NextPos),
m_MinCoeff(1),
m_HitEntity(NULL)
{
}
virtual bool Item(cEntity * a_Entity) override
{
if (a_Entity == m_Projectile)
{
// Self-colision
return false;
}
cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
// Instead of colliding the bounding box with another bounding box in motion, we collide an enlarged bounding box with a hairline.
// The results should be good enough for our purposes
double LineCoeff;
char Face;
EntBox.Expand(m_Projectile->GetWidth() / 2, m_Projectile->GetHeight() / 2, m_Projectile->GetWidth() / 2);
if (!EntBox.CalcLineIntersection(m_Pos, m_NextPos, LineCoeff, Face))
{
// No intersection whatsoever
return false;
}
// TODO: Some entities don't interact with the projectiles (pickups, falling blocks)
// TODO: Allow plugins to interfere about which entities can be hit
if (LineCoeff < m_MinCoeff)
{
// The entity is closer than anything we've stored so far, replace it as the potential victim
m_MinCoeff = LineCoeff;
m_HitEntity = a_Entity;
}
// Don't break the enumeration, we want all the entities
return false;
}
/// Returns the nearest entity that was hit, after the enumeration has been completed
cEntity * GetHitEntity(void) const { return m_HitEntity; }
/// Returns the line coeff where the hit was encountered, after the enumeration has been completed
double GetMinCoeff(void) const { return m_MinCoeff; }
/// Returns true if the callback has encountered a true hit
bool HasHit(void) const { return (m_MinCoeff < 1); }
protected:
cProjectileEntity * m_Projectile;
const Vector3d & m_Pos;
const Vector3d & m_NextPos;
double m_MinCoeff; // The coefficient of the nearest hit on the Pos line
// Although it's bad(tm) to store entity ptrs from a callback, we can afford it here, because the entire callback
// is processed inside the tick thread, so the entities won't be removed in between the calls and the final processing
cEntity * m_HitEntity; // The nearest hit entity
} ;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProjectileEntity:
@ -192,17 +271,39 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
// Trace the tick's worth of movement as a line:
Vector3d NextPos = Pos + PerTickSpeed;
cProjectileTracerCallback TracerCallback(this);
if (cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
{
// Nothing in the way, update the position
SetPosition(NextPos);
// Something has been hit, abort all other processing
return;
}
// Test for entity collisions:
cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos);
a_Chunk.ForEachEntity(EntityCollisionCallback);
if (EntityCollisionCallback.HasHit())
{
// An entity was hit:
// DEBUG:
Vector3d HitPos = Pos + (NextPos - Pos) * EntityCollisionCallback.GetMinCoeff();
LOGD("Projectile %d has hit an entity %d (%s) at {%.02f, %.02f, %.02f} (coeff %.03f)",
m_UniqueID,
EntityCollisionCallback.GetHitEntity()->GetUniqueID(),
EntityCollisionCallback.GetHitEntity()->GetClass(),
HitPos.x, HitPos.y, HitPos.z,
EntityCollisionCallback.GetMinCoeff()
);
OnHitEntity(*(EntityCollisionCallback.GetHitEntity()));
}
// TODO: Test the entities in the neighboring chunks, too
// Update the position:
SetPosition(NextPos);
// Add gravity effect to the vertical speed component:
SetSpeedY(GetSpeedY() + m_Gravity / 20);
// DEBUG:
LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}",
LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}",
m_UniqueID,
GetPosX(), GetPosY(), GetPosZ(),
GetSpeedX(), GetSpeedY(), GetSpeedZ()
@ -277,6 +378,24 @@ void cArrowEntity::SpawnOn(cClientHandle & a_Client)
void cArrowEntity::OnHitEntity(cEntity & a_EntityHit)
{
if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer())
{
// Not an entity that interacts with an arrow
return;
}
// TODO: The damage dealt should be based on arrow speed in addition to the damage coeff
a_EntityHit.TakeDamage(dtRangedAttack, this, (int)(2.5 * m_DamageCoeff), 1);
Destroy();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cThrownEggEntity:

View File

@ -50,6 +50,9 @@ public:
/// Called by the physics blocktracer when the entity hits a solid block, the block's coords and the face hit is given
virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace);
/// Called by the physics blocktracer when the entity hits another entity
virtual void OnHitEntity(cEntity & a_EntityHit) {}
// tolua_begin
/// Returns the kind of the projectile (fast class identification)
@ -140,6 +143,7 @@ protected:
// cProjectileEntity overrides:
virtual void SpawnOn(cClientHandle & a_Client) override;
virtual void OnHitEntity(cEntity & a_EntityHit) override;
// tolua_begin
} ;