From 33cc1f2a50d870b7d264ee5479068f8eee3aa458 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 22 Jun 2014 20:44:01 +0100 Subject: Fixed multiple issues with projectiles * Fixed arrows not being collectable/not truly hitting a block/not lodging into blocks/not going in far enough * Fixed projectiles not playing their block hit animation owning to being destroyed too quickly --- src/Entities/ArrowEntity.cpp | 33 +++++------------- src/Entities/ProjectileEntity.cpp | 61 ++++++++++++++++++--------------- src/Entities/ThrownEggEntity.cpp | 7 ++-- src/Entities/ThrownEggEntity.h | 18 ++++++++++ src/Entities/ThrownEnderPearlEntity.cpp | 9 ++--- src/Entities/ThrownEnderPearlEntity.h | 22 ++++++++++-- src/Entities/ThrownSnowballEntity.cpp | 7 ++-- src/Entities/ThrownSnowballEntity.h | 18 ++++++++++ 8 files changed, 112 insertions(+), 63 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 8d2569125..db9dc781a 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -68,25 +68,16 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { - if (a_HitFace == BLOCK_FACE_NONE) { return; } - - super::OnHitSolidBlock(a_HitPos, a_HitFace); - int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; - - switch (a_HitFace) - { - case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed - case BLOCK_FACE_YM: - { - break; - } - default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true); - } + Vector3d Hit = a_HitPos; + Hit += GetSpeed() / 700; // Make arrow sink into block a little + + super::OnHitSolidBlock(Hit, a_HitFace); + int X = (int)floor(Hit.x), Y = (int)floor(Hit.y), Z = (int)floor(Hit.z); - m_HitBlockPos = Vector3i(a_X, a_Y, a_Z); + m_HitBlockPos = Vector3i(X, Y, Z); // Broadcast arrow hit sound - m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + m_World->BroadcastSoundEffect("random.bowhit", X * 8, Y * 8, Z * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); } @@ -94,13 +85,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -{ - if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat()) - { - // Not an entity that interacts with an arrow - return; - } - +{ int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5); if (m_IsCritical) { @@ -165,7 +150,7 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) if (!m_HasTeleported) // Sent a teleport already, don't do again { - if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case + if (m_HitGroundTimer > 500.f) // Send after half a second, could be less, but just in case { m_World->BroadcastTeleportEntity(*this); m_HasTeleported = true; diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 95c494569..d45f1d212 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -67,16 +67,17 @@ protected: if (cBlockInfo::IsSolid(a_BlockType)) { - // The projectile hit a solid block - // Calculate the exact hit coords: - cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1); - Vector3d Line1 = m_Projectile->GetPosition(); - Vector3d Line2 = Line1 + m_Projectile->GetSpeed(); - double LineCoeff = 0; - eBlockFace Face; - if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face)) + // The projectile hit a solid block, calculate the exact hit coords: + cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1); // Bounding box of the block hit + const Vector3d LineStart = m_Projectile->GetPosition(); // Start point for the imaginary line that goes through the block hit + const Vector3d LineEnd = LineStart + m_Projectile->GetSpeed(); // End point for the imaginary line that goes through the block hit + double LineCoeff = 0; // Used to calculate where along the line an intersection with the bounding box occurs + eBlockFace Face; // Face hit + + if (bb.CalcLineIntersection(LineStart, LineEnd, LineCoeff, Face)) { - Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff; + Vector3d Intersection = LineStart + m_Projectile->GetSpeed() * LineCoeff; // Point where projectile goes into the hit block + if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile, a_BlockX, a_BlockY, a_BlockZ, Face, &Intersection)) { return false; @@ -161,7 +162,12 @@ public: return false; } - // TODO: Some entities don't interact with the projectiles (pickups, falling blocks) + if (!a_Entity->IsMob() && !a_Entity->IsMinecart() && !a_Entity->IsPlayer() && !a_Entity->IsBoat()) + { + // Not an entity that interacts with a projectile + return false; + } + if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, *a_Entity)) { // A plugin disagreed. @@ -316,8 +322,9 @@ AString cProjectileEntity::GetMCAClassName(void) const void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); - - if (GetProjectileKind() != pkArrow) // See cArrow::Tick + + // TODO: see BroadcastMovementUpdate; RelativeMove packet jerkiness affects projectiles too (cause of sympton described in cArrowEntity::Tick()) + if (GetProjectileKind() != pkArrow) { BroadcastMovementUpdate(); } @@ -335,19 +342,10 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) return; } - Vector3d PerTickSpeed = GetSpeed() / 20; - Vector3d Pos = GetPosition(); - - // 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)) - { - // Something has been hit, abort all other processing - return; - } - // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff - + const Vector3d PerTickSpeed = GetSpeed() / 20; + const Vector3d Pos = GetPosition(); + const Vector3d NextPos = Pos + PerTickSpeed; + // Test for entity collisions: cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos); a_Chunk.ForEachEntity(EntityCollisionCallback); @@ -363,11 +361,20 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) EntityCollisionCallback.GetHitEntity()->GetClass(), HitPos.x, HitPos.y, HitPos.z, EntityCollisionCallback.GetMinCoeff() - ); - + ); + OnHitEntity(*(EntityCollisionCallback.GetHitEntity()), HitPos); } // TODO: Test the entities in the neighboring chunks, too + + // Trace the tick's worth of movement as a line: + cProjectileTracerCallback TracerCallback(this); + if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos)) + { + // Something has been hit, abort all other processing + return; + } + // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff // Update the position: SetPosition(NextPos); diff --git a/src/Entities/ThrownEggEntity.cpp b/src/Entities/ThrownEggEntity.cpp index 224019091..d7eed41e3 100644 --- a/src/Entities/ThrownEggEntity.cpp +++ b/src/Entities/ThrownEggEntity.cpp @@ -8,7 +8,8 @@ cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) + super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), + m_DestroyTimer(-1) { SetSpeed(a_Speed); } @@ -21,7 +22,7 @@ void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H { TrySpawnChicken(a_HitPos); - Destroy(); + m_DestroyTimer = 5; } @@ -36,7 +37,7 @@ void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_Hit TrySpawnChicken(a_HitPos); a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); - Destroy(true); + m_DestroyTimer = 5; } diff --git a/src/Entities/ThrownEggEntity.h b/src/Entities/ThrownEggEntity.h index 5ba8f051b..894665428 100644 --- a/src/Entities/ThrownEggEntity.h +++ b/src/Entities/ThrownEggEntity.h @@ -30,8 +30,26 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void Tick (float a_Dt, cChunk & a_Chunk) override + { + if (m_DestroyTimer > 0) + { + m_DestroyTimer--; + if (m_DestroyTimer == 0) + { + Destroy(); + return; + } + } + else { super::Tick(a_Dt, a_Chunk); } + } // Randomly decides whether to spawn a chicken where the egg lands. void TrySpawnChicken(const Vector3d & a_HitPos); + +private: + + /** Time in ticks to wait for the hit animation to begin before destroying */ + int m_DestroyTimer; } ; // tolua_export diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp index c37161145..a3ee23389 100644 --- a/src/Entities/ThrownEnderPearlEntity.cpp +++ b/src/Entities/ThrownEnderPearlEntity.cpp @@ -7,7 +7,8 @@ cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) + super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), + m_DestroyTimer(-1) { SetSpeed(a_Speed); } @@ -21,7 +22,7 @@ void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockF // TODO: Tweak a_HitPos based on block face. TeleportCreator(a_HitPos); - Destroy(); + m_DestroyTimer = 5; } @@ -36,7 +37,7 @@ void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d TeleportCreator(a_HitPos); a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); - Destroy(true); + m_DestroyTimer = 5; } @@ -48,7 +49,7 @@ void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos) // Teleport the creator here, make them take 5 damage: if (m_Creator != NULL) { - m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5); + m_Creator->TeleportToCoords(a_HitPos.x, a_HitPos.y + 0.2, a_HitPos.z); m_Creator->TakeDamage(dtEnderPearl, this, 5, 0); } } diff --git a/src/Entities/ThrownEnderPearlEntity.h b/src/Entities/ThrownEnderPearlEntity.h index ddee5babe..bfd9bd70d 100644 --- a/src/Entities/ThrownEnderPearlEntity.h +++ b/src/Entities/ThrownEnderPearlEntity.h @@ -30,8 +30,26 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - - // Teleports the creator where the ender pearl lands. + virtual void Tick (float a_Dt, cChunk & a_Chunk) override + { + if (m_DestroyTimer > 0) + { + m_DestroyTimer--; + if (m_DestroyTimer == 0) + { + Destroy(); + return; + } + } + else { super::Tick(a_Dt, a_Chunk); } + } + + /** Teleports the creator where the ender pearl lands */ void TeleportCreator(const Vector3d & a_HitPos); + +private: + + /** Time in ticks to wait for the hit animation to begin before destroying */ + int m_DestroyTimer; } ; // tolua_export diff --git a/src/Entities/ThrownSnowballEntity.cpp b/src/Entities/ThrownSnowballEntity.cpp index cefc3433c..b82cd56db 100644 --- a/src/Entities/ThrownSnowballEntity.cpp +++ b/src/Entities/ThrownSnowballEntity.cpp @@ -8,7 +8,8 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) + super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), + m_DestroyTimer(-1) { SetSpeed(a_Speed); } @@ -19,7 +20,7 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, do void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { - Destroy(); + m_DestroyTimer = 5; } @@ -40,5 +41,5 @@ void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & // TODO: If entity is Ender Crystal, destroy it a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); - Destroy(true); + m_DestroyTimer = 5; } diff --git a/src/Entities/ThrownSnowballEntity.h b/src/Entities/ThrownSnowballEntity.h index a09512e37..e30971f0a 100644 --- a/src/Entities/ThrownSnowballEntity.h +++ b/src/Entities/ThrownSnowballEntity.h @@ -30,5 +30,23 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void Tick (float a_Dt, cChunk & a_Chunk) override + { + if (m_DestroyTimer > 0) + { + m_DestroyTimer--; + if (m_DestroyTimer == 0) + { + Destroy(); + return; + } + } + else { super::Tick(a_Dt, a_Chunk); } + } + +private: + + /** Time in ticks to wait for the hit animation to begin before destroying */ + int m_DestroyTimer; } ; // tolua_export -- cgit v1.2.3